diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Controller/ContentController.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Controller/ContentController.php new file mode 100644 index 0000000000000000000000000000000000000000..ca979dff707a45318cc72626965fc47fa4389580 --- /dev/null +++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Controller/ContentController.php @@ -0,0 +1,116 @@ +<?php +declare(strict_types=1); + +namespace ExtbaseTeam\BlogExample\Controller; + +/* + * 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! + */ + +/** + * ContentController + */ +class ContentController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController +{ + /** + * @inject + * @var \ExtbaseTeam\BlogExample\Domain\Repository\TtContentRepository + */ + protected $contentRepository; + + /** + * @var string + */ + protected $defaultViewObjectName = \TYPO3\CMS\Extbase\Mvc\View\JsonView::class; + + /** + * @inject + * @var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapFactory + */ + protected $dataMapFactory; + + /** + * @return array + */ + public function listAction() + { + $content = $this->contentRepository->findAll(); + $value[$this->getRuntimeIdentifier()] = $this->getStructure($content); + + $this->view->assign('value', $value); + } + + /** + * @param \TYPO3\CMS\Extbase\Mvc\RequestInterface $request + * @param \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response + * @throws \RuntimeException + */ + public function processRequest(\TYPO3\CMS\Extbase\Mvc\RequestInterface $request, \TYPO3\CMS\Extbase\Mvc\ResponseInterface $response) + { + try { + parent::processRequest($request, $response); + } catch (\TYPO3\CMS\Extbase\Property\Exception $exception) { + throw new \RuntimeException( + $this->getRuntimeIdentifier() . ': ' . $exception->getMessage() . ' (' . $exception->getCode() . ')', + 1476122223 + ); + } + } + + /** + * @param \Iterator|\TYPO3\CMS\Extbase\DomainObject\AbstractEntity[] $iterator + * @return array + */ + protected function getStructure($iterator) + { + $structure = []; + + if (!$iterator instanceof \Iterator) { + $iterator = [$iterator]; + } + + foreach ($iterator as $entity) { + $dataMap = $this->dataMapFactory->buildDataMap(get_class($entity)); + $tableName = $dataMap->getTableName(); + $identifier = $tableName . ':' . $entity->getUid(); + $properties = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getGettableProperties($entity); + + $structureItem = []; + foreach ($properties as $propertyName => $propertyValue) { + $columnMap = $dataMap->getColumnMap($propertyName); + if ($columnMap !== null) { + $propertyName = $columnMap->getColumnName(); + } + if ($propertyValue instanceof \Iterator) { + $structureItem[$propertyName] = $this->getStructure($propertyValue); + } else { + $structureItem[$propertyName] = $propertyValue; + } + } + $structure[$identifier] = $structureItem; + } + + return $structure; + } + + /** + * @return string + */ + protected function getRuntimeIdentifier() + { + $arguments = []; + foreach ($this->request->getArguments() as $argumentName => $argumentValue) { + $arguments[] = $argumentName . '=' . $argumentValue; + } + return $this->request->getControllerActionName() . '(' . implode(', ', $arguments) . ')'; + } +} diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/TtContent.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/TtContent.php new file mode 100644 index 0000000000000000000000000000000000000000..4cf57c77ca1c616e5e6a28a0b66930de9b7fabe5 --- /dev/null +++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Model/TtContent.php @@ -0,0 +1,124 @@ +<?php +declare(strict_types=1); + +namespace ExtbaseTeam\BlogExample\Domain\Model; + +/* + * 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! + */ + +/** + * A tt_content model + */ +class TtContent extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity +{ + /** + * uid + * + * @var string + */ + protected $uid = ''; + + /** + * pid + * + * @var string + */ + protected $pid = ''; + + /** + * @var string + */ + protected $header; + + /** + * Images + * + * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> + * @lazy + */ + protected $image; + + /** + * Constructs this post + */ + public function __construct() + { + $this->image = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); + } + + /** + * Gets the uid + * + * @return string $uid + */ + public function getUid() + { + return $this->uid; + } + + /** + * Gets the pid + * + * @return string $pid + */ + public function getPid() + { + return $this->pid; + } + + /** + * Returns the header + * + * @return string $header + */ + public function getHeader() + { + return $this->header; + } + + /** + * Sets the header + * + * @param string $header + */ + public function setHeader($header) + { + $this->header = $header; + } + + /** + * @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage + */ + public function getImage(): \TYPO3\CMS\Extbase\Persistence\ObjectStorage + { + return $this->image; + } + + /** + * @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $image + */ + public function setImage(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $image) + { + $this->image = $image; + } + + /** + * Returns this as a formatted string + * + * @return string + */ + public function __toString() + { + return $this->getHeader(); + } +} diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/TtContentRepository.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/TtContentRepository.php new file mode 100644 index 0000000000000000000000000000000000000000..a7f6e34f9b81f26aaab1ba3cb815779a3bce43cc --- /dev/null +++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Classes/Domain/Repository/TtContentRepository.php @@ -0,0 +1,26 @@ +<?php +declare(strict_types=1); + +namespace ExtbaseTeam\BlogExample\Domain\Repository; + +/* + * 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! + */ + +use TYPO3\CMS\Extbase\Persistence\QueryInterface; + +/** + * A repository for tt_contents + */ +class TtContentRepository extends \TYPO3\CMS\Extbase\Persistence\Repository +{ +} diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_localconf.php b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_localconf.php index 05cff596c8ef828b1711e0d82f22eb53b41abadc..cf248f0e183d3d8a44a27fa1653c52c1badc9ef3 100644 --- a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_localconf.php +++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_localconf.php @@ -8,3 +8,10 @@ defined('TYPO3_MODE') or die(); ], [] ); +\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( + 'ExtbaseTeam.' . $_EXTKEY, 'Content', + [ + 'Content' => 'list', + ], + [] +); diff --git a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_typoscript_setup.txt b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_typoscript_setup.txt index c3f0d3a06deba6d117207d44ccc13a80c64b384f..05a80663cb43d8d6f6658a44b89abd36519fb26f 100644 --- a/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_typoscript_setup.txt +++ b/typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/ext_typoscript_setup.txt @@ -14,6 +14,16 @@ config.tx_extbase { recordType = ExtbaseTeam\BlogExample\Domain\Model\Administrator } } + ExtbaseTeam\BlogExample\Domain\Model\TtContent { + mapping { + tableName = tt_content + columns { + uid.mapOnProperty = uid + pid.mapOnProperty = pid + header.mapOnProperty = header + } + } + } } } } \ No newline at end of file diff --git a/typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/Frontend/ContentJsonRenderer.ts b/typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/Frontend/ContentJsonRenderer.ts new file mode 100644 index 0000000000000000000000000000000000000000..d6f57e6cf710e0653d7946e7381e0e39c471db2e --- /dev/null +++ b/typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/Frontend/ContentJsonRenderer.ts @@ -0,0 +1,44 @@ +config { + no_cache = 1 + debug = 0 + xhtml_cleaning = 0 + admPanel = 0 + disableAllHeaderCode = 1 + sendCacheHeaders = 0 + sys_language_uid = 0 + additionalHeaders = Content-Type: application/json; charset=utf-8 +} + +plugin.tx_blogexample { + persistence { + storagePid = 89 + } +} + +page = PAGE +page { + 10 = COA + 10 { + 10 = USER + 10 { + userFunc = TYPO3\CMS\Extbase\Core\Bootstrap->run + extensionName = BlogExample + pluginName = Content + vendorName = ExtbaseTeam + } + stdWrap.postUserFunc = TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Renderer->parseValues + stdWrap.postUserFunc.as = Extbase + } + + stdWrap.postUserFunc = TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Renderer->renderSections +} + +[globalVar = GP:L = 1] + config.sys_language_uid = 1 +[end] +[globalVar = GP:L = 2] + config.sys_language_uid = 2 +[end] +[globalVar = GP:L = 3] + config.sys_language_uid = 3 +[end] diff --git a/typo3/sysext/extbase/Tests/Functional/Persistence/TranslatedContentTest.php b/typo3/sysext/extbase/Tests/Functional/Persistence/TranslatedContentTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7c3f8524c37a1712e104e11b34d2c5a5a874ebf5 --- /dev/null +++ b/typo3/sysext/extbase/Tests/Functional/Persistence/TranslatedContentTest.php @@ -0,0 +1,595 @@ +<?php +declare(strict_types=1); + +namespace TYPO3\CMS\Extbase\Tests\Functional\Persistence; + +/* + * 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! + */ + +use TYPO3\CMS\Core\Database\ConnectionPool; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Response; + +/** + * This test is an Extbase version of the \TYPO3\CMS\Frontend\Tests\Functional\Rendering\LocalizedContentRenderingTest + * scenarios are the same, just a way of fetching content is different + * + * This test documents current behaviour of extbase which is inconsistent with TypoScript rendering of tt_content. + */ +class TranslatedContentTest extends \TYPO3\CMS\Core\Tests\Functional\DataHandling\AbstractDataHandlerActionTestCase +{ + const VALUE_PageId = 89; + const TABLE_Content = 'tt_content'; + const TABLE_Pages = 'pages'; + + /** + * @var string + */ + protected $scenarioDataSetDirectory = 'typo3/sysext/frontend/Tests/Functional/Rendering/DataSet/'; + + /** + * @var array + */ + protected $testExtensionsToLoad = ['typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example']; + + /** + * @var array + */ + protected $coreExtensionsToLoad = ['extbase', 'fluid']; + + /** + * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface The object manager + */ + protected $objectManager; + + /** + * @var \ExtbaseTeam\BlogExample\Domain\Repository\TtContentRepository + */ + protected $contentRepository; + + /** + * Custom 404 handler returning valid json is registered so the $this->getFrontendResponse() + * does not fail on 404 pages + * + * @var array + */ + protected $configurationToUseInTestInstance = [ + 'FE' => [ + 'pageNotFound_handling' => 'READFILE:typo3/sysext/frontend/Tests/Functional/Rendering/DataSet/404Template.html' + ] + ]; + + protected function setUp() + { + parent::setUp(); + $this->importScenarioDataSet('LiveDefaultPages'); + $this->importScenarioDataSet('LiveDefaultElements'); + + $this->backendUser->workspace = 0; + $this->objectManager = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class); + $this->contentRepository = $this->objectManager->get(\ExtbaseTeam\BlogExample\Domain\Repository\TtContentRepository::class); + $this->setUpFrontendRootPage(1, [ + 'typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example/Configuration/TypoScript/setup.txt', + 'typo3/sysext/extbase/Tests/Functional/Persistence/Fixtures/Frontend/ContentJsonRenderer.ts' + + ]); + } + + public function defaultLanguageConfigurationDataProvider(): array + { + return [ + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode =', + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = content_fallback', + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = content_fallback;1,0', + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = strict', + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = ignore', + ], + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode =', + ], + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = content_fallback', + ], + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = content_fallback;1,0', + ], + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = strict', + ], + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = ignore', + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode =', + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = content_fallback', + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = content_fallback;1,0', + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = strict', + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = ignore', + ], + ]; + } + + /** + * For the default language all combination of language settings should give the same result, + * regardless of TypoScript settings, if the requested language is "0" then no TypoScript settings apply. + * + * @test + * @dataProvider defaultLanguageConfigurationDataProvider + * + * @param string $typoScript + */ + public function onlyEnglishContentIsRenderedForDefaultLanguage(string $typoScript) + { + $this->addTypoScriptToTemplateRecord(1, $typoScript); + + $frontendResponse = $this->getFrontendResponse(self::VALUE_PageId, 0); + $responseSections = $frontendResponse->getResponseSections('Extbase:list()'); + $visibleHeaders = ['Regular Element #1', 'Regular Element #2', 'Regular Element #3']; + $this->assertThat($responseSections, $this->getRequestSectionHasRecordConstraint() + ->setTable(self::TABLE_Content) + ->setField('header') + ->setValues(...$visibleHeaders) + ); + $this->assertThat($responseSections, $this->getRequestSectionDoesNotHaveRecordConstraint() + ->setTable(self::TABLE_Content) + ->setField('header') + ->setValues(...$this->getNonVisibleHeaders($visibleHeaders)) + ); + } + + /** + * Dutch language has pages_language_overlay record and some content elements are translated + * + * @return array + */ + public function dutchDataProvider(): array + { + //Expected behaviour: + //Page is translated to Dutch, so changing sys_language_mode does NOT change the results + //Page title is always [DK]Page, and both sys_language_content and sys_language_uid are always 1 + return [ + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode =', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', 'Regular Element #2', '[DK] UnHidden Element #4'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = content_fallback', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', 'Regular Element #2', '[DK] UnHidden Element #4'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = content_fallback;1,0', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', 'Regular Element #2', '[DK] UnHidden Element #4'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = strict', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = ignore', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', 'Regular Element #2', '[DK] UnHidden Element #4'], + ], + 5 => [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode =', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'], + ], +// Expected behaviour: +// Not translated element #2 is shown because sys_language_overlay = 1 (with sys_language_overlay = hideNonTranslated, it would be hidden) + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = content_fallback', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'], + ], +// Expected behaviour: +// Same as config.sys_language_mode = content_fallback because we're requesting language 1, so no additional fallback possible + + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = content_fallback;1,0', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = strict', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = ignore', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'], + ], +// Expected behaviour: +// Non translated default language elements are not shown, because of hideNonTranslated + 10 => [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode =', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = content_fallback', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = content_fallback;1,0', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'], + ], +// Setting sys_language_mode = strict has the same effect as previous data sets, because the translation of the page exists + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = strict', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = ignore', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'], + ], + ]; + } + + /** + * @test + * @dataProvider dutchDataProvider + * + * @param string $typoScript + * @param array $visibleHeaders + */ + public function renderingOfDutchLanguage(string $typoScript, array $visibleHeaders) + { + $this->addTypoScriptToTemplateRecord(1, $typoScript); + $frontendResponse = $this->getFrontendResponse(self::VALUE_PageId, 1); + $responseSections = $frontendResponse->getResponseSections('Extbase:list()'); + $this->assertThat($responseSections, $this->getRequestSectionHasRecordConstraint() + ->setTable(self::TABLE_Content) + ->setField('header') + ->setValues(...$visibleHeaders) + ); + $this->assertThat($responseSections, $this->getRequestSectionDoesNotHaveRecordConstraint() + ->setTable(self::TABLE_Content) + ->setField('header') + ->setValues(...$this->getNonVisibleHeaders($visibleHeaders)) + ); + } + + public function contentOnNonTranslatedPageDataProvider(): array + { + //Expected behaviour: + //the page is NOT translated so setting sys_language_mode to different values changes the results + //- setting sys_language_mode to empty value makes TYPO3 return default language records + //- setting it to strict throws 404, independently from other settings + //Setting config.sys_language_overlay = 0 + return [ + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode =', + 'visibleRecordHeaders' => ['Regular Element #1', 'Regular Element #2', 'Regular Element #3'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = content_fallback', + 'visibleRecordHeaders' => ['Regular Element #1', 'Regular Element #2', 'Regular Element #3'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = content_fallback;1,0', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] UnHidden Element #4', '[DK] Without default language'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = strict', + 'visibleRecordHeaders' => [], + 'status' => 404, + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = ignore', + 'visibleRecordHeaders' => ['[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1', 'Regular Element #2', 'Regular Element #3', '[DE] Without default language'], + ], + 5 => [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode =', + 'visibleRecordHeaders' => ['Regular Element #1', 'Regular Element #2', 'Regular Element #3'], + ], + //falling back to default language + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = content_fallback', + 'visibleRecordHeaders' => ['Regular Element #1', 'Regular Element #2', 'Regular Element #3'], + ], + //Dutch elements are shown because of the content fallback 1,0 - first Dutch, then default language + //note that '[DK] Without default language' is NOT shown - due to overlays (fetch default language and overlay it with translations) + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = content_fallback;1,0', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', 'Regular Element #2', '[Translate to Dansk:] Regular Element #3', '[DK] Without default language', '[DK] UnHidden Element #4'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = strict', + 'visibleRecordHeaders' => [], + 'status' => 404 + ], + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = ignore', + 'visibleRecordHeaders' => ['[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1', 'Regular Element #2', 'Regular Element #3', '[DE] Without default language'], + ], + 10 => [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode =', + 'visibleRecordHeaders' => ['Regular Element #1', 'Regular Element #2', 'Regular Element #3'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = content_fallback', + 'visibleRecordHeaders' => ['Regular Element #1', 'Regular Element #2', 'Regular Element #3'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = content_fallback;1,0', + 'visibleRecordHeaders' => ['[Translate to Dansk:] Regular Element #1', '[Translate to Dansk:] Regular Element #3', 'Regular Element #2', '[DK] Without default language', '[DK] UnHidden Element #4'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = strict', + 'visibleRecordHeaders' => [], + 'status' => 404, + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = ignore', + 'visibleRecordHeaders' => ['[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1', 'Regular Element #2', 'Regular Element #3', '[DE] Without default language'], + ], + ]; + } + + /** + * Page uid 89 is NOT translated to german + * + * @test + * @dataProvider contentOnNonTranslatedPageDataProvider + * + * @param string $typoScript + * @param array $visibleHeaders + * @param string $status 'success' or 404 + */ + public function contentOnNonTranslatedPageGerman(string $typoScript, array $visibleHeaders, string $status='success') + { + $this->addTypoScriptToTemplateRecord(1, $typoScript); + + $frontendResponse = $this->getFrontendResponse(self::VALUE_PageId, 2); + if ($status === Response::STATUS_Success) { + $responseSections = $frontendResponse->getResponseSections('Extbase:list()'); + $this->assertThat($responseSections, $this->getRequestSectionHasRecordConstraint() + ->setTable(self::TABLE_Content) + ->setField('header') + ->setValues(...$visibleHeaders) + ); + $this->assertThat($responseSections, $this->getRequestSectionDoesNotHaveRecordConstraint() + ->setTable(self::TABLE_Content) + ->setField('header') + ->setValues(...$this->getNonVisibleHeaders($visibleHeaders)) + ); + } + //some configuration combinations results in 404, in that case status will be set to 404 + $this->assertEquals($status, $frontendResponse->getStatus()); + } + + public function contentOnPartiallyTranslatedPageDataProvider(): array + { + + //Expected behaviour: + //Setting sys_language_mode to different values doesn't influence the result as the requested page is translated to Polish, + //Page title is always [PL]Page, and both sys_language_content and sys_language_uid are always 3 + return [ + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode =', + 'visibleRecordHeaders' => ['Regular Element #2', 'Regular Element #3', '[Translate to Polski:] Regular Element #1', '[PL] Without default language'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = content_fallback', + 'visibleRecordHeaders' => ['Regular Element #2', 'Regular Element #3', '[Translate to Polski:] Regular Element #1', '[PL] Without default language'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = content_fallback;1,0', + 'visibleRecordHeaders' => ['Regular Element #2', 'Regular Element #3', '[Translate to Polski:] Regular Element #1', '[PL] Without default language'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = strict', + 'visibleRecordHeaders' => ['[Translate to Polski:] Regular Element #1', '[PL] Without default language'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 0 + config.sys_language_mode = ignore', + 'visibleRecordHeaders' => ['Regular Element #2', 'Regular Element #3', '[Translate to Polski:] Regular Element #1', '[PL] Without default language'], + ], + 5 => [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode =', + 'visibleRecordHeaders' => ['[PL] Without default language', '[Translate to Polski:] Regular Element #1', 'Regular Element #2', 'Regular Element #3'], + ], + // Expected behaviour: + // Not translated element #2 is shown because sys_language_overlay = 1 (with sys_language_overlay = hideNonTranslated, it would be hidden) + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = content_fallback', + 'visibleRecordHeaders' => ['[PL] Without default language', '[Translate to Polski:] Regular Element #1', 'Regular Element #2', 'Regular Element #3'], + ], +// Expected behaviour: +// Element #3 is not translated in PL and it is translated in DK. It's not shown as content_fallback is not related to single CE level +// but on page level - and this page is translated to Polish, so no fallback is happening + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = content_fallback;1,0', + 'visibleRecordHeaders' => ['[PL] Without default language', '[Translate to Polski:] Regular Element #1', 'Regular Element #2', 'Regular Element #3'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = strict', + 'visibleRecordHeaders' => ['[PL] Without default language', '[Translate to Polski:] Regular Element #1'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = 1 + config.sys_language_mode = ignore', + 'visibleRecordHeaders' => ['[PL] Without default language', '[Translate to Polski:] Regular Element #1', 'Regular Element #2', 'Regular Element #3'], + ], + // Expected behaviour: + // Non translated default language elements are not shown, because of hideNonTranslated + 10 => [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode =', + 'visibleRecordHeaders' => ['[PL] Without default language', 'Regular Element #2', 'Regular Element #3', '[Translate to Polski:] Regular Element #1'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = content_fallback', + 'visibleRecordHeaders' => ['[PL] Without default language', 'Regular Element #2', 'Regular Element #3', '[Translate to Polski:] Regular Element #1'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = content_fallback;1,0', + 'visibleRecordHeaders' => ['[PL] Without default language', 'Regular Element #2', 'Regular Element #3', '[Translate to Polski:] Regular Element #1'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = strict', + 'visibleRecordHeaders' => ['[PL] Without default language', '[Translate to Polski:] Regular Element #1'], + ], + [ + 'typoScript' => 'config.sys_language_overlay = hideNonTranslated + config.sys_language_mode = ignore', + 'visibleRecordHeaders' => ['[PL] Without default language', 'Regular Element #2', 'Regular Element #3', '[Translate to Polski:] Regular Element #1'], + ] + ]; + } + + /** + * Page uid 89 is translated to to Polish, but not all CE are translated + * + * @test + * @dataProvider contentOnPartiallyTranslatedPageDataProvider + * + * @param string $typoScript + * @param array $visibleHeaders + */ + public function contentOnPartiallyTranslatedPage(string $typoScript, array $visibleHeaders) + { + $this->addTypoScriptToTemplateRecord(1, $typoScript); + + $frontendResponse = $this->getFrontendResponse(self::VALUE_PageId, 3); + $this->assertEquals('success', $frontendResponse->getStatus()); + $responseSections = $frontendResponse->getResponseSections('Extbase:list()'); + + $this->assertThat($responseSections, $this->getRequestSectionHasRecordConstraint() + ->setTable(self::TABLE_Content) + ->setField('header') + ->setValues(...$visibleHeaders) + ); + $this->assertThat($responseSections, $this->getRequestSectionDoesNotHaveRecordConstraint() + ->setTable(self::TABLE_Content) + ->setField('header') + ->setValues(...$this->getNonVisibleHeaders($visibleHeaders)) + ); + } + + /** + * Helper function to ease asserting that rest of the data set is not visible + * + * @param array $visibleHeaders + * @return array + */ + protected function getNonVisibleHeaders(array $visibleHeaders): array + { + $allElements = [ + 'Regular Element #1', + 'Regular Element #2', + 'Regular Element #3', + 'Hidden Element #4', + '[Translate to Dansk:] Regular Element #1', + '[Translate to Dansk:] Regular Element #3', + '[DK] Without default language', + '[DK] UnHidden Element #4', + '[DE] Without default language', + '[Translate to Deutsch:] [Translate to Dansk:] Regular Element #1', + '[Translate to Polski:] Regular Element #1', + '[PL] Without default language', + '[PL] Hidden Regular Element #2' + ]; + return array_diff($allElements, $visibleHeaders); + } + + /** + * Adds TypoScript setup snippet to the existing template record + * + * @param int $pageId + * @param string $typoScript + */ + protected function addTypoScriptToTemplateRecord(int $pageId, string $typoScript) + { + $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('sys_template'); + + $template = $connection->select(['*'], 'sys_template', ['pid' => $pageId, 'root' => 1])->fetch(); + if (empty($template)) { + $this->fail('Cannot find root template on page with id: "' . $pageId . '"'); + } + $updateFields['config'] = $template['config'] . LF . $typoScript; + $connection->update( + 'sys_template', + $updateFields, + ['uid' => $template['uid']] + ); + } +}