/** * Creates the listing of records from a single table * * @param string $table Table name * @param integer $id Page id * @param string $rowlist List of fields to show in the listing. Pseudo fields will be added including the record header. * @return string HTML table with the listing for the record. * @todo Define visibility */ public function getTable($table, $id, $rowlist) { // Loading all TCA details for this table: \TYPO3\CMS\Core\Utility\GeneralUtility::loadTCA($table); // Init $addWhere = ''; $titleCol = $GLOBALS['TCA'][$table]['ctrl']['label']; $thumbsCol = $GLOBALS['TCA'][$table]['ctrl']['thumbnail']; $l10nEnabled = $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] && !$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable']; $tableCollapsed = !$this->tablesCollapsed[$table] ? FALSE : TRUE; // prepare space icon $this->spaceIcon = \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('empty-empty', array('style' => 'background-position: 0 10px;')); // Cleaning rowlist for duplicates and place the $titleCol as the first column always! $this->fieldArray = array(); // title Column // Add title column $this->fieldArray[] = $titleCol; // Control-Panel if (!\TYPO3\CMS\Core\Utility\GeneralUtility::inList($rowlist, '_CONTROL_')) { $this->fieldArray[] = '_CONTROL_'; $this->fieldArray[] = '_AFTERCONTROL_'; } // Clipboard if ($this->showClipboard) { $this->fieldArray[] = '_CLIPBOARD_'; } // Ref if (!$this->dontShowClipControlPanels) { $this->fieldArray[] = '_REF_'; $this->fieldArray[] = '_AFTERREF_'; } // Path if ($this->searchLevels) { $this->fieldArray[] = '_PATH_'; } // Localization if ($this->localizationView && $l10nEnabled) { $this->fieldArray[] = '_LOCALIZATION_'; $this->fieldArray[] = '_LOCALIZATION_b'; $addWhere .= ' AND ( ' . $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '<=0 OR ' . $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . ' = 0 )'; } // Cleaning up: $this->fieldArray = array_unique(array_merge($this->fieldArray, \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $rowlist, 1))); if ($this->noControlPanels) { $tempArray = array_flip($this->fieldArray); unset($tempArray['_CONTROL_']); unset($tempArray['_CLIPBOARD_']); $this->fieldArray = array_keys($tempArray); } // Creating the list of fields to include in the SQL query: $selectFields = $this->fieldArray; $selectFields[] = 'uid'; $selectFields[] = 'pid'; // adding column for thumbnails if ($thumbsCol) { $selectFields[] = $thumbsCol; } if ($table == 'pages') { if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('cms')) { $selectFields[] = 'module'; $selectFields[] = 'extendToSubpages'; $selectFields[] = 'nav_hide'; } $selectFields[] = 'doktype'; } if (is_array($GLOBALS['TCA'][$table]['ctrl']['enablecolumns'])) { $selectFields = array_merge($selectFields, $GLOBALS['TCA'][$table]['ctrl']['enablecolumns']); } if ($GLOBALS['TCA'][$table]['ctrl']['type']) { $selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['type']; } if ($GLOBALS['TCA'][$table]['ctrl']['typeicon_column']) { $selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['typeicon_column']; } if ($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) { $selectFields[] = 't3ver_id'; $selectFields[] = 't3ver_state'; $selectFields[] = 't3ver_wsid'; } if ($l10nEnabled) { $selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['languageField']; $selectFields[] = $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']; } if ($GLOBALS['TCA'][$table]['ctrl']['label_alt']) { $selectFields = array_merge($selectFields, \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $GLOBALS['TCA'][$table]['ctrl']['label_alt'], 1)); } // Unique list! $selectFields = array_unique($selectFields); $fieldListFields = $this->makeFieldList($table, 1); if (empty($fieldListFields) && $GLOBALS['TYPO3_CONF_VARS']['BE']['debug']) { $message = sprintf($GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_web_list.php:missingTcaColumnsMessage', TRUE), $table, $table); $messageTitle = $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_mod_web_list.php:missingTcaColumnsMessageTitle', TRUE); $flashMessage = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\FlashMessage', $message, $messageTitle, \TYPO3\CMS\Core\Messaging\FlashMessage::WARNING, TRUE); /** @var \TYPO3\CMS\Core\Messaging\FlashMessage $flashMessage */ \TYPO3\CMS\Core\Messaging\FlashMessageQueue::addMessage($flashMessage); } // Making sure that the fields in the field-list ARE in the field-list from TCA! $selectFields = array_intersect($selectFields, $fieldListFields); // Implode it into a list of fields for the SQL-statement. $selFieldList = implode(',', $selectFields); $this->selFieldList = $selFieldList; /** * @hook DB-List getTable * @date 2007-11-16 * @request Malte Jansen <*****@*****.**> */ if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['getTable'])) { foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['typo3/class.db_list_extra.inc']['getTable'] as $classData) { $hookObject = \TYPO3\CMS\Core\Utility\GeneralUtility::getUserObj($classData); if (!$hookObject instanceof \TYPO3\CMS\Backend\RecordList\RecordListGetTableHookInterface) { throw new \UnexpectedValueException('$hookObject must implement interface TYPO3\\CMS\\Backend\\RecordList\\RecordListGetTableHookInterface', 1195114460); } $hookObject->getDBlistQuery($table, $id, $addWhere, $selFieldList, $this); } } // Create the SQL query for selecting the elements in the listing: // do not do paging when outputting as CSV if ($this->csvOutput) { $this->iLimit = 0; } if ($this->firstElementNumber > 2 && $this->iLimit > 0) { // Get the two previous rows for sorting if displaying page > 1 $this->firstElementNumber = $this->firstElementNumber - 2; $this->iLimit = $this->iLimit + 2; // (API function from class.db_list.inc) $queryParts = $this->makeQueryArray($table, $id, $addWhere, $selFieldList); $this->firstElementNumber = $this->firstElementNumber + 2; $this->iLimit = $this->iLimit - 2; } else { // (API function from class.db_list.inc) $queryParts = $this->makeQueryArray($table, $id, $addWhere, $selFieldList); } // Finding the total amount of records on the page (API function from class.db_list.inc) $this->setTotalItems($queryParts); // Init: $dbCount = 0; $out = ''; $listOnlyInSingleTableMode = $this->listOnlyInSingleTableMode && !$this->table; // If the count query returned any number of records, we perform the real query, selecting records. if ($this->totalItems) { // Fetch records only if not in single table mode or if in multi table mode and not collapsed if ($listOnlyInSingleTableMode || !$this->table && $tableCollapsed) { $dbCount = $this->totalItems; } else { // Set the showLimit to the number of records when outputting as CSV if ($this->csvOutput) { $this->showLimit = $this->totalItems; $this->iLimit = $this->totalItems; } $result = $GLOBALS['TYPO3_DB']->exec_SELECT_queryArray($queryParts); $dbCount = $GLOBALS['TYPO3_DB']->sql_num_rows($result); } } // If any records was selected, render the list: if ($dbCount) { // Half line is drawn between tables: if (!$listOnlyInSingleTableMode) { $theData = array(); if (!$this->table && !$rowlist) { $theData[$titleCol] = '<img src="clear.gif" width="' . ($GLOBALS['SOBE']->MOD_SETTINGS['bigControlPanel'] ? '230' : '350') . '" height="1" alt="" />'; if (in_array('_CONTROL_', $this->fieldArray)) { $theData['_CONTROL_'] = ''; } if (in_array('_CLIPBOARD_', $this->fieldArray)) { $theData['_CLIPBOARD_'] = ''; } } $out .= $this->addelement(0, '', $theData, 'class="c-table-row-spacer"', $this->leftMargin); } $tableTitle = $GLOBALS['LANG']->sL($GLOBALS['TCA'][$table]['ctrl']['title'], TRUE); if ($tableTitle === '') { $tableTitle = $table; } // Header line is drawn $theData = array(); if ($this->disableSingleTableView) { $theData[$titleCol] = '<span class="c-table">' . \TYPO3\CMS\Backend\Utility\BackendUtility::wrapInHelp($table, '', $tableTitle) . '</span> (' . $this->totalItems . ')'; } else { $theData[$titleCol] = $this->linkWrapTable($table, '<span class="c-table">' . $tableTitle . '</span> (' . $this->totalItems . ') ' . ($this->table ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-table-collapse', array('title' => $GLOBALS['LANG']->getLL('contractView', TRUE))) : \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-table-expand', array('title' => $GLOBALS['LANG']->getLL('expandView', TRUE))))); } if ($listOnlyInSingleTableMode) { $out .= ' <tr> <td class="t3-row-header" style="width:95%;">' . \TYPO3\CMS\Backend\Utility\BackendUtility::wrapInHelp($table, '', $theData[$titleCol]) . '</td> </tr>'; } else { // Render collapse button if in multi table mode $collapseIcon = ''; if (!$this->table) { $collapseIcon = '<a href="' . htmlspecialchars($this->listURL() . '&collapse[' . $table . ']=' . ($tableCollapsed ? '0' : '1')) . '" title="' . ($tableCollapsed ? $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.expandTable', TRUE) : $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.php:labels.collapseTable', TRUE)) . '">' . ($tableCollapsed ? \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-list-expand', array('class' => 'collapseIcon')) : \TYPO3\CMS\Backend\Utility\IconUtility::getSpriteIcon('actions-view-list-collapse', array('class' => 'collapseIcon'))) . '</a>'; } $out .= $this->addElement(1, $collapseIcon, $theData, ' class="t3-row-header"', ''); } // Render table rows only if in multi table view and not collapsed or if in single table view if (!$listOnlyInSingleTableMode && (!$tableCollapsed || $this->table)) { // Fixing a order table for sortby tables $this->currentTable = array(); $currentIdList = array(); $doSort = $GLOBALS['TCA'][$table]['ctrl']['sortby'] && !$this->sortField; $prevUid = 0; $prevPrevUid = 0; // Get first two rows and initialize prevPrevUid and prevUid if on page > 1 if ($this->firstElementNumber > 2 && $this->iLimit > 0) { $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result); $prevPrevUid = -(int) $row['uid']; $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result); $prevUid = $row['uid']; } $accRows = array(); // Accumulate rows here while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($result)) { if (!$this->isRowListingConditionFulfilled($table, $row)) { continue; } // In offline workspace, look for alternative record: \TYPO3\CMS\Backend\Utility\BackendUtility::workspaceOL($table, $row, $GLOBALS['BE_USER']->workspace, TRUE); if (is_array($row)) { $accRows[] = $row; $currentIdList[] = $row['uid']; if ($doSort) { if ($prevUid) { $this->currentTable['prev'][$row['uid']] = $prevPrevUid; $this->currentTable['next'][$prevUid] = '-' . $row['uid']; $this->currentTable['prevUid'][$row['uid']] = $prevUid; } $prevPrevUid = isset($this->currentTable['prev'][$row['uid']]) ? -$prevUid : $row['pid']; $prevUid = $row['uid']; } } } $GLOBALS['TYPO3_DB']->sql_free_result($result); $this->totalRowCount = count($accRows); // CSV initiated if ($this->csvOutput) { $this->initCSV(); } // Render items: $this->CBnames = array(); $this->duplicateStack = array(); $this->eCounter = $this->firstElementNumber; $iOut = ''; $cc = 0; foreach ($accRows as $row) { // Render item row if counter < limit if ($cc < $this->iLimit) { $cc++; $this->translations = FALSE; $iOut .= $this->renderListRow($table, $row, $cc, $titleCol, $thumbsCol); // If localization view is enabled it means that the selected records are // either default or All language and here we will not select translations // which point to the main record: if ($this->localizationView && $l10nEnabled) { // For each available translation, render the record: if (is_array($this->translations)) { foreach ($this->translations as $lRow) { // $lRow isn't always what we want - if record was moved we've to work with the // placeholder records otherwise the list is messed up a bit if ($row['_MOVE_PLH_uid'] && $row['_MOVE_PLH_pid']) { $tmpRow = \TYPO3\CMS\Backend\Utility\BackendUtility::getRecordRaw($table, 't3ver_move_id="' . intval($lRow['uid']) . '" AND pid="' . $row['_MOVE_PLH_pid'] . '" AND t3ver_wsid=' . $row['t3ver_wsid'] . \t3lib_beFunc::deleteClause($table), $selFieldList); $lRow = is_array($tmpRow) ? $tmpRow : $lRow; } // In offline workspace, look for alternative record: \TYPO3\CMS\Backend\Utility\BackendUtility::workspaceOL($table, $lRow, $GLOBALS['BE_USER']->workspace, TRUE); if (is_array($lRow) && $GLOBALS['BE_USER']->checkLanguageAccess($lRow[$GLOBALS['TCA'][$table]['ctrl']['languageField']])) { $currentIdList[] = $lRow['uid']; $iOut .= $this->renderListRow($table, $lRow, $cc, $titleCol, $thumbsCol, 18); } } } } } // Counter of total rows incremented: $this->eCounter++; } // Record navigation is added to the beginning and end of the table if in single table mode if ($this->table) { $iOut = $this->renderListNavigation('top') . $iOut . $this->renderListNavigation('bottom'); } else { // Show that there are more records than shown if ($this->totalItems > $this->itemsLimitPerTable) { $countOnFirstPage = $this->totalItems > $this->itemsLimitSingleTable ? $this->itemsLimitSingleTable : $this->totalItems; $hasMore = $this->totalItems > $this->itemsLimitSingleTable; $iOut .= '<tr><td colspan="' . count($this->fieldArray) . '" style="padding:5px;"> <a href="' . htmlspecialchars($this->listURL() . '&table=' . rawurlencode($table)) . '">' . '<img' . \TYPO3\CMS\Backend\Utility\IconUtility::skinImg($this->backPath, 'gfx/pildown.gif', 'width="14" height="14"') . ' alt="" />' . ' <i>[1 - ' . $countOnFirstPage . ($hasMore ? '+' : '') . ']</i></a> </td></tr>'; } } // The header row for the table is now created: $out .= $this->renderListHeader($table, $currentIdList); } // The list of records is added after the header: $out .= $iOut; unset($iOut); // ... and it is all wrapped in a table: $out = ' <!-- DB listing of elements: "' . htmlspecialchars($table) . '" --> <table border="0" cellpadding="0" cellspacing="0" class="typo3-dblist' . ($listOnlyInSingleTableMode ? ' typo3-dblist-overview' : '') . '"> ' . $out . ' </table>'; // Output csv if... // This ends the page with exit. if ($this->csvOutput) { $this->outputCSV($table); } } // Return content: return $out; }