Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[TASK] Centralize Page Layout resolving
This change centralizes Frontend's "PageLayoutResolver", used in TypoScript, and BackendLayoutView logic to find the used page layout, while also modelling more towards an object within PageLayout which can be used at a later stage in FE to retrieve more information. At the same time, some BackendLayoutView code is reduced now. Resolves: #103466 Releases: main Change-Id: I716fe7313894aac92e5519a6b725feefff908270 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/83567 Tested-by: Stefan Bürk <stefan@buerk.tech> Reviewed-by: Nikita Hovratov <nikita.h@live.de> Reviewed-by: Benni Mack <benni@typo3.org> Tested-by: Nikita Hovratov <nikita.h@live.de> Tested-by: Benni Mack <benni@typo3.org> Tested-by: core-ci <typo3@b13.com> Reviewed-by: Stefan Bürk <stefan@buerk.tech>
- Loading branch information
Showing
11 changed files
with
299 additions
and
233 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
/* | ||
* This file is part of the TYPO3 CMS project. | ||
* | ||
* It is free software; you can redistribute it and/or modify it under | ||
* the terms of the GNU General Public License, either version 2 | ||
* of the License, or any later version. | ||
* | ||
* For the full copyright and license information, please read the | ||
* LICENSE.txt file that was distributed with this source code. | ||
* | ||
* The TYPO3 project - inspiring people to share! | ||
*/ | ||
|
||
namespace TYPO3\CMS\Core\Page; | ||
|
||
/** | ||
* Contains information about the layout of a page, | ||
* mainly which content areas (colPos=0, colPos=1, ...) are used and filled. | ||
* | ||
* @internal This is not part of TYPO3 Core API. | ||
*/ | ||
class PageLayout | ||
{ | ||
public function __construct( | ||
protected string $identifier, | ||
protected string $title, | ||
protected array $contentAreas, | ||
protected array $fullConfiguration | ||
) {} | ||
|
||
public function getIdentifier(): string | ||
{ | ||
return $this->identifier; | ||
} | ||
|
||
public function getTitle(): string | ||
{ | ||
return $this->title; | ||
} | ||
|
||
public function getContentAreas(): array | ||
{ | ||
return $this->contentAreas; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
/* | ||
* This file is part of the TYPO3 CMS project. | ||
* | ||
* It is free software; you can redistribute it and/or modify it under | ||
* the terms of the GNU General Public License, either version 2 | ||
* of the License, or any later version. | ||
* | ||
* For the full copyright and license information, please read the | ||
* LICENSE.txt file that was distributed with this source code. | ||
* | ||
* The TYPO3 project - inspiring people to share! | ||
*/ | ||
|
||
namespace TYPO3\CMS\Core\Page; | ||
|
||
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\Site\SiteFinder; | ||
use TYPO3\CMS\Core\TypoScript\PageTsConfigFactory; | ||
use TYPO3\CMS\Core\Utility\GeneralUtility; | ||
|
||
/** | ||
* Finds the proper layout for a page, using the database fields "backend_layout" | ||
* and "backend_layout_next_level". | ||
* | ||
* The most crucial part is that "backend_layout" is only applied for the CURRENT level, | ||
* whereas backend_layout_next_level. | ||
* | ||
* Used in TypoScript as "getData:pagelayout". | ||
* | ||
* Currently, there is a hard dependency on EXT:backend however, all DataProvider logic should be migrated | ||
* towards EXT:core. | ||
* | ||
* @internal This is not part of TYPO3 Core API. | ||
*/ | ||
class PageLayoutResolver | ||
{ | ||
public function __construct( | ||
protected readonly DataProviderCollection $dataProviderCollection, | ||
protected readonly SiteFinder $siteFinder, | ||
protected readonly PageTsConfigFactory $pageTsConfigFactory | ||
) { | ||
$this->dataProviderCollection->add('default', DefaultDataProvider::class); | ||
foreach ((array)($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['BackendLayoutDataProvider'] ?? []) as $identifier => $className) { | ||
$this->dataProviderCollection->add($identifier, $className); | ||
} | ||
} | ||
|
||
public function getLayoutForPage(array $pageRecord, array $rootLine): ?PageLayout | ||
{ | ||
$pageId = (int)$pageRecord['uid']; | ||
$site = $this->siteFinder->getSiteByPageId($pageId, $rootLine); | ||
$pageTsConfig = $this->pageTsConfigFactory->create($rootLine, $site); | ||
|
||
$dataProviderContext = GeneralUtility::makeInstance(DataProviderContext::class); | ||
$dataProviderContext | ||
->setPageId($pageId) | ||
->setData($pageRecord) | ||
->setTableName('pages') | ||
->setFieldName('backend_layout') | ||
->setPageTsConfig($pageTsConfig->getPageTsConfigArray()); | ||
|
||
$selectedPageLayout = $this->getLayoutIdentifierForPage($pageRecord, $rootLine); | ||
$layout = $this->dataProviderCollection->getBackendLayout($selectedPageLayout, $pageId); | ||
|
||
if ($layout === null) { | ||
return null; | ||
} | ||
|
||
$fullStructure = $layout->getStructure()['__config']; | ||
$contentAreas = []; | ||
// find all arrays recursively from , where one of the columns within the array is called "colPos" | ||
$findColPos = function (array $structure) use (&$findColPos, &$contentAreas) { | ||
if (isset($structure['colPos'])) { | ||
unset($structure['colspan'], $structure['rowspan']); | ||
$contentAreas[] = $structure; | ||
} | ||
foreach ($structure as $value) { | ||
if (is_array($value)) { | ||
$findColPos($value); | ||
} | ||
} | ||
}; | ||
$findColPos($fullStructure); | ||
|
||
return new PageLayout($layout->getIdentifier(), $layout->getTitle(), $contentAreas, $layout->getStructure()); | ||
} | ||
|
||
/** | ||
* Check if the current page has a value in the DB field "backend_layout" | ||
* if empty, check the root line for "backend_layout_next_level" | ||
* Same as TypoScript: | ||
* field = backend_layout | ||
* ifEmpty.data = levelfield:-2, backend_layout_next_level, slide | ||
* ifEmpty.ifEmpty = default | ||
*/ | ||
public function getLayoutIdentifierForPage(array $page, array $rootLine): string | ||
{ | ||
$selectedLayout = $page['backend_layout'] ?? ''; | ||
|
||
// If it is set to "none" - don't use any | ||
if ($selectedLayout === '-1') { | ||
return 'none'; | ||
} | ||
|
||
if ($selectedLayout === '' || $selectedLayout === '0') { | ||
// If it not set check the root-line for a layout on next level and use this | ||
// Remove first element, which is the current page | ||
// See also \TYPO3\CMS\Backend\View\BackendLayoutView::getSelectedCombinedIdentifier() | ||
array_shift($rootLine); | ||
foreach ($rootLine as $rootLinePage) { | ||
$selectedLayout = (string)($rootLinePage['backend_layout_next_level'] ?? ''); | ||
// If layout for "next level" is set to "none" - don't use any and stop searching | ||
if ($selectedLayout === '-1') { | ||
$selectedLayout = 'none'; | ||
break; | ||
} | ||
if ($selectedLayout !== '' && $selectedLayout !== '0') { | ||
// Stop searching if a layout for "next level" is set | ||
break; | ||
} | ||
} | ||
} | ||
if ($selectedLayout === '0' || $selectedLayout === '') { | ||
$selectedLayout = 'default'; | ||
} | ||
return $selectedLayout; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.