From 5ac249b5ef001ca5f87905f47855c2a068ec4b0a Mon Sep 17 00:00:00 2001 From: Benni Mack <benni@typo3.org> Date: Fri, 8 Mar 2024 22:42:22 +0100 Subject: [PATCH] [TASK] Streamline Backend Layout View code This change adapts some places around Backend Layouts, which is a pre-patch in order to centralize previously used code from 2013 to move towards a more generic concept, which needs to go into EXT:core as the structure should also be useful and evaluated in EXT:frontend. This change now cleans up places which are non-breaking but hardens PHP code without changing the underlying logic. Resolves: #103365 Releases: main Change-Id: I77382d93342e5c2e45966f96bf485619c79f25f3 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/83362 Reviewed-by: Oliver Bartsch <bo@cedev.de> Tested-by: Andreas Kienast <a.fernandez@scripting-base.de> Tested-by: Oliver Bartsch <bo@cedev.de> Reviewed-by: Andreas Kienast <a.fernandez@scripting-base.de> Tested-by: core-ci <typo3@b13.com> --- .../View/BackendLayout/BackendLayout.php | 116 ++++------------ .../BackendLayout/DataProviderCollection.php | 34 ++--- .../BackendLayout/DataProviderContext.php | 79 +++-------- .../BackendLayout/DefaultDataProvider.php | 34 ++--- .../PageTsBackendLayoutDataProvider.php | 22 +-- .../Classes/View/BackendLayoutView.php | 130 ++++++------------ .../View/BackendLayoutViewTest.php | 44 ++++-- 7 files changed, 136 insertions(+), 323 deletions(-) rename typo3/sysext/backend/Tests/{Unit => Functional}/View/BackendLayoutViewTest.php (88%) diff --git a/typo3/sysext/backend/Classes/View/BackendLayout/BackendLayout.php b/typo3/sysext/backend/Classes/View/BackendLayout/BackendLayout.php index dd499041c870..cc85112ac211 100644 --- a/typo3/sysext/backend/Classes/View/BackendLayout/BackendLayout.php +++ b/typo3/sysext/backend/Classes/View/BackendLayout/BackendLayout.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + /* * This file is part of the TYPO3 CMS project. * @@ -23,50 +25,19 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; */ class BackendLayout { - /** - * @var string - */ - protected $identifier; - - /** - * @var string - */ - protected $title; - - /** - * @var string - */ - protected $description; - - /** - * @var string - */ - protected $iconPath; - - /** - * @var string - */ - protected $configuration; + protected string $identifier; + protected string $title; + protected string $description = ''; + protected string $iconPath = ''; + protected string $configuration = ''; /** * The structured data of the configuration represented as array. - * - * @var array */ - protected $structure = []; + protected array $structure = []; + protected array $data = []; - /** - * @var array - */ - protected $data; - - /** - * @param string $identifier - * @param string $title - * @param string|array $configuration - * @return BackendLayout - */ - public static function create($identifier, $title, $configuration) + public static function create(string $identifier, string $title, string|array $configuration): BackendLayout { return GeneralUtility::makeInstance( static::class, @@ -76,12 +47,7 @@ class BackendLayout ); } - /** - * @param string $identifier - * @param string $title - * @param string|array $configuration - */ - public function __construct($identifier, $title, $configuration) + public function __construct(string $identifier, string $title, string|array $configuration) { $this->setIdentifier($identifier); $this->setTitle($title); @@ -93,19 +59,12 @@ class BackendLayout } } - /** - * @return string - */ - public function getIdentifier() + public function getIdentifier(): string { return $this->identifier; } - /** - * @param string $identifier - * @throws \UnexpectedValueException - */ - public function setIdentifier($identifier) + public function setIdentifier(string $identifier): void { if (str_contains($identifier, '__')) { throw new \UnexpectedValueException( @@ -117,66 +76,42 @@ class BackendLayout $this->identifier = $identifier; } - /** - * @return string - */ - public function getTitle() + public function getTitle(): string { return $this->title; } - /** - * @param string $title - */ - public function setTitle($title) + public function setTitle(string $title): void { $this->title = $title; } - /** - * @return string - */ - public function getDescription() + public function getDescription(): string { return $this->description; } - /** - * @param string $description - */ - public function setDescription($description) + public function setDescription(string $description): void { $this->description = $description; } - /** - * @return string - */ - public function getIconPath() + public function getIconPath(): string { return $this->iconPath; } - /** - * @param string $iconPath - */ - public function setIconPath($iconPath) + public function setIconPath(string $iconPath): void { $this->iconPath = $iconPath; } - /** - * @return string - */ - public function getConfiguration() + public function getConfiguration(): string { return $this->configuration; } - /** - * @param string $configuration - */ - public function setConfiguration($configuration) + public function setConfiguration(string $configuration): void { $this->configuration = $configuration; $this->structure = GeneralUtility::makeInstance(BackendLayoutView::class)->parseStructure($this); @@ -203,20 +138,17 @@ class BackendLayout return $this->structure['rowCount'] ?? 0; } - /** - * @return array - */ - public function getData() + public function getData(): array { return $this->data; } - public function setData(array $data) + public function setData(array $data): void { $this->data = $data; } - public function setStructure(array $structure) + public function setStructure(array $structure): void { $this->structure = $structure; } diff --git a/typo3/sysext/backend/Classes/View/BackendLayout/DataProviderCollection.php b/typo3/sysext/backend/Classes/View/BackendLayout/DataProviderCollection.php index 141a5673722e..5bcb0465a14d 100644 --- a/typo3/sysext/backend/Classes/View/BackendLayout/DataProviderCollection.php +++ b/typo3/sysext/backend/Classes/View/BackendLayout/DataProviderCollection.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + /* * This file is part of the TYPO3 CMS project. * @@ -24,24 +26,15 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; class DataProviderCollection implements SingletonInterface { /** - * @var array|DataProviderInterface[] - */ - protected $dataProviders = []; - - /** - * @var array + * @var DataProviderInterface[] */ - protected $results = []; + protected array $dataProviders = []; + protected array $results = []; /** * Adds a data provider to this collection. - * - * @param string $identifier - * @param string|object $classNameOrObject - * @throws \UnexpectedValueException - * @throws \LogicException */ - public function add($identifier, $classNameOrObject) + public function add(string $identifier, string|object $classNameOrObject): void { if (str_contains($identifier, '__')) { throw new \UnexpectedValueException( @@ -73,9 +66,9 @@ class DataProviderCollection implements SingletonInterface * backend layouts. Each data provider returns its own * backend layout collection. * - * @return array|BackendLayoutCollection[] + * @return BackendLayoutCollection[] */ - public function getBackendLayoutCollections(DataProviderContext $dataProviderContext) + public function getBackendLayoutCollections(DataProviderContext $dataProviderContext): array { $result = []; @@ -93,12 +86,8 @@ class DataProviderCollection implements SingletonInterface * e.g. "myextension_regular" and "myextension" is the identifier * of the accordant data provider and "regular" the identifier of * the accordant backend layout. - * - * @param string $combinedIdentifier - * @param int $pageId - * @return BackendLayout|null */ - public function getBackendLayout($combinedIdentifier, $pageId) + public function getBackendLayout(string $combinedIdentifier, int $pageId): ?BackendLayout { $backendLayout = null; @@ -118,11 +107,8 @@ class DataProviderCollection implements SingletonInterface /** * Creates a new backend layout collection. - * - * @param string $identifier - * @return BackendLayoutCollection */ - protected function createBackendLayoutCollection($identifier) + protected function createBackendLayoutCollection(string $identifier): BackendLayoutCollection { return GeneralUtility::makeInstance( BackendLayoutCollection::class, diff --git a/typo3/sysext/backend/Classes/View/BackendLayout/DataProviderContext.php b/typo3/sysext/backend/Classes/View/BackendLayout/DataProviderContext.php index 8d09efaf8568..2b21457c7747 100644 --- a/typo3/sysext/backend/Classes/View/BackendLayout/DataProviderContext.php +++ b/typo3/sysext/backend/Classes/View/BackendLayout/DataProviderContext.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + /* * This file is part of the TYPO3 CMS project. * @@ -22,97 +24,51 @@ use TYPO3\CMS\Core\SingletonInterface; */ class DataProviderContext implements SingletonInterface { - /** - * @var int - */ - protected $pageId; - - /** - * @var string - */ - protected $tableName; - - /** - * @var string - */ - protected $fieldName; - - /** - * @var array - */ - protected $data; - - /** - * @var array - */ - protected $pageTsConfig; + protected int $pageId = 0; + protected string $tableName = ''; + protected string $fieldName = ''; + protected array $data = []; + protected array $pageTsConfig = []; - /** - * @return int - */ - public function getPageId() + public function getPageId(): int { return $this->pageId; } - /** - * @param int $pageId - * @return DataProviderContext - */ - public function setPageId($pageId) + public function setPageId(int $pageId): self { $this->pageId = $pageId; return $this; } - /** - * @return string - */ - public function getTableName() + public function getTableName(): string { return $this->tableName; } - /** - * @param string $tableName - * @return DataProviderContext - */ - public function setTableName($tableName) + public function setTableName(string $tableName): self { $this->tableName = $tableName; return $this; } - /** - * @return string - */ - public function getFieldName() + public function getFieldName(): string { return $this->fieldName; } - /** - * @param string $fieldName - * @return DataProviderContext - */ - public function setFieldName($fieldName) + public function setFieldName(string $fieldName): self { $this->fieldName = $fieldName; return $this; } - /** - * @return array - */ - public function getData() + public function getData(): array { return $this->data; } - /** - * @return DataProviderContext - */ - public function setData(array $data) + public function setData(array $data): self { $this->data = $data; return $this; @@ -123,10 +79,7 @@ class DataProviderContext implements SingletonInterface return $this->pageTsConfig; } - /** - * @return DataProviderContext - */ - public function setPageTsConfig(array $pageTsConfig) + public function setPageTsConfig(array $pageTsConfig): self { $this->pageTsConfig = $pageTsConfig; return $this; diff --git a/typo3/sysext/backend/Classes/View/BackendLayout/DefaultDataProvider.php b/typo3/sysext/backend/Classes/View/BackendLayout/DefaultDataProvider.php index 03a2b3001caa..1b183499475d 100644 --- a/typo3/sysext/backend/Classes/View/BackendLayout/DefaultDataProvider.php +++ b/typo3/sysext/backend/Classes/View/BackendLayout/DefaultDataProvider.php @@ -1,5 +1,7 @@ <?php +declare(strict_types=1); + /* * This file is part of the TYPO3 CMS project. * @@ -31,10 +33,9 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; class DefaultDataProvider implements DataProviderInterface { /** - * @var string * Table name for backend_layouts */ - protected $tableName = 'backend_layout'; + protected string $tableName = 'backend_layout'; /** * Adds backend layouts to the given backend layout collection. @@ -44,7 +45,7 @@ class DefaultDataProvider implements DataProviderInterface public function addBackendLayouts( DataProviderContext $dataProviderContext, BackendLayoutCollection $backendLayoutCollection - ) { + ): void { $layoutData = $this->getLayoutData( $dataProviderContext->getFieldName(), $dataProviderContext->getPageTsConfig(), @@ -62,9 +63,8 @@ class DefaultDataProvider implements DataProviderInterface * * @param string|int $identifier * @param int $pageId - * @return BackendLayout|null */ - public function getBackendLayout($identifier, $pageId) + public function getBackendLayout($identifier, $pageId): ?BackendLayout { $backendLayout = null; @@ -83,10 +83,8 @@ class DefaultDataProvider implements DataProviderInterface /** * Creates a backend layout with the default configuration. - * - * @return BackendLayout */ - protected function createDefaultBackendLayout() + protected function createDefaultBackendLayout(): BackendLayout { return BackendLayout::create( 'default', @@ -97,12 +95,10 @@ class DefaultDataProvider implements DataProviderInterface /** * Creates a new backend layout using the given record data. - * - * @return BackendLayout */ - protected function createBackendLayout(array $data) + protected function createBackendLayout(array $data): BackendLayout { - $backendLayout = BackendLayout::create($data['uid'], $data['title'], $data['config']); + $backendLayout = BackendLayout::create((string)$data['uid'], $data['title'], $data['config']); $backendLayout->setIconPath($this->getIconPath($data)); $backendLayout->setData($data); return $backendLayout; @@ -110,10 +106,8 @@ class DefaultDataProvider implements DataProviderInterface /** * Resolves the icon from the database record - * - * @return string */ - protected function getIconPath(array $icon) + protected function getIconPath(array $icon): string { $fileRepository = GeneralUtility::makeInstance(FileRepository::class); $references = $fileRepository->findByRelation($this->tableName, 'icon', (int)$icon['uid']); @@ -132,7 +126,7 @@ class DefaultDataProvider implements DataProviderInterface * @param int $pageUid the ID of the page wea re getting the layouts for * @return array $layouts A collection of layout data of the registered provider */ - protected function getLayoutData($fieldName, array $pageTsConfig, $pageUid) + protected function getLayoutData(string $fieldName, array $pageTsConfig, int $pageUid): array { $storagePid = $this->getStoragePid($pageTsConfig); $pageTsConfigId = $this->getPageTSconfigIds($pageTsConfig); @@ -207,10 +201,8 @@ class DefaultDataProvider implements DataProviderInterface /** * Returns the storage PID from TCEFORM. - * - * @return int */ - protected function getStoragePid(array $pageTsConfig) + protected function getStoragePid(array $pageTsConfig): int { $storagePid = 0; @@ -223,10 +215,8 @@ class DefaultDataProvider implements DataProviderInterface /** * Returns the page TSconfig from TCEFORM. - * - * @return array */ - protected function getPageTSconfigIds(array $pageTsConfig) + protected function getPageTSconfigIds(array $pageTsConfig): array { $pageTsConfigIds = [ 'backend_layout' => 0, diff --git a/typo3/sysext/backend/Classes/View/BackendLayout/PageTsBackendLayoutDataProvider.php b/typo3/sysext/backend/Classes/View/BackendLayout/PageTsBackendLayoutDataProvider.php index d89ae0c0fb87..390443b81bfb 100644 --- a/typo3/sysext/backend/Classes/View/BackendLayout/PageTsBackendLayoutDataProvider.php +++ b/typo3/sysext/backend/Classes/View/BackendLayout/PageTsBackendLayoutDataProvider.php @@ -130,7 +130,7 @@ final class PageTsBackendLayoutDataProvider implements DataProviderInterface private function generateBackendLayoutFromTsConfig(string $identifier, array $data): ?array { $backendLayout = []; - if (!empty($data['config.']['backend_layout.']) && is_array($data['config.']['backend_layout.'])) { + if (is_array($data['config.']['backend_layout.'] ?? null)) { $backendLayout['uid'] = substr($identifier, 0, -1); $backendLayout['title'] = $data['title'] ?? $backendLayout['uid']; $backendLayout['icon'] = $data['icon'] ?? ''; @@ -148,7 +148,7 @@ final class PageTsBackendLayoutDataProvider implements DataProviderInterface /** * Attach Backend Layout to internal Stack */ - private function attachBackendLayout(mixed $backendLayout = null) + private function attachBackendLayout(mixed $backendLayout = null): void { if ($backendLayout) { $this->backendLayouts[$backendLayout['uid']] = $backendLayout; @@ -160,23 +160,9 @@ final class PageTsBackendLayoutDataProvider implements DataProviderInterface */ private function createBackendLayout(array $data): BackendLayout { - $backendLayout = BackendLayout::create($data['uid'], $data['title'], $data['config']); - $backendLayout->setIconPath($this->getIconPath($data['icon'])); + $backendLayout = BackendLayout::create((string)$data['uid'], $data['title'], $data['config']); + $backendLayout->setIconPath($data['icon'] ?? ''); $backendLayout->setData($data); return $backendLayout; } - - /** - * Gets and sanitizes the icon path. - * - * @param string $icon Name of the icon file - */ - private function getIconPath(string $icon): string - { - $iconPath = ''; - if (!empty($icon)) { - $iconPath = $icon; - } - return $iconPath; - } } diff --git a/typo3/sysext/backend/Classes/View/BackendLayoutView.php b/typo3/sysext/backend/Classes/View/BackendLayoutView.php index 9211bbf2a2e3..23a8759376aa 100644 --- a/typo3/sysext/backend/Classes/View/BackendLayoutView.php +++ b/typo3/sysext/backend/Classes/View/BackendLayoutView.php @@ -47,11 +47,8 @@ class BackendLayoutView implements SingletonInterface private readonly TypoScriptStringFactory $typoScriptStringFactory, ) { $this->dataProviderCollection->add('default', DefaultDataProvider::class); - if (!empty($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['BackendLayoutDataProvider'])) { - $dataProviders = (array)$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['BackendLayoutDataProvider']; - foreach ($dataProviders as $identifier => $className) { - $this->dataProviderCollection->add($identifier, $className); - } + foreach ((array)($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['BackendLayoutDataProvider'] ?? []) as $identifier => $className) { + $this->dataProviderCollection->add($identifier, $className); } } @@ -70,10 +67,11 @@ class BackendLayoutView implements SingletonInterface public function addBackendLayoutItems(array &$parameters) { $pageId = $this->determinePageId($parameters['table'], $parameters['row']) ?: 0; - $pageTsConfig = (array)BackendUtility::getPagesTSconfig($pageId); + $pageTsConfig = BackendUtility::getPagesTSconfig($pageId); $identifiersToBeExcluded = $this->getIdentifiersToBeExcluded($pageTsConfig); - $dataProviderContext = $this->createDataProviderContext() + $dataProviderContext = GeneralUtility::makeInstance(DataProviderContext::class); + $dataProviderContext ->setPageId($pageId) ->setData($parameters['row']) ->setTableName($parameters['table']) @@ -106,12 +104,11 @@ class BackendLayoutView implements SingletonInterface /** * Determines the page id for a given record of a database table. * - * @param string $tableName * @return int|false Returns page id or false on error */ - protected function determinePageId($tableName, array $data) + protected function determinePageId(string $tableName, array $data): int|false { - if (empty($data)) { + if ($data === []) { return false; } @@ -144,28 +141,26 @@ class BackendLayoutView implements SingletonInterface $pageId = $data['pid']; } - return $pageId; + return (int)$pageId; } /** * Returns the backend layout which should be used for this page. * - * @param int $pageId - * @return bool|string Identifier of the backend layout to be used, or FALSE if none + * @return false|string Identifier of the backend layout to be used, or FALSE if none */ - public function getSelectedCombinedIdentifier($pageId) + protected function getSelectedCombinedIdentifier(int $pageId): string|false { if (!isset($this->selectedCombinedIdentifier[$pageId])) { $page = $this->getPage($pageId); $this->selectedCombinedIdentifier[$pageId] = (string)($page['backend_layout'] ?? null); - if ($this->selectedCombinedIdentifier[$pageId] === '-1') { // If it is set to "none" - don't use any $this->selectedCombinedIdentifier[$pageId] = false; } elseif ($this->selectedCombinedIdentifier[$pageId] === '' || $this->selectedCombinedIdentifier[$pageId] === '0') { // If it not set check the root-line for a layout on next level and use this // (root-line starts with current page and has page "0" at the end) - $rootLine = $this->getRootLine($pageId); + $rootLine = BackendUtility::BEgetRootLine($pageId, '', true); // Remove first and last element (current and root page) array_shift($rootLine); array_pop($rootLine); @@ -189,10 +184,8 @@ class BackendLayoutView implements SingletonInterface /** * Gets backend layout identifiers to be excluded - * - * @return array */ - protected function getIdentifiersToBeExcluded(array $pageTSconfig) + protected function getIdentifiersToBeExcluded(array $pageTSconfig): array { $identifiersToBeExcluded = []; @@ -212,7 +205,7 @@ class BackendLayoutView implements SingletonInterface * This method is called as "itemsProcFunc" with the accordant context * for tt_content.colPos. */ - public function colPosListItemProcFunc(array $parameters) + public function colPosListItemProcFunc(array &$parameters): void { $pageId = $this->determinePageId($parameters['table'], $parameters['row']); @@ -223,12 +216,8 @@ class BackendLayoutView implements SingletonInterface /** * Adds items to a colpos list - * - * @param int $pageId - * @param array $items - * @return array */ - protected function addColPosListLayoutItems($pageId, $items) + protected function addColPosListLayoutItems(int $pageId, array $items): array { $layout = $this->getSelectedBackendLayout($pageId); if ($layout && !empty($layout['__items'])) { @@ -239,11 +228,9 @@ class BackendLayoutView implements SingletonInterface /** * Gets the list of available columns for a given page id - * - * @param int $id - * @return array $tcaItems + * @todo: will be removed once Page Position Map for content is removed. */ - public function getColPosListItemsParsed($id) + public function getColPosListItemsParsed(int $id): array { $tsConfig = BackendUtility::getPagesTSconfig($id)['TCEFORM.']['tt_content.']['colPos.'] ?? []; $tcaConfig = $GLOBALS['TCA']['tt_content']['columns']['colPos']['config'] ?? []; @@ -275,43 +262,36 @@ class BackendLayoutView implements SingletonInterface * @return array The updated $item array * @internal */ - protected function addItems($items, $iArray) + protected function addItems(array $items, array $iArray): array { $languageService = $this->getLanguageService(); - if (is_array($iArray)) { - foreach ($iArray as $value => $label) { - // if the label is an array (that means it is a subelement - // like "34.icon = mylabel.png", skip it (see its usage below) - if (is_array($label)) { - continue; - } - // check if the value "34 = mylabel" also has a "34.icon = myimage.png" - if (isset($iArray[$value . '.']) && $iArray[$value . '.']['icon']) { - $icon = $iArray[$value . '.']['icon']; - } else { - $icon = ''; - } - $items[] = [$languageService->sL($label), $value, $icon]; + foreach ($iArray as $value => $label) { + // if the label is an array (that means it is a subelement + // like "34.icon = mylabel.png", skip it (see its usage below) + if (is_array($label)) { + continue; + } + // check if the value "34 = mylabel" also has a "34.icon = myimage.png" + if (isset($iArray[$value . '.']) && $iArray[$value . '.']['icon']) { + $icon = $iArray[$value . '.']['icon']; + } else { + $icon = ''; } + $items[] = [$languageService->sL($label), $value, $icon]; } return $items; } /** * Gets the selected backend layout structure as an array - * - * @param int $pageId - * @return array|null $backendLayout */ - public function getSelectedBackendLayout($pageId) + public function getSelectedBackendLayout(int $pageId): ?array { - $layout = $this->getBackendLayoutForPage((int)$pageId); - return $layout?->getStructure(); + return $this->getBackendLayoutForPage($pageId)?->getStructure(); } /** * Get the BackendLayout object and parse the structure based on the UserTSconfig - * @return BackendLayout */ public function getBackendLayoutForPage(int $pageId): ?BackendLayout { @@ -329,7 +309,7 @@ class BackendLayoutView implements SingletonInterface $backendLayout = $this->dataProviderCollection->getBackendLayout('default', $pageId); } - if ($backendLayout instanceof BackendLayout) { + if ($backendLayout !== null) { $this->selectedBackendLayout[$pageId] = $backendLayout; } return $backendLayout; @@ -376,12 +356,9 @@ class BackendLayoutView implements SingletonInterface } /** - * Get default columns layout - * - * @return string Default four column layout - * @static + * Get default columns layout (main column) */ - public static function getDefaultColumnLayout() + public static function getDefaultColumnLayout(): string { return ' backend_layout { @@ -403,11 +380,8 @@ class BackendLayoutView implements SingletonInterface /** * Gets a page record. - * - * @param int $pageId - * @return array|false|null */ - protected function getPage($pageId) + protected function getPage(int $pageId): ?array { $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) ->getQueryBuilderForTable('pages'); @@ -424,28 +398,11 @@ class BackendLayoutView implements SingletonInterface ) ->executeQuery() ->fetchAssociative(); - BackendUtility::workspaceOL('pages', $page); - - return $page; - } - - /** - * Gets the page root-line. - * - * @param int $pageId - * @return array - */ - protected function getRootLine($pageId) - { - return BackendUtility::BEgetRootLine($pageId, '', true); - } + if (is_array($page)) { + BackendUtility::workspaceOL('pages', $page); + } - /** - * @return DataProviderContext - */ - protected function createDataProviderContext() - { - return GeneralUtility::makeInstance(DataProviderContext::class); + return is_array($page) ? $page : null; } protected function getLanguageService(): LanguageService @@ -455,14 +412,9 @@ class BackendLayoutView implements SingletonInterface /** * Get column name from colPos item structure - * - * @param array $column - * @return string */ - protected function getColumnName($column) + protected function getColumnName(array $column): string { - $columnName = $column['name']; - $columnName = $this->getLanguageService()->sL($columnName); - return $columnName; + return $this->getLanguageService()->sL($column['name']); } } diff --git a/typo3/sysext/backend/Tests/Unit/View/BackendLayoutViewTest.php b/typo3/sysext/backend/Tests/Functional/View/BackendLayoutViewTest.php similarity index 88% rename from typo3/sysext/backend/Tests/Unit/View/BackendLayoutViewTest.php rename to typo3/sysext/backend/Tests/Functional/View/BackendLayoutViewTest.php index 5e56d0c919c1..a5904c937724 100644 --- a/typo3/sysext/backend/Tests/Unit/View/BackendLayoutViewTest.php +++ b/typo3/sysext/backend/Tests/Functional/View/BackendLayoutViewTest.php @@ -15,49 +15,55 @@ declare(strict_types=1); * The TYPO3 project - inspiring people to share! */ -namespace TYPO3\CMS\Backend\Tests\Unit\View; +namespace TYPO3\CMS\Backend\Tests\Functional\View; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\MockObject\MockObject; use TYPO3\CMS\Backend\View\BackendLayoutView; +use TYPO3\CMS\Core\Cache\CacheManager; +use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; use TYPO3\TestingFramework\Core\AccessibleObjectInterface; -use TYPO3\TestingFramework\Core\Unit\UnitTestCase; +use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; -final class BackendLayoutViewTest extends UnitTestCase +final class BackendLayoutViewTest extends FunctionalTestCase { - protected BackendLayoutView&MockObject&AccessibleObjectInterface $backendLayoutView; + private const RUNTIME_CACHE_ENTRY = 'backendUtilityBeGetRootLine'; + + private FrontendInterface $runtimeCache; + private BackendLayoutView&MockObject&AccessibleObjectInterface $backendLayoutView; - /** - * Sets up this test case. - */ protected function setUp(): void { parent::setUp(); + $this->runtimeCache = $this->get(CacheManager::class)->getCache('runtime'); $this->backendLayoutView = $this->getAccessibleMock( BackendLayoutView::class, - ['getPage', 'getRootLine'], + ['getPage'], [], '', false ); } - /** - * @param bool|string $expected - */ + protected function tearDown(): void + { + $this->runtimeCache->remove(self::RUNTIME_CACHE_ENTRY); + parent::tearDown(); + } + #[DataProvider('selectedCombinedIdentifierIsDeterminedDataProvider')] #[Test] - public function selectedCombinedIdentifierIsDetermined($expected, array $page, array $rootLine): void + public function selectedCombinedIdentifierIsDetermined(false|string $expected, array $page, array $rootLine): void { $pageId = $page['uid']; + if ($pageId !== false) { + $this->mockRootLine((int)$pageId, $rootLine); + } $this->backendLayoutView->expects(self::once()) ->method('getPage')->with(self::equalTo($pageId)) ->willReturn($page); - $this->backendLayoutView - ->method('getRootLine')->with(self::equalTo($pageId)) - ->willReturn($rootLine); $selectedCombinedIdentifier = $this->backendLayoutView->_call('getSelectedCombinedIdentifier', $pageId); self::assertEquals($expected, $selectedCombinedIdentifier); @@ -201,4 +207,12 @@ final class BackendLayoutViewTest extends UnitTestCase ], ]; } + + private function mockRootLine(int $pageId, array $rootLine): void + { + $this->runtimeCache->set(self::RUNTIME_CACHE_ENTRY, [ + $pageId . '--' => $rootLine, // plain, no overlay + $pageId . '--1' => $rootLine, // workspace overlay + ]); + } } -- GitLab