backendLayoutView = $backendLayoutView; } /** * Creates a linked position icon * * @param array|null $row The record row. If this is an array the link will cause an insert after this * content element, otherwise the link will insert at the first position in the column. * @param int $colPos Column position value. * @param int $pid PID value. * @return string HTML */ abstract protected function insertPositionIcon(?array $row, int $colPos, int $pid): string; /** * Create content element header (includes record type (CType) icon, content element title, etc.) * * @param array $row The element row * @return string HTML */ abstract protected function getRecordHeader(array $row): string; /** * Creates HTML for inserting/moving content elements. * * @param int $pid page id onto which to insert content element. * @return string HTML */ public function printContentElementColumns(int $pid, array $pageInfo, ServerRequestInterface $request): string { $lines = []; $columnsConfiguration = $this->getColumnsConfiguration($pid); foreach ($columnsConfiguration as $columnConfiguration) { if ($columnConfiguration['isRestricted']) { // Do not fetch records of restricted columns continue; } $colPos = $columnConfiguration['colPos']; $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tt_content'); $queryBuilder ->getRestrictions() ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, $this->getBackendUser()->workspace)) ->removeByType(HiddenRestriction::class) ->removeByType(StartTimeRestriction::class) ->removeByType(EndTimeRestriction::class); $queryBuilder ->select('*') ->from('tt_content') ->where( $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($pid, Connection::PARAM_INT)), $queryBuilder->expr()->eq('colPos', $queryBuilder->createNamedParameter($colPos, Connection::PARAM_INT)) ) ->orderBy('sorting'); $queryBuilder->andWhere( $queryBuilder->expr()->eq( 'sys_language_uid', $queryBuilder->createNamedParameter($this->cur_sys_language, Connection::PARAM_INT) ) ); $res = $queryBuilder->executeQuery(); $lines[$colPos] = [ $this->insertPositionIcon(null, $colPos, $pid), ]; while ($row = $res->fetchAssociative()) { BackendUtility::workspaceOL('tt_content', $row); if (is_array($row)) { $lines[$colPos][] = $this->getRecordHeader($row); $lines[$colPos][] = $this->insertPositionIcon($row, $colPos, $pid); } } } return $this->printRecordMap($lines, $columnsConfiguration, $pid); } /** * Creates the table with the content columns * * @param array $lines Array with arrays of lines for each column * @param array $tcaColumnsConfiguration Column configuration array * @param int $pid The id of the page * @return string HTML */ protected function printRecordMap(array $lines, array $tcaColumnsConfiguration, int $pid): string { $lang = $this->getLanguageService(); $hideRestrictedColumns = (bool)(BackendUtility::getPagesTSconfig($pid)['mod.']['web_layout.']['hideRestrictedCols'] ?? false); $backendLayout = $this->backendLayoutView->getSelectedBackendLayout($pid); if (isset($backendLayout['__config']['backend_layout.'])) { // Build position map based on the fetched backend layout $colCount = (int)($backendLayout['__config']['backend_layout.']['colCount'] ?? 0); $rowCount = (int)($backendLayout['__config']['backend_layout.']['rowCount'] ?? 0); // Cycle through rows $tableRows = []; for ($row = 1; $row <= $rowCount; $row++) { $rowConfig = $backendLayout['__config']['backend_layout.']['rows.'][$row . '.'] ?? null; if (!$rowConfig) { // Skip empty rows continue; } // Cycle through cells $tableCells = []; for ($col = 1; $col <= $colCount; $col++) { $columnConfig = $rowConfig['columns.'][$col . '.'] ?? null; if (!$columnConfig) { // Skip empty columns continue; } // Set table cell attributes $tableCellAttributes = [ 'class' => 'col-nowrap col-min', ]; if (isset($columnConfig['colspan'])) { $tableCellAttributes['colspan'] = $columnConfig['colspan']; } if (isset($columnConfig['rowspan'])) { $tableCellAttributes['rowspan'] = $columnConfig['rowspan']; } $columnKey = null; $columnTitle = ''; $isRestricted = false; $isUnassigned = true; if (isset($columnConfig['colPos'])) { // If colPos is defined, initialize column information (e.g. title and restricted state) $columnKey = (int)$columnConfig['colPos']; foreach ($tcaColumnsConfiguration as $tcaColumnConfiguration) { if ($tcaColumnConfiguration['colPos'] === $columnKey) { $columnTitle = '' . htmlspecialchars($lang->sL($tcaColumnConfiguration['title'])) . ''; $isRestricted = $tcaColumnConfiguration['isRestricted']; $isUnassigned = false; } } } // Generate the cell content, based on the columns' state (e.g. restricted or unassigned) $cellContent = ''; if ($isRestricted) { if ($hideRestrictedColumns) { // Hide in case this column is not accessible and hideRestrictedColumns is set $tableCellAttributes['class'] = 'hidden'; } else { $cellContent = '

' . $columnTitle . ' (' . htmlspecialchars($lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:noAccess')) . ')

'; $tableCellAttributes['class'] .= ' danger'; } } elseif ($isUnassigned) { if ($hideRestrictedColumns) { // Hide in case this column is not assigned and hideRestrictedColumns is set $tableCellAttributes['class'] = 'hidden'; } else { $cellContent = ' ' . htmlspecialchars($lang->sL($columnConfig['name']) ?: '') . ' ' . ' (' . htmlspecialchars($lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:notAssigned')) . ')' . ' '; $tableCellAttributes['class'] .= ' warning'; } } else { // If not restricted and not unassigned, wrap column title and render list (if available) $cellContent = '

' . $columnTitle . '

'; if (!empty($lines[$columnKey])) { $cellContent .= ' '; } } // Add the table cell $tableCells[] = '' . $cellContent . ''; } // Add the table row $tableRows[] = '' . implode(LF, $tableCells) . ''; } // Create the table content $tableContent = '' . str_repeat('', $colCount) . '' . '' . implode(LF, $tableRows) . ''; } else { // Build position map based on TCA colPos configuration $tableCells = []; foreach ($tcaColumnsConfiguration as $tcaColumnConfiguration) { if ($hideRestrictedColumns && $tcaColumnConfiguration['isRestricted']) { // Skip in case this column is not accessible and restricted columns should be hidden continue; } // Generate the cell content, based on the columns' state (e.g. restricted or unassigned) $tableCellClasses = 'col-nowrap col-min'; $columnTitle = '' . htmlspecialchars($tcaColumnConfiguration['title']) . ''; if ($tcaColumnConfiguration['isRestricted']) { // If this colPos is restricted, add an information to the column title and color the cell $tableCellClasses .= ' danger'; $cellContent = '

' . $columnTitle . ' (' . htmlspecialchars($lang->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:noAccess')) . ')

'; } else { // If not restricted, wrap column title and render list (if available) $cellContent = '

' . $columnTitle . '

'; if (!empty($lines[$tcaColumnConfiguration['colPos']])) { $cellContent .= ' '; } } // Add the table cell $tableCells[] = '' . $cellContent . ''; } // Create the table content $tableContent = '' . implode(LF, $tableCells) . ''; } // Return the record map (table) return ' ' . $tableContent . '
'; } /** * Fetch TCA colPos list from BackendLayoutView and prepare for map generation. * This also takes the "colPos_list" TSconfig into account. */ protected function getColumnsConfiguration(int $pageId): array { $backendLayout = $this->backendLayoutView->getBackendLayoutForPage($pageId); $items = []; // Prepare the columns configuration (using named keys, etc.) foreach ($backendLayout->getUsedColumns() as $colPos => $label) { $items[] = [ 'title' => $label, 'colPos' => (int)$colPos, 'isRestricted' => false, ]; } $sharedColPosList = trim(BackendUtility::getPagesTSconfig($pageId)['mod.']['SHARED.']['colPos_list'] ?? ''); if ($sharedColPosList !== '') { $activeColPosArray = array_unique(GeneralUtility::intExplode(',', $sharedColPosList)); if (!empty($items) && !empty($activeColPosArray)) { foreach ($items as &$item) { if (!in_array((int)$item['colPos'], $activeColPosArray, true)) { $item['isRestricted'] = true; } } unset($item); } } return $items; } protected function getBackendUser(): BackendUserAuthentication { return $GLOBALS['BE_USER']; } protected function getLanguageService(): LanguageService { return $GLOBALS['LANG']; } }