From 31e37247ef8131978ec9e217dd261243b18506f0 Mon Sep 17 00:00:00 2001 From: Benni Mack <benni@typo3.org> Date: Tue, 19 Mar 2024 20:34:35 +0100 Subject: [PATCH] [FEATURE] Group-based content fetching in Frontend This change adds a new RecordCollector which is similar to CONTENT cObject, except that it does not render the records directly, but instead creates instances of a generic Record object, so the Templating Engine can deal with the way of how the record should be rendered. Based on the Page Layout / Backend Layout, all registered colPos contents are fetched, and grouped, if the Backend Layout has an "identifier" set via a new PageContentFetchingProcessor ("page-content"). The slide functionality can now be defined in the Page Layout as well (Backend Layout), with a Enum defining to Collect, CollectReverse and a simple Slide logic. This feature brings a clearer separation of fetching content from the database and the actual representation in the output (fluid) in place, allowing for further optimizations. In addition, one needs to write much less TypoScript to fetch all contents from a page. Next steps is then to enrich the records with their relations (see next feature), and to optimize the Fluid-based rendering for any kind of content. Resolves: #103894 Releases: main Change-Id: I6a1a0efacefe8c83e86b9551b00199c93e284a28 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/83638 Reviewed-by: Oliver Bartsch <bo@cedev.de> Tested-by: Georg Ringer <georg.ringer@gmail.com> Reviewed-by: Benni Mack <benni@typo3.org> Tested-by: Oliver Bartsch <bo@cedev.de> Reviewed-by: Georg Ringer <georg.ringer@gmail.com> Tested-by: core-ci <typo3@b13.com> Tested-by: Benni Mack <benni@typo3.org> --- .../Classes/View/BackendLayoutView.php | 1 + ...ionalPropertiesForColumnsInPageLayouts.rst | 101 ++++++++++++++++++ .../Classes/Content/ContentSlideMode.php | 36 +++++++ .../Classes/Content/RecordCollector.php | 83 ++++++++++++++ .../PageContentFetchingProcessor.php | 73 +++++++++++++ .../frontend/Configuration/Services.yaml | 4 + .../PageContentProcessor/Pages/Default.html | 26 +++++ .../PageContentProcessor/Pages/Home.html | 16 +++ .../Pages/Productdetail.html | 26 +++++ .../Partials/SingleContent.html | 6 ++ .../PageContentProcessor/setup.typoscript | 6 ++ .../{ => RecordTransform}/setup.typoscript | 0 .../PageContentFetchingProcessorTest.php | 94 ++++++++++++++++ .../RecordTransformationProcessorTest.php | 2 +- 14 files changed, 473 insertions(+), 1 deletion(-) create mode 100644 typo3/sysext/core/Documentation/Changelog/13.2/Feature-103894-AdditionalPropertiesForColumnsInPageLayouts.rst create mode 100644 typo3/sysext/frontend/Classes/Content/ContentSlideMode.php create mode 100644 typo3/sysext/frontend/Classes/Content/RecordCollector.php create mode 100644 typo3/sysext/frontend/Classes/DataProcessing/PageContentFetchingProcessor.php create mode 100644 typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Pages/Default.html create mode 100644 typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Pages/Home.html create mode 100644 typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Pages/Productdetail.html create mode 100644 typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Partials/SingleContent.html create mode 100644 typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/setup.typoscript rename typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/{ => RecordTransform}/setup.typoscript (100%) create mode 100644 typo3/sysext/frontend/Tests/Functional/DataProcessing/PageContentFetchingProcessorTest.php diff --git a/typo3/sysext/backend/Classes/View/BackendLayoutView.php b/typo3/sysext/backend/Classes/View/BackendLayoutView.php index 3ede3dfb0f30..bcbb46df3741 100644 --- a/typo3/sysext/backend/Classes/View/BackendLayoutView.php +++ b/typo3/sysext/backend/Classes/View/BackendLayoutView.php @@ -302,6 +302,7 @@ class BackendLayoutView implements SingletonInterface 1 { name = LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:colPos.I.1 colPos = 0 + identifier = main } } } diff --git a/typo3/sysext/core/Documentation/Changelog/13.2/Feature-103894-AdditionalPropertiesForColumnsInPageLayouts.rst b/typo3/sysext/core/Documentation/Changelog/13.2/Feature-103894-AdditionalPropertiesForColumnsInPageLayouts.rst new file mode 100644 index 000000000000..16a294b4b900 --- /dev/null +++ b/typo3/sysext/core/Documentation/Changelog/13.2/Feature-103894-AdditionalPropertiesForColumnsInPageLayouts.rst @@ -0,0 +1,101 @@ +.. include:: /Includes.rst.txt + +.. _feature-103894-1716544976: + +==================================================================== +Feature: #103894 - Additional properties for columns in Page Layouts +==================================================================== + +See :issue:`103894` + +Description +=========== + +Backend Layouts were introduced in TYPO3 v6 in order to customize the view of +the Page module in TYPO3 Backend for a page, but has then since grown also in +Frontend rendering to select e.g. Fluid template files via TypoScript for a page, +commonly used via :typoscript:`data:pagelayout`. + +In order to use a single source for Backend and Frontend representation, the +definition of a "Backend Layout" or "Page Layout" is expanded to also include +more information for a specific content area. The Content Area is previously +defined via "name" (for the label in the Page Module) and "colPos", +the numeric database field in which content is grouped in. + +A definition can now optionally also contain a "slideMode" property and an +"identifier" property next to each colPos, in order to simplify the Frontend +rendering. + +Whereas "identifier" is a speaking representation for the colPos, such as +"main", "sidebar" or "footerArea", the "slideMode" can be set to one of the +three options: + +* :typoscript:`slideMode = slide` - if no content is found, check the parent pages for more content +* :typoscript:`slideMode = collect` - use all content from this page, and the parent pages as one collection +* :typoscript:`slideMode = collectReverse`- same as "collect" but in the opposite order + +With this information added, a new DataProcessor :typoscript:"page-content" +(:php:`PageContentFetchingProcessor`) is introduced for the Frontend Rendering, +which fetches all content for a page respecting the settings from the +Page Layout. + + +Impact +====== + +Enriching the Backend Layout information for each colPos enables a TYPO3 +integrator to write less TypoScript in order to render content on a page. + +The DataProcessor fetches all content elements from all defined columns with an +included "identifier" in the selected Backend Layout and makes the resolved +record objects available in the Fluid Template via +:html:`{content."myIdentifier".records}`. + +Example for an enriched Backend Layout definition: + +.. code-block:: typoscript + + mod.web_layout.BackendLayouts { + default { + title = Default + config { + backend_layout { + colCount = 1 + rowCount = 1 + rows { + 1 { + columns { + 1 { + name = Main Content Area + colPos = 0 + identifier = main + slideMode = slide + } + } + } + } + } + } + } + } + +Example for the Frontend output: + +.. code-block:: typoscript + + page = PAGE + page.10 = PAGEVIEW + page.10.paths.10 = EXT:my_site_package/Tests/Resources/Private/Templates/ + page.10.dataProcessing.10 = page-content + page.10.dataProcessing.10.as = myContent + +.. code-block:: html + + <main> + <f:for each="{myContent.main.records}" as="record"> + <h4>{record.header}</h4> + </f:for> + </main> + + +.. index:: Backend, Frontend, ext:frontend diff --git a/typo3/sysext/frontend/Classes/Content/ContentSlideMode.php b/typo3/sysext/frontend/Classes/Content/ContentSlideMode.php new file mode 100644 index 000000000000..65f5dacfb25a --- /dev/null +++ b/typo3/sysext/frontend/Classes/Content/ContentSlideMode.php @@ -0,0 +1,36 @@ +<?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\Frontend\Content; + +enum ContentSlideMode +{ + case None; + case Slide; + case Collect; + case CollectReverse; + + public static function tryFrom(?string $slideMode): ContentSlideMode + { + return match ($slideMode) { + 'slide' => self::Slide, + 'collect' => self::Collect, + 'collectReverse' => self::CollectReverse, + default => self::None, + }; + } +} diff --git a/typo3/sysext/frontend/Classes/Content/RecordCollector.php b/typo3/sysext/frontend/Classes/Content/RecordCollector.php new file mode 100644 index 000000000000..a4d768db2a25 --- /dev/null +++ b/typo3/sysext/frontend/Classes/Content/RecordCollector.php @@ -0,0 +1,83 @@ +<?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\Frontend\Content; + +use TYPO3\CMS\Core\Domain\RecordFactory; +use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; + +/** + * Executes a SQL query, and retrieves TCA-based records for Frontend rendering. + */ +class RecordCollector +{ + public function __construct( + protected readonly RecordFactory $recordFactory + ) {} + + public function collect( + string $table, + array $select, + ContentSlideMode $slideMode, + ContentObjectRenderer $contentObjectRenderer + ): array { + $slideCollectReverse = false; + $collect = false; + switch ($slideMode) { + case ContentSlideMode::Slide: + $slide = true; + break; + case ContentSlideMode::Collect: + $slide = true; + $collect = true; + break; + case ContentSlideMode::CollectReverse: + $slide = true; + $collect = true; + $slideCollectReverse = true; + break; + default: + $slide = false; + } + $again = false; + $totalRecords = []; + + do { + $recordsOnPid = $contentObjectRenderer->getRecords($table, $select); + $recordsOnPid = array_map( + function ($record) use ($table) { + return $this->recordFactory->createFromDatabaseRow($table, $record); + }, + $recordsOnPid + ); + + if ($slideCollectReverse) { + $totalRecords = array_merge($totalRecords, $recordsOnPid); + } else { + $totalRecords = array_merge($recordsOnPid, $totalRecords); + } + if ($slide) { + $select['pidInList'] = $contentObjectRenderer->getSlidePids($select['pidInList'] ?? '', $select['pidInList.'] ?? []); + if (isset($select['pidInList.'])) { + unset($select['pidInList.']); + } + $again = $select['pidInList'] !== ''; + } + } while ($again && $slide && ($recordsOnPid === [] || $collect)); + return $totalRecords; + } +} diff --git a/typo3/sysext/frontend/Classes/DataProcessing/PageContentFetchingProcessor.php b/typo3/sysext/frontend/Classes/DataProcessing/PageContentFetchingProcessor.php new file mode 100644 index 000000000000..1d0978f3d02a --- /dev/null +++ b/typo3/sysext/frontend/Classes/DataProcessing/PageContentFetchingProcessor.php @@ -0,0 +1,73 @@ +<?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\Frontend\DataProcessing; + +use TYPO3\CMS\Core\Page\PageLayoutResolver; +use TYPO3\CMS\Frontend\Content\ContentSlideMode; +use TYPO3\CMS\Frontend\Content\RecordCollector; +use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; +use TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface; + +/** + * All-in-one data processor that loads all tt_content records from the current page layout into + * the template with a given identifier for each colPos, also respecting slideMode or + * collect options based on the page layouts content columns. + */ +readonly class PageContentFetchingProcessor implements DataProcessorInterface +{ + public function __construct( + protected RecordCollector $recordCollector, + protected PageLayoutResolver $pageLayoutResolver, + ) {} + + public function process( + ContentObjectRenderer $cObj, + array $contentObjectConfiguration, + array $processorConfiguration, + array $processedData + ): array { + if (isset($processorConfiguration['if.']) && !$cObj->checkIf($processorConfiguration['if.'])) { + return $processedData; + } + $pageInformation = $cObj->getRequest()->getAttribute('frontend.page.information'); + $pageLayout = $pageInformation->getPageLayout(); + + $targetVariableName = $cObj->stdWrapValue('as', $processorConfiguration, 'content'); + foreach ($pageLayout?->getContentAreas() ?? [] as $contentAreaData) { + if (!isset($contentAreaData['colPos'])) { + continue; + } + if (!isset($contentAreaData['identifier'])) { + continue; + } + $records = $this->recordCollector->collect( + 'tt_content', + [ + 'where' => '{#colPos}=' . (int)$contentAreaData['colPos'], + 'orderBy' => 'sorting', + ], + ContentSlideMode::tryFrom($contentAreaData['slideMode'] ?? null), + $cObj, + ); + $contentAreaData['records'] = $records; + $contentAreaName = $contentAreaData['identifier']; + $processedData[$targetVariableName][$contentAreaName] = $contentAreaData; + } + return $processedData; + } +} diff --git a/typo3/sysext/frontend/Configuration/Services.yaml b/typo3/sysext/frontend/Configuration/Services.yaml index e2285521172c..ca7c6b0120ff 100644 --- a/typo3/sysext/frontend/Configuration/Services.yaml +++ b/typo3/sysext/frontend/Configuration/Services.yaml @@ -200,3 +200,7 @@ services: TYPO3\CMS\Frontend\DataProcessing\RecordTransformationProcessor: tags: - { name: 'data.processor', identifier: 'record-transformation' } + + TYPO3\CMS\Frontend\DataProcessing\PageContentFetchingProcessor: + tags: + - { name: 'data.processor', identifier: 'page-content' } diff --git a/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Pages/Default.html b/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Pages/Default.html new file mode 100644 index 000000000000..72cae9dc01eb --- /dev/null +++ b/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Pages/Default.html @@ -0,0 +1,26 @@ +<header> + <h1>{page.pageRecord.title}</h1> + <f:for each="{mainContent.stage.records}" as="record"> + <f:render partial="SingleContent" arguments="{record: record}"/> + </f:for> +</header> +<section> + <f:for each="{mainContent.flashInfo.records}" as="record"> + <f:render partial="SingleContent" arguments="{record: record}"/> + </f:for> +</section> +<aside> + <f:for each="{mainContent.aside.records}" as="record"> + <f:render partial="SingleContent" arguments="{record: record}"/> + </f:for> +</aside> +<main> + <f:for each="{mainContent.main.records}" as="record"> + <f:render partial="SingleContent" arguments="{record: record}"/> + </f:for> +</main> +<footer> + <f:for each="{mainContent.footer.records}" as="record"> + <f:render partial="SingleContent" arguments="{record: record}"/> + </f:for> +</footer> diff --git a/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Pages/Home.html b/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Pages/Home.html new file mode 100644 index 000000000000..9c61d9518c04 --- /dev/null +++ b/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Pages/Home.html @@ -0,0 +1,16 @@ +<header> + <h1>{page.pageRecord.title}</h1> + <f:for each="{mainContent.stage.records}" as="record"> + <f:render partial="SingleContent" arguments="{record: record}"/> + </f:for> +</header> +<main> + <f:for each="{mainContent.main.records}" as="record"> + <f:render partial="SingleContent" arguments="{record: record}"/> + </f:for> +</main> +<footer> + <f:for each="{mainContent.footer.records}" as="record"> + <f:render partial="SingleContent" arguments="{record: record}"/> + </f:for> +</footer> diff --git a/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Pages/Productdetail.html b/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Pages/Productdetail.html new file mode 100644 index 000000000000..19d3f3120cb0 --- /dev/null +++ b/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Pages/Productdetail.html @@ -0,0 +1,26 @@ +<header> + <h1>{page.pageRecord.title}</h1> + <f:for each="{mainContent.stage.records}" as="record"> + <f:render partial="SingleContent" arguments="{record: record}"/> + </f:for> +</header> +<section> + <f:for each="{mainContent.flashInfo.records}" as="record"> + <f:render partial="SingleContent" arguments="{record: record}"/> + </f:for> +</section> +<aside> + <f:for each="{mainContent.aside.records}" as="record"> + <f:render partial="SingleContent" arguments="{record: record}"/> + </f:for> +</aside> +<main> + <f:for each="{mainContent.main.records}" as="record"> + <f:render partial="SingleContent" arguments="{record: record}"/> + </f:for> +</main> +<footer><f:spaceless> + <f:for each="{mainContent.footer.records}" as="record"> + <f:render partial="SingleContent" arguments="{record: record}"/> + </f:for> +</f:spaceless></footer> diff --git a/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Partials/SingleContent.html b/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Partials/SingleContent.html new file mode 100644 index 000000000000..3b93ad1a4501 --- /dev/null +++ b/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/Partials/SingleContent.html @@ -0,0 +1,6 @@ +<f:switch expression="{record.recordType}"> + <f:case value="text"> + <h3>{record.header}</h3> + <p>{record.bodytext}</p> + </f:case> +</f:switch> diff --git a/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/setup.typoscript b/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/setup.typoscript new file mode 100644 index 000000000000..67dc237a7799 --- /dev/null +++ b/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/setup.typoscript @@ -0,0 +1,6 @@ +page = PAGE +page.config.disableAllHeaderCode = 1 +page.10 = PAGEVIEW +page.10.paths.10 = EXT:frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/ +page.10.dataProcessing.10 = page-content +page.10.dataProcessing.10.as = mainContent diff --git a/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/setup.typoscript b/typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/RecordTransform/setup.typoscript similarity index 100% rename from typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/setup.typoscript rename to typo3/sysext/frontend/Tests/Functional/DataProcessing/Fixtures/RecordTransform/setup.typoscript diff --git a/typo3/sysext/frontend/Tests/Functional/DataProcessing/PageContentFetchingProcessorTest.php b/typo3/sysext/frontend/Tests/Functional/DataProcessing/PageContentFetchingProcessorTest.php new file mode 100644 index 000000000000..c08dbbc7f9a2 --- /dev/null +++ b/typo3/sysext/frontend/Tests/Functional/DataProcessing/PageContentFetchingProcessorTest.php @@ -0,0 +1,94 @@ +<?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\Frontend\Tests\Functional\DataProcessing; + +use PHPUnit\Framework\Attributes\Test; +use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Localization\LanguageServiceFactory; +use TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerFactory; +use TYPO3\TestingFramework\Core\Functional\Framework\DataHandling\Scenario\DataHandlerWriter; +use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest; +use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase; + +final class PageContentFetchingProcessorTest extends FunctionalTestCase +{ + use SiteBasedTestTrait; + + protected const LANGUAGE_PRESETS = [ + 'EN' => ['id' => 0, 'title' => 'English', 'locale' => 'en-US'], + ]; + + protected function setUp(): void + { + parent::setUp(); + + $this->writeSiteConfiguration( + 'acme-com', + $this->buildSiteConfiguration(1000, 'https://acme.com/'), + [ + $this->buildDefaultLanguageConfiguration('EN', '/'), + ] + ); + + $this->withDatabaseSnapshot(function () { + $this->importCSVDataSet(__DIR__ . '/../Fixtures/be_users.csv'); + $backendUser = $this->setUpBackendUser(1); + $GLOBALS['LANG'] = $this->get(LanguageServiceFactory::class)->createFromUserPreferences($backendUser); + $scenarioFile = __DIR__ . '/Fixtures/ContentScenario.yaml'; + $factory = DataHandlerFactory::fromYamlFile($scenarioFile); + $writer = DataHandlerWriter::withBackendUser($backendUser); + $writer->invokeFactory($factory); + self::failIfArrayIsNotEmpty($writer->getErrors()); + $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('pages'); + + $pageLayoutFileContents[] = file_get_contents(__DIR__ . '/Fixtures/PageLayouts/Default.tsconfig'); + $pageLayoutFileContents[] = file_get_contents(__DIR__ . '/Fixtures/PageLayouts/Home.tsconfig'); + $pageLayoutFileContents[] = file_get_contents(__DIR__ . '/Fixtures/PageLayouts/Productdetail.tsconfig'); + + $connection->update( + 'pages', + ['TSconfig' => implode(chr(10), $pageLayoutFileContents)], + ['uid' => 1000] + ); + $this->setUpFrontendRootPage(1000, ['EXT:frontend/Tests/Functional/DataProcessing/Fixtures/PageContentProcessor/setup.typoscript'], ['title' => 'ACME Guitars']); + }); + } + + #[Test] + public function homeLayoutIsRendered(): void + { + $response = $this->executeFrontendSubRequest((new InternalRequest('https://acme.com/'))->withPageId(1000)); + $body = (string)$response->getBody(); + self::assertStringContainsString('Welcome to ACME guitars', $body); + self::assertStringContainsString('Great to see you here', $body); + self::assertStringContainsString('If you read this you are at the end.', $body); + } + + #[Test] + public function productDetailLayoutIsRendered(): void + { + $response = $this->executeFrontendSubRequest((new InternalRequest('https://acme.com/'))->withPageId(1110)); + $body = (string)$response->getBody(); + self::assertStringContainsString('Hero is our flagship', $body); + self::assertStringContainsString('Get a hero for yourself', $body); + self::assertStringContainsString('Flash Info for all products', $body); + self::assertStringContainsString('If you read this you are at the end.', $body); + } +} diff --git a/typo3/sysext/frontend/Tests/Functional/DataProcessing/RecordTransformationProcessorTest.php b/typo3/sysext/frontend/Tests/Functional/DataProcessing/RecordTransformationProcessorTest.php index a0c9cff1983b..7992e93b29b9 100644 --- a/typo3/sysext/frontend/Tests/Functional/DataProcessing/RecordTransformationProcessorTest.php +++ b/typo3/sysext/frontend/Tests/Functional/DataProcessing/RecordTransformationProcessorTest.php @@ -67,7 +67,7 @@ final class RecordTransformationProcessorTest extends FunctionalTestCase ['TSconfig' => implode(chr(10), $pageLayoutFileContents)], ['uid' => 1000] ); - $this->setUpFrontendRootPage(1000, ['EXT:frontend/Tests/Functional/DataProcessing/Fixtures/setup.typoscript'], ['title' => 'ACME Guitars']); + $this->setUpFrontendRootPage(1000, ['EXT:frontend/Tests/Functional/DataProcessing/Fixtures/RecordTransform/setup.typoscript'], ['title' => 'ACME Guitars']); }); } -- GitLab