diff --git a/typo3/sysext/backend/Classes/Controller/Page/LocalizationController.php b/typo3/sysext/backend/Classes/Controller/Page/LocalizationController.php index 574384b1d4d8487b7395b16a1ae2b34fc8ac0dea..9b91cf1bc0dcbdb7a169e53dfb6618bdfe5a9e6b 100644 --- a/typo3/sysext/backend/Classes/Controller/Page/LocalizationController.php +++ b/typo3/sysext/backend/Classes/Controller/Page/LocalizationController.php @@ -260,15 +260,15 @@ class LocalizationController { $columns = []; $backendLayoutView = GeneralUtility::makeInstance(BackendLayoutView::class); - $backendLayouts = $backendLayoutView->getSelectedBackendLayout($pageId); + $backendLayout = $backendLayoutView->getBackendLayoutForPage($pageId); - foreach ($backendLayouts['__items'] as $backendLayout) { - $columns[(int)$backendLayout[1]] = $backendLayout[0]; + foreach ($backendLayout->getUsedColumns() as $columnPos => $columnLabel) { + $columns[$columnPos] = $GLOBALS['LANG']->sL($columnLabel); } return [ 'columns' => $columns, - 'columnList' => array_values($backendLayouts['__colPosList']), + 'columnList' => array_values($backendLayout->getColumnPositionNumbers()), ]; } } diff --git a/typo3/sysext/backend/Classes/Controller/PageLayoutController.php b/typo3/sysext/backend/Classes/Controller/PageLayoutController.php index 8049f783625b9104c028add460971e334fb1a374..62f1d6ba6bdb0972dec52ba010353af9d390103c 100644 --- a/typo3/sysext/backend/Classes/Controller/PageLayoutController.php +++ b/typo3/sysext/backend/Classes/Controller/PageLayoutController.php @@ -546,9 +546,9 @@ class PageLayoutController '); // Find backend layout / columns - $backendLayout = $this->backendLayouts->getSelectedBackendLayout($this->id); - if (!empty($backendLayout['__colPosList'])) { - $this->colPosList = implode(',', $backendLayout['__colPosList']); + $backendLayout = $this->backendLayouts->getBackendLayoutForPage($this->id); + if (!empty($backendLayout->getColumnPositionNumbers())) { + $this->colPosList = implode(',', $backendLayout->getColumnPositionNumbers()); } // Removing duplicates, if any $this->colPosList = array_unique(GeneralUtility::intExplode(',', $this->colPosList)); @@ -612,24 +612,7 @@ class PageLayoutController $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextMenu'); if (GeneralUtility::makeInstance(Features::class)->isFeatureEnabled('fluidBasedPageModule')) { - $selectedCombinedIdentifier = $this->backendLayouts->getSelectedCombinedIdentifier($this->id); - // If no backend layout is selected, use default - if (empty($selectedCombinedIdentifier)) { - $selectedCombinedIdentifier = 'default'; - } - - $backendLayout = $this->backendLayouts->getDataProviderCollection()->getBackendLayout( - $selectedCombinedIdentifier, - $this->id - ); - - // If backend layout is not found available anymore, use default - if ($backendLayout === null) { - $backendLayout = $this->backendLayouts->getDataProviderCollection()->getBackendLayout( - 'default', - $this->id - ); - } + $backendLayout = $this->backendLayouts->getBackendLayoutForPage((int)$this->id); $configuration = $backendLayout->getDrawingConfiguration(); $configuration->setPageId($this->id); diff --git a/typo3/sysext/backend/Classes/View/BackendLayout/BackendLayout.php b/typo3/sysext/backend/Classes/View/BackendLayout/BackendLayout.php index e0c4671496856083c509f91afc221035ed56643c..383264246c236d5767b464c050ec70fa422bbfc0 100644 --- a/typo3/sysext/backend/Classes/View/BackendLayout/BackendLayout.php +++ b/typo3/sysext/backend/Classes/View/BackendLayout/BackendLayout.php @@ -19,10 +19,9 @@ use TYPO3\CMS\Backend\View\BackendLayout\Grid\Grid; use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumn; use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridRow; use TYPO3\CMS\Backend\View\BackendLayout\Grid\LanguageColumn; +use TYPO3\CMS\Backend\View\BackendLayoutView; use TYPO3\CMS\Backend\View\Drawing\BackendLayoutRenderer; use TYPO3\CMS\Backend\View\Drawing\DrawingConfiguration; -use TYPO3\CMS\Core\Localization\LanguageService; -use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser; use TYPO3\CMS\Core\Utility\GeneralUtility; /** @@ -56,9 +55,11 @@ class BackendLayout protected $configuration; /** + * The structured data of the configuration represented as array. + * * @var array */ - protected $configurationArray; + protected $structure = []; /** * @var array @@ -114,7 +115,8 @@ class BackendLayout $this->setIdentifier($identifier); $this->setTitle($title); if (is_array($configuration)) { - $this->setConfigurationArray($configuration); + $this->structure = $configuration; + $this->configuration = $configuration['config'] ?? ''; } else { $this->setConfiguration($configuration); } @@ -201,61 +203,24 @@ class BackendLayout } /** - * @param array $configurationArray + * @param string $configuration */ - public function setConfigurationArray(array $configurationArray): void + public function setConfiguration($configuration) { - if (!isset($configurationArray['__colPosList'], $configurationArray['__items'])) { - // Backend layout configuration is unprocessed, process it now to extract counts and column item lists - $colPosList = []; - $items = []; - $rowIndex = 0; - foreach ($configurationArray['backend_layout.']['rows.'] as $row) { - $index = 0; - $colCount = 0; - $columns = []; - foreach ($row['columns.'] as $column) { - if (!isset($column['colPos'])) { - continue; - } - $colPos = $column['colPos']; - $colPos = (int)$colPos; - $colPosList[$colPos] = $colPos; - $key = ($index + 1) . '.'; - $columns[$key] = $column; - $items[$colPos] = [ - (string)$this->getLanguageService()->sL($column['name']), - $colPos, - $column['icon'] - ]; - $colCount += $column['colspan'] ? $column['colspan'] : 1; - ++ $index; - } - ++ $rowIndex; - } - - $configurationArray['__config'] = $configurationArray; - $configurationArray['__colPosList'] = $colPosList; - $configurationArray['__items'] = $items; - } - $this->configurationArray = $configurationArray; + $this->configuration = $configuration; + GeneralUtility::makeInstance(BackendLayoutView::class)->parseStructure($this); } /** + * Returns the columns registered for this layout as $key => $value pair where the key is the colPos + * and the value is the title. + * "1" => "Left" etc. + * Please note that the title can contain LLL references ready for translation. * @return array */ - public function getConfigurationArray(): array + public function getUsedColumns(): array { - return $this->configurationArray; - } - - /** - * @param string $configuration - */ - public function setConfiguration($configuration) - { - $this->configuration = $configuration; - $this->parseConfigurationStringAndSetConfigurationArray($configuration); + return $this->structure['usedColumns'] ?? []; } /** @@ -274,6 +239,16 @@ class BackendLayout $this->data = $data; } + public function setStructure(array $structure) + { + $this->structure = $structure; + } + + public function getStructure(): array + { + return $this->structure; + } + /** * @return LanguageColumn[] */ @@ -295,7 +270,7 @@ class BackendLayout public function getGrid(): Grid { $grid = GeneralUtility::makeInstance(Grid::class, $this); - foreach ($this->getConfigurationArray()['__config']['backend_layout.']['rows.'] as $row) { + foreach ($this->structure['__config']['backend_layout.']['rows.'] ?? [] as $row) { $rowObject = GeneralUtility::makeInstance(GridRow::class, $this); foreach ($row['columns.'] as $column) { $columnObject = GeneralUtility::makeInstance(GridColumn::class, $this, $column); @@ -313,7 +288,7 @@ class BackendLayout public function getColumnPositionNumbers(): array { - return $this->getConfigurationArray()['__colPosList']; + return $this->structure['__colPosList']; } public function getContentFetcher(): ContentFetcher @@ -349,22 +324,9 @@ class BackendLayout return $translationData['mode'] ?? ''; } - protected function parseConfigurationStringAndSetConfigurationArray(string $configuration): void - { - $parser = GeneralUtility::makeInstance(TypoScriptParser::class); - $conditionMatcher = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher::class); - $parser->parse(TypoScriptParser::checkIncludeLines($configuration), $conditionMatcher); - $this->setConfigurationArray($parser->setup); - } - public function __clone() { $this->drawingConfiguration = clone $this->drawingConfiguration; $this->contentFetcher->setBackendLayout($this); } - - protected function getLanguageService(): LanguageService - { - return $GLOBALS['LANG']; - } } diff --git a/typo3/sysext/backend/Classes/View/BackendLayout/Grid/GridColumn.php b/typo3/sysext/backend/Classes/View/BackendLayout/Grid/GridColumn.php index f9f6687df91421edccb825dc9f16924061029481..374627c085c1ae8465ad0deb6bcb19346b7a9ce3 100644 --- a/typo3/sysext/backend/Classes/View/BackendLayout/Grid/GridColumn.php +++ b/typo3/sysext/backend/Classes/View/BackendLayout/Grid/GridColumn.php @@ -188,10 +188,9 @@ class GridColumn extends AbstractGridObject { $columnNumber = $this->getColumnNumber(); $colTitle = (string)BackendUtility::getProcessedValue('tt_content', 'colPos', $columnNumber); - $tcaItems = $this->backendLayout->getConfigurationArray()['__items']; - foreach ($tcaItems as $item) { - if ($item[1] === $columnNumber) { - $colTitle = (string)$this->getLanguageService()->sL($item[0]); + foreach ($this->backendLayout->getUsedColumns() as $colPos => $title) { + if ($colPos === $columnNumber) { + $colTitle = (string)$this->getLanguageService()->sL($title); } } return $colTitle; diff --git a/typo3/sysext/backend/Classes/View/BackendLayoutView.php b/typo3/sysext/backend/Classes/View/BackendLayoutView.php index b238d77725b082c6fcf829465b41cd0c51b65329..3895d9457ab7c11b027bcd238010c934018ee190 100644 --- a/typo3/sysext/backend/Classes/View/BackendLayoutView.php +++ b/typo3/sysext/backend/Classes/View/BackendLayoutView.php @@ -14,8 +14,15 @@ namespace TYPO3\CMS\Backend\View; * The TYPO3 project - inspiring people to share! */ +use TYPO3\CMS\Backend\Configuration\TypoScript\ConditionMatching\ConditionMatcher; use TYPO3\CMS\Backend\Utility\BackendUtility; +use TYPO3\CMS\Backend\View\BackendLayout\BackendLayout; +use TYPO3\CMS\Backend\View\BackendLayout\DataProviderCollection; +use TYPO3\CMS\Backend\View\BackendLayout\DataProviderContext; +use TYPO3\CMS\Backend\View\BackendLayout\DefaultDataProvider; use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Localization\LanguageService; +use TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser; use TYPO3\CMS\Core\Utility\ArrayUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -26,7 +33,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; class BackendLayoutView implements \TYPO3\CMS\Core\SingletonInterface { /** - * @var BackendLayout\DataProviderCollection + * @var DataProviderCollection */ protected $dataProviderCollection; @@ -53,15 +60,8 @@ class BackendLayoutView implements \TYPO3\CMS\Core\SingletonInterface */ protected function initializeDataProviderCollection() { - /** @var BackendLayout\DataProviderCollection $dataProviderCollection */ - $dataProviderCollection = GeneralUtility::makeInstance( - BackendLayout\DataProviderCollection::class - ); - - $dataProviderCollection->add( - 'default', - \TYPO3\CMS\Backend\View\BackendLayout\DefaultDataProvider::class - ); + $dataProviderCollection = GeneralUtility::makeInstance(DataProviderCollection::class); + $dataProviderCollection->add('default', DefaultDataProvider::class); if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['BackendLayoutDataProvider'])) { $dataProviders = (array)$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['BackendLayoutDataProvider']; @@ -74,15 +74,15 @@ class BackendLayoutView implements \TYPO3\CMS\Core\SingletonInterface } /** - * @param BackendLayout\DataProviderCollection $dataProviderCollection + * @param DataProviderCollection $dataProviderCollection */ - public function setDataProviderCollection(BackendLayout\DataProviderCollection $dataProviderCollection) + public function setDataProviderCollection(DataProviderCollection $dataProviderCollection) { $this->dataProviderCollection = $dataProviderCollection; } /** - * @return BackendLayout\DataProviderCollection + * @return DataProviderCollection */ public function getDataProviderCollection() { @@ -327,32 +327,89 @@ class BackendLayoutView implements \TYPO3\CMS\Core\SingletonInterface } /** - * Gets the selected backend layout + * Gets the selected backend layout structure as an array * * @param int $pageId * @return array|null $backendLayout */ - public function getSelectedBackendLayout($pageId) + public function getSelectedBackendLayout($pageId): ?array + { + $layout = $this->getBackendLayoutForPage((int)$pageId); + if ($layout instanceof BackendLayout) { + return $layout->getStructure(); + } + return null; + } + + /** + * Get the BackendLayout object and parse the structure based on the UserTSconfig + * @param int $pageId + * @return BackendLayout + */ + public function getBackendLayoutForPage(int $pageId): ?BackendLayout { if (isset($this->selectedBackendLayout[$pageId])) { return $this->selectedBackendLayout[$pageId]; } - $backendLayoutData = null; - $selectedCombinedIdentifier = $this->getSelectedCombinedIdentifier($pageId); // If no backend layout is selected, use default if (empty($selectedCombinedIdentifier)) { $selectedCombinedIdentifier = 'default'; } - $backendLayout = $this->getDataProviderCollection()->getBackendLayout($selectedCombinedIdentifier, $pageId); // If backend layout is not found available anymore, use default if ($backendLayout === null) { - $selectedCombinedIdentifier = 'default'; - $backendLayout = $this->getDataProviderCollection()->getBackendLayout($selectedCombinedIdentifier, $pageId); + $backendLayout = $this->getDataProviderCollection()->getBackendLayout('default', $pageId); + } + + $structure = null; + if ($backendLayout instanceof BackendLayout) { + $structure = $this->parseStructure($backendLayout); + // Parse the configuration and inject it back in the backend layout object + $backendLayout->setStructure($structure); + $this->selectedBackendLayout[$pageId] = $backendLayout; } + return $backendLayout; + } - return $backendLayout->getConfigurationArray(); + /** + * @param BackendLayout $backendLayout + * @return array + * @internal + */ + public function parseStructure(BackendLayout $backendLayout): array + { + $parser = GeneralUtility::makeInstance(TypoScriptParser::class); + $conditionMatcher = GeneralUtility::makeInstance(ConditionMatcher::class); + $parser->parse(TypoScriptParser::checkIncludeLines($backendLayout->getConfiguration()), $conditionMatcher); + + $backendLayoutData = []; + $backendLayoutData['config'] = $backendLayout->getConfiguration(); + $backendLayoutData['__config'] = $parser->setup; + $backendLayoutData['__items'] = []; + $backendLayoutData['__colPosList'] = []; + $backendLayoutData['usedColumns'] = []; + + // create items and colPosList + if (!empty($backendLayoutData['__config']['backend_layout.']['rows.'])) { + foreach ($backendLayoutData['__config']['backend_layout.']['rows.'] as $row) { + if (!empty($row['columns.'])) { + foreach ($row['columns.'] as $column) { + if (!isset($column['colPos'])) { + continue; + } + $backendLayoutData['__items'][] = [ + $this->getColumnName($column), + $column['colPos'], + null + ]; + $backendLayoutData['__colPosList'][] = $column['colPos']; + $backendLayoutData['usedColumns'][(int)$column['colPos']] = $column['name']; + } + } + } + } + return $backendLayoutData; } /** @@ -421,18 +478,35 @@ class BackendLayoutView implements \TYPO3\CMS\Core\SingletonInterface } /** - * @return BackendLayout\DataProviderContext + * @return DataProviderContext */ protected function createDataProviderContext() { - return GeneralUtility::makeInstance(BackendLayout\DataProviderContext::class); + return GeneralUtility::makeInstance(DataProviderContext::class); } /** - * @return \TYPO3\CMS\Core\Localization\LanguageService + * @return LanguageService */ protected function getLanguageService() { return $GLOBALS['LANG']; } + + /** + * Get column name from colPos item structure + * + * @param array $column + * @return string + */ + protected function getColumnName($column) + { + $columnName = $column['name']; + + if (GeneralUtility::isFirstPartOfStr($columnName, 'LLL:')) { + $columnName = $this->getLanguageService()->sL($columnName); + } + + return $columnName; + } }