diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26698323..f33f5ec3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,10 +47,6 @@ jobs: - name: Acceptance Tests run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -t ${{ matrix.TYPO3 }} -s acceptance -- --fail-fast - if: matrix.TYPO3 == '13' - - name: Acceptance Tests 14 - run: Build/Scripts/runTests.sh -p ${{ matrix.php }} -t ${{ matrix.TYPO3 }} -s acceptance -- --fail-fast --skip-group=content_defender - if: matrix.TYPO3 != '13' - name: Archive acceptance tests results uses: actions/upload-artifact@v4 if: always() diff --git a/Build/phpstan13.neon b/Build/phpstan13.neon index e254f305..c07c5454 100644 --- a/Build/phpstan13.neon +++ b/Build/phpstan13.neon @@ -10,4 +10,6 @@ parameters: excludePaths: - %currentWorkingDirectory%/Classes/Listener/PageContentPreviewRendering.php + - %currentWorkingDirectory%/Classes/Listener/ManipulateBackendLayoutColPosConfigurationForPage.php + - %currentWorkingDirectory%/Classes/Hooks/Datahandler/ContentElementRestriction diff --git a/Classes/Hooks/Datahandler/CommandMapPostProcessingHook.php b/Classes/Hooks/Datahandler/CommandMapPostProcessingHook.php index b4d8c418..b4e80719 100644 --- a/Classes/Hooks/Datahandler/CommandMapPostProcessingHook.php +++ b/Classes/Hooks/Datahandler/CommandMapPostProcessingHook.php @@ -118,6 +118,7 @@ protected function copyOrMoveChildren(int $origUid, int $newId, int $containerId // when moving or copy a container into other language the other language is returned $container = $this->containerFactory->buildContainer($origUid); (GeneralUtility::makeInstance(DatahandlerProcess::class))->startContainerProcess($origUid); + (GeneralUtility::makeInstance(DatahandlerProcess::class))->lockContentElementRestrictions(); $children = []; $colPosVals = $container->getChildrenColPos(); foreach ($colPosVals as $colPos) { @@ -170,6 +171,7 @@ protected function copyOrMoveChildren(int $origUid, int $newId, int $containerId } } (GeneralUtility::makeInstance(DatahandlerProcess::class))->endContainerProcess($origUid); + (GeneralUtility::makeInstance(DatahandlerProcess::class))->unlockContentElementRestrictions(); } catch (Exception $e) { // nothing todo } diff --git a/Classes/Hooks/Datahandler/ContentElementRestriction/DataHandlerHook.php b/Classes/Hooks/Datahandler/ContentElementRestriction/DataHandlerHook.php new file mode 100644 index 00000000..13cdac75 --- /dev/null +++ b/Classes/Hooks/Datahandler/ContentElementRestriction/DataHandlerHook.php @@ -0,0 +1,222 @@ +cmdmap; + if (isset($cmdmap['pages'])) { + $this->lockDatamapHook = true; + } + if (empty($cmdmap['tt_content']) || $dataHandler->bypassAccessCheckForRecords) { + return; + } + $this->lockDatamapHook = true; + if ($this->datahandlerProcess->areContentElementRestrictionsLooked()) { + return; + } + foreach ($cmdmap['tt_content'] as $id => $incomingFieldArray) { + foreach ($incomingFieldArray as $command => $value) { + if (!in_array($command, ['copy', 'move'], true)) { + continue; + } + $currentRecord = BackendUtility::getRecord('tt_content', $id); + + // EXT:container start + if ( + (!empty($value['update'])) && + isset($value['update']['colPos']) && + $value['update']['colPos'] > 0 && + isset($value['update']['tx_container_parent']) && + $value['update']['tx_container_parent'] > 0 && + MathUtility::canBeInterpretedAsInteger($id) + ) { + $colPos = (int)$value['update']['colPos']; + if (!empty($currentRecord['CType'])) { + if ($this->checkContainerCType((int)$value['update']['tx_container_parent'], $currentRecord['CType'], (int)$value['update']['colPos']) === false) { + // Not allowed to move or copy to target. Unset this command and create a log entry which may be turned into a notification when called by BE. + unset($dataHandler->cmdmap['tt_content'][$id]); + $dataHandler->log('tt_content', $id, 1, null, 1, 'The command "%s" for record "tt_content:%s" with CType "%s" to colPos "%s" couldn\'t be executed due to disallowed value(s).', null, [$command, $id, $currentRecord['CType'], $colPos]); + } + } + $useChildId = null; + if ($command === 'move') { + $useChildId = $id; + } + if ($this->checkContainerMaxItems((int)$value['update']['tx_container_parent'], (int)$value['update']['colPos'], $useChildId)) { + unset($dataHandler->cmdmap['tt_content'][$id]); + $dataHandler->log('tt_content', $id, 1, null, 1, 'The command "%s" for record "tt_content:%s" to colPos "%s" couldn\'t be executed due to maxitems reached.', null, [$command, $id, $colPos]); + } + return; + } + // EXT:container end + + if (empty($currentRecord['CType'] ?? '')) { + continue; + } + if (is_array($value) && !empty($value['action']) && $value['action'] === 'paste' && isset($value['update']['colPos'])) { + // Moving / pasting to a new colPos on a potentially different page + $pageId = (int)$value['target']; + $colPos = (int)$value['update']['colPos']; + } else { + $pageId = (int)$value; + $colPos = (int)$currentRecord['colPos']; + } + if ($pageId < 0) { + $targetRecord = BackendUtility::getRecord('tt_content', abs($pageId)); + $pageId = (int)$targetRecord['pid']; + $colPos = (int)$targetRecord['colPos']; + } + + $backendLayout = $this->backendLayoutView->getBackendLayoutForPage($pageId); + $columnConfiguration = $this->backendLayoutView->getColPosConfigurationForPage($backendLayout, $colPos, $pageId); + $allowedContentElementsInTargetColPos = GeneralUtility::trimExplode(',', $columnConfiguration['allowedContentTypes'] ?? '', true); + $disallowedContentElementsInTargetColPos = GeneralUtility::trimExplode(',', $columnConfiguration['disallowedContentTypes'] ?? '', true); + if ((!empty($allowedContentElementsInTargetColPos) && !in_array($currentRecord['CType'], $allowedContentElementsInTargetColPos, true)) + || (!empty($disallowedContentElementsInTargetColPos) && in_array($currentRecord['CType'], $disallowedContentElementsInTargetColPos, true)) + ) { + // Not allowed to move or copy to target. Unset this command and create a log entry which may be turned into a notification when called by BE. + unset($dataHandler->cmdmap['tt_content'][$id]); + $dataHandler->log('tt_content', $id, 1, null, 1, 'The command "%s" for record "tt_content:%s" with CType "%s" to colPos "%s" couldn\'t be executed due to disallowed value(s).', null, [$command, $id, $currentRecord['CType'], $colPos]); + } + } + } + } + + protected function checkContainerMaxItems(int $containerId, int $colPos, ?int $childUid = null): bool + { + try { + $container = $this->containerFactory->buildContainer($containerId); + $columnConfiguration = $this->registry->getContentDefenderConfiguration($container->getCType(), $colPos); + if (($columnConfiguration['maxitems'] ?? 0) === 0) { + return false; + } + $childrenOfColumn = $container->getChildrenByColPos($colPos); + $count = count($childrenOfColumn); + if ($childUid !== null && $container->hasChildInColPos($colPos, $childUid)) { + $count--; + } + return $count >= $columnConfiguration['maxitems']; + } catch (Exception) { + // not a container; + } + return false; + } + + protected function checkContainerCType(int $containerId, string $cType, int $colPos): bool + { + try { + $container = $this->containerFactory->buildContainer($containerId); + $columnConfiguration = $this->registry->getContentDefenderConfiguration($container->getCType(), $colPos); + $allowedContentElementsInTargetColPos = GeneralUtility::trimExplode(',', $columnConfiguration['allowedContentTypes'] ?? '', true); + $disallowedContentElementsInTargetColPos = GeneralUtility::trimExplode(',', $columnConfiguration['disallowedContentTypes'] ?? '', true); + if ((!empty($allowedContentElementsInTargetColPos) && !in_array($cType, $allowedContentElementsInTargetColPos, true)) + || (!empty($disallowedContentElementsInTargetColPos) && in_array($cType, $disallowedContentElementsInTargetColPos, true)) + ) { + return false; + } + } catch (Exception) { + // not a container; + } + return true; + } + + public function processCmdmap_postProcess(string $command, string $table, $id, $value, DataHandler $dataHandler, $pasteUpdate, $pasteDatamap): void + { + $this->lockDatamapHook = false; + } + + public function processDatamap_beforeStart(DataHandler $dataHandler): void + { + if ($this->lockDatamapHook === true) { + return; + } + $datamap = $dataHandler->datamap; + if (empty($datamap['tt_content']) || $dataHandler->bypassAccessCheckForRecords) { + return; + } + foreach ($datamap['tt_content'] as $id => $incomingFieldArray) { + if (MathUtility::canBeInterpretedAsInteger($id)) { + $record = BackendUtility::getRecord('tt_content', $id); + if (!is_array($record)) { + // Skip this if the record could not be determined for whatever reason + continue; + } + $recordData = array_merge($record, $incomingFieldArray); + } else { + $recordData = array_merge($dataHandler->defaultValues['tt_content'] ?? [], $incomingFieldArray); + } + // EXT:container start + if ((int)($recordData['tx_container_parent'] ?? 0) > 0 && (int)($recordData['colPos'] ?? 0) > 0) { + if ($this->checkContainerMaxItems((int)$recordData['tx_container_parent'], (int)$recordData['colPos'])) { + if (MathUtility::canBeInterpretedAsInteger($id)) { + // edit + continue; + } + unset($dataHandler->datamap['tt_content'][$id]); + $dataHandler->log('tt_content', $id, 1, null, 1, 'The command "%s" for record "tt_content:%s" to colPos "%s" couldn\'t be executed due to maxitems reached.', null, [$id, $recordData['colPos']]); + } + } + // EXT:container end + if (empty($recordData['CType']) || !array_key_exists('colPos', $recordData)) { + // No idea what happened here, but we stop with this record if there is no CType or colPos + continue; + } + $pageId = (int)$recordData['pid']; + if ($pageId < 0) { + $previousRecord = BackendUtility::getRecord('tt_content', abs($pageId), 'pid'); + if ($previousRecord === null) { + // Broken target data. Stop here and let DH handle this mess. + continue; + } + $pageId = (int)$previousRecord['pid']; + } + $colPos = (int)$recordData['colPos']; + $backendLayout = $this->backendLayoutView->getBackendLayoutForPage($pageId); + $columnConfiguration = $this->backendLayoutView->getColPosConfigurationForPage($backendLayout, $colPos, $pageId); + $allowedContentElementsInTargetColPos = GeneralUtility::trimExplode(',', $columnConfiguration['allowedContentTypes'] ?? '', true); + $disallowedContentElementsInTargetColPos = GeneralUtility::trimExplode(',', $columnConfiguration['disallowedContentTypes'] ?? '', true); + if ((!empty($allowedContentElementsInTargetColPos) && !in_array($recordData['CType'], $allowedContentElementsInTargetColPos, true)) + || (!empty($disallowedContentElementsInTargetColPos) && in_array($recordData['CType'], $disallowedContentElementsInTargetColPos, true)) + ) { + // Not allowed to create in this colPos on this page. Unset this command and create a log entry which may be turned into a notification when called by BE. + unset($dataHandler->datamap['tt_content'][$id]); + $dataHandler->log('tt_content', $id, 1, null, 1, 'The record "tt_content:%s" with CType "%s" in colPos "%s" couldn\'t be saved due to disallowed value(s).', null, [$id, $recordData['CType'], $colPos]); + } + } + } +} diff --git a/Classes/Hooks/Datahandler/DatahandlerProcess.php b/Classes/Hooks/Datahandler/DatahandlerProcess.php index 6c8b0e3f..b67ca8db 100644 --- a/Classes/Hooks/Datahandler/DatahandlerProcess.php +++ b/Classes/Hooks/Datahandler/DatahandlerProcess.php @@ -18,6 +18,25 @@ class DatahandlerProcess implements SingletonInterface { protected $containerInProcess = []; + protected $contentElementRestrictionsLook = false; + + protected $stack = 0; + + public function areContentElementRestrictionsLooked(): bool + { + return $this->stack > 0; + } + + public function unlockContentElementRestrictions(): void + { + $this->stack--; + } + + public function lockContentElementRestrictions(): void + { + $this->stack++; + } + public function isContainerInProcess(int $containerId): bool { return in_array($containerId, $this->containerInProcess, true); diff --git a/Classes/Listener/ManipulateBackendLayoutColPosConfigurationForPage.php b/Classes/Listener/ManipulateBackendLayoutColPosConfigurationForPage.php new file mode 100644 index 00000000..be42c5f6 --- /dev/null +++ b/Classes/Listener/ManipulateBackendLayoutColPosConfigurationForPage.php @@ -0,0 +1,79 @@ +getParentUid($e->request); + if ($parent === null) { + return; + } + + try { + $container = $this->containerFactory->buildContainer($parent); + } catch (Exception $e) { + // not a container + return; + } + $cType = $container->getCType(); + $configuration = $this->tcaRegistry->getContentDefenderConfiguration($cType, $e->colPos); + $e->configuration = [ + 'allowedContentTypes' => $configuration['allowedContentTypes'], + 'disallowedContentTypes' => $configuration['disallowedContentTypes'], + ]; + } + + private function getParentUid(?ServerRequestInterface $request): ?int + { + if ($request === null) { + return null; + } + $queryParams = $request->getQueryParams(); + if (isset($queryParams['tx_container_parent']) && $queryParams['tx_container_parent'] > 0) { + // new content elemment wizard + return (int)$queryParams['tx_container_parent']; + } + if ( + isset($queryParams['defVals']['tt_content']['tx_container_parent']) && + $queryParams['defVals']['tt_content']['tx_container_parent'] > 0 + ) { + // TcaCTypeItems: new record + return (int)$queryParams['defVals']['tt_content']['tx_container_parent']; + } + if (isset($queryParams['edit']['tt_content'])) { + $recordUid = array_keys($queryParams['edit']['tt_content'])[0]; + $recordUid = (int)abs($recordUid); + // TcaCTypeItems: edit record + $record = BackendUtility::getRecord('tt_content', $recordUid, 'tx_container_parent'); + if (isset($record['tx_container_parent'])) { + return (int)$record['tx_container_parent']; + } + } + return null; + } +} diff --git a/Classes/Tca/Registry.php b/Classes/Tca/Registry.php index 7d2af1c5..56c8fdee 100644 --- a/Classes/Tca/Registry.php +++ b/Classes/Tca/Registry.php @@ -96,9 +96,17 @@ public function getContentDefenderConfiguration(string $cType, int $colPos): arr foreach ($rows as $columns) { foreach ($columns as $column) { if ((int)$column['colPos'] === $colPos) { + $contentDefenderConfiguration['allowedContentTypes'] = $column['allowedContentTypes'] ?? ''; + $contentDefenderConfiguration['disallowedContentTypes'] = $column['disallowedContentTypes'] ?? ''; $contentDefenderConfiguration['allowed.'] = $column['allowed'] ?? []; $contentDefenderConfiguration['disallowed.'] = $column['disallowed'] ?? []; $contentDefenderConfiguration['maxitems'] = $column['maxitems'] ?? 0; + if ($contentDefenderConfiguration['allowedContentTypes'] === '' && $contentDefenderConfiguration['allowed.'] !== []) { + $contentDefenderConfiguration['allowedContentTypes'] = $contentDefenderConfiguration['allowed.']['CType'] ?? ''; + } + if ($contentDefenderConfiguration['disallowedContentTypes'] === '' && $contentDefenderConfiguration['disallowed.'] !== []) { + $contentDefenderConfiguration['disallowedContentTypes'] = $contentDefenderConfiguration['disallowed.']['CType'] ?? ''; + } return $contentDefenderConfiguration; } } diff --git a/Tests/Acceptance/Backend/ContentDefenderCest.php b/Tests/Acceptance/Backend/ContentDefenderCest.php index 78995f21..24e28f60 100644 --- a/Tests/Acceptance/Backend/ContentDefenderCest.php +++ b/Tests/Acceptance/Backend/ContentDefenderCest.php @@ -149,6 +149,7 @@ public function canCreateNewChildInContainerIfMaxitemsIsReachedInOtherContainer( $I->switchToContentFrame(); $dataColPos = $I->getDataColPos(402, 202); $colPosSelector = '#element-tt_content-402 [data-colpos="' . $dataColPos . '"]'; + $I->scrollTo($colPosSelector); $I->clickNewContentElement($colPosSelector); $I->switchToIFrame(); $I->waitForModal(); diff --git a/Tests/Functional/Datahandler/ContentDefender/CopyContainerTest.php b/Tests/Functional/Datahandler/ContentDefender/CopyContainerTest.php index b8477281..cebde641 100644 --- a/Tests/Functional/Datahandler/ContentDefender/CopyContainerTest.php +++ b/Tests/Functional/Datahandler/ContentDefender/CopyContainerTest.php @@ -14,17 +14,20 @@ use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\Test; +use TYPO3\CMS\Core\Information\Typo3Version; class CopyContainerTest extends AbstractContentDefender { protected array $testExtensionsToLoad = [ 'typo3conf/ext/container', 'typo3conf/ext/container_example', - 'typo3conf/ext/content_defender', ]; protected function setUp(): void { + if ((new Typo3Version())->getMajorVersion() < 14) { + $this->testExtensionsToLoad[] = 'typo3conf/ext/content_defender'; + } parent::setUp(); $this->importCSVDataSet(__DIR__ . '/Fixtures/copy_container.csv'); } diff --git a/Tests/Functional/Datahandler/ContentDefender/DefaultLanguageTest.php b/Tests/Functional/Datahandler/ContentDefender/DefaultLanguageTest.php index f8068bf7..a39ddb33 100644 --- a/Tests/Functional/Datahandler/ContentDefender/DefaultLanguageTest.php +++ b/Tests/Functional/Datahandler/ContentDefender/DefaultLanguageTest.php @@ -14,17 +14,20 @@ use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\Test; +use TYPO3\CMS\Core\Information\Typo3Version; class DefaultLanguageTest extends AbstractContentDefender { protected array $testExtensionsToLoad = [ 'typo3conf/ext/container', 'typo3conf/ext/container_example', - 'typo3conf/ext/content_defender', ]; protected function setUp(): void { + if ((new Typo3Version())->getMajorVersion() < 14) { + $this->testExtensionsToLoad[] = 'typo3conf/ext/content_defender'; + } parent::setUp(); $this->importCSVDataSet(__DIR__ . '/Fixtures/DefaultLanguage/setup.csv'); } diff --git a/Tests/Functional/Datahandler/ContentDefender/LocalizationTest.php b/Tests/Functional/Datahandler/ContentDefender/LocalizationTest.php index de6132e8..202b645b 100644 --- a/Tests/Functional/Datahandler/ContentDefender/LocalizationTest.php +++ b/Tests/Functional/Datahandler/ContentDefender/LocalizationTest.php @@ -14,17 +14,20 @@ use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\Test; +use TYPO3\CMS\Core\Information\Typo3Version; class LocalizationTest extends AbstractContentDefender { protected array $testExtensionsToLoad = [ 'typo3conf/ext/container', 'typo3conf/ext/container_example', - 'typo3conf/ext/content_defender', ]; protected function setUp(): void { + if ((new Typo3Version())->getMajorVersion() < 14) { + $this->testExtensionsToLoad[] = 'typo3conf/ext/content_defender'; + } parent::setUp(); $this->importCSVDataSet(__DIR__ . '/Fixtures/Localization/setup.csv'); } diff --git a/Tests/Functional/Datahandler/ContentDefender/MaxItemsTest.php b/Tests/Functional/Datahandler/ContentDefender/MaxItemsTest.php index 7e1448b4..6b5cd82c 100644 --- a/Tests/Functional/Datahandler/ContentDefender/MaxItemsTest.php +++ b/Tests/Functional/Datahandler/ContentDefender/MaxItemsTest.php @@ -13,8 +13,8 @@ */ use PHPUnit\Framework\Attributes\Group; - use PHPUnit\Framework\Attributes\Test; +use TYPO3\CMS\Core\Information\Typo3Version; use TYPO3\CMS\Core\Utility\StringUtility; class MaxItemsTest extends AbstractContentDefender @@ -22,9 +22,16 @@ class MaxItemsTest extends AbstractContentDefender protected array $testExtensionsToLoad = [ 'typo3conf/ext/container', 'typo3conf/ext/container_example', - 'typo3conf/ext/content_defender', ]; + protected function setUp(): void + { + if ((new Typo3Version())->getMajorVersion() < 14) { + $this->testExtensionsToLoad[] = 'typo3conf/ext/content_defender'; + } + parent::setUp(); + } + #[Test] #[Group('content_defender')] public function canMoveElementIntoContainerIfMaxitemsIsNotReached(): void @@ -77,7 +84,11 @@ public function cannotMoveElementIntoContainerIfMaxitemsIsReached(): void $this->dataHandler->process_datamap(); $this->dataHandler->process_cmdmap(); self::assertCSVDataSet(__DIR__ . '/Fixtures/Maxitems/CannotMoveElementIntoContainerIfMaxitemsIsReachedResult.csv'); - self::assertNotEmpty($this->dataHandler->errorLog, 'dataHander error log is empty'); + if ((new Typo3Version())->getMajorVersion() < 14) { + self::assertNotEmpty($this->dataHandler->errorLog, 'dataHander error log is not empty'); + } else { + self::assertTrue($this->dataHandler->errorLog !== [], 'dataHander error log is not empty'); + } } #[Test] @@ -107,7 +118,11 @@ public function cannotCopyElementIntoContainerIfMaxitemsIsReachedAfterIntoContai $this->dataHandler->process_datamap(); $this->dataHandler->process_cmdmap(); self::assertCSVDataSet(__DIR__ . '/Fixtures/Maxitems/CannotCopyElementIntoContainerIfMaxitemsIsReachedAfterIntoContainerResult.csv'); - self::assertNotEmpty($this->dataHandler->errorLog, 'dataHander error log is not empty'); + if ((new Typo3Version())->getMajorVersion() < 14) { + self::assertNotEmpty($this->dataHandler->errorLog, 'dataHander error log is not empty'); + } else { + self::assertTrue($this->dataHandler->errorLog !== [], 'dataHander error log is not empty'); + } } #[Test] @@ -126,7 +141,11 @@ public function cannotCopyElementIntoContainerIfMaxitemsIsReachedAfterElement(): $this->dataHandler->process_datamap(); $this->dataHandler->process_cmdmap(); self::assertCSVDataSet(__DIR__ . '/Fixtures/Maxitems/CannotCopyElementIntoContainerIfMaxitemsIsReachedAfterElementResult.csv'); - self::assertNotEmpty($this->dataHandler->errorLog, 'dataHander error log is not empty'); + if ((new Typo3Version())->getMajorVersion() < 14) { + self::assertNotEmpty($this->dataHandler->errorLog, 'dataHander error log is not empty'); + } else { + self::assertTrue($this->dataHandler->errorLog !== [], 'dataHander error log is not empty'); + } } #[Test] @@ -326,7 +345,11 @@ public function cannotMoveElementInsideContainerColumnIfMaxitemsIsReached(): voi $this->dataHandler->start([], $cmdmap, $this->backendUser); $this->dataHandler->process_datamap(); $this->dataHandler->process_cmdmap(); - self::assertNotEmpty($this->dataHandler->errorLog, 'dataHander error log is not empty'); + if ((new Typo3Version())->getMajorVersion() < 14) { + self::assertNotEmpty($this->dataHandler->errorLog, 'dataHander error log is not empty'); + } else { + self::assertTrue($this->dataHandler->errorLog !== [], 'dataHander error log is not empty'); + } } #[Test] @@ -343,7 +366,11 @@ public function canTranslateChildIfContainerOfDefaultLanguageMaxitemsIsReached() $this->dataHandler->process_datamap(); $this->dataHandler->process_cmdmap(); self::assertCSVDataSet(__DIR__ . '/Fixtures/Maxitems/CanTranslateChildIfContainerOfDefaultLanguageMaxitemsIsReachedResult.csv'); - self::assertEmpty($this->dataHandler->errorLog, 'dataHander error log is not empty'); + if ((new Typo3Version())->getMajorVersion() < 14) { + self::assertEmpty($this->dataHandler->errorLog, 'dataHander error log is not empty'); + } else { + self::assertTrue($this->dataHandler->errorLog === [], 'dataHander error log is not empty'); + } } #[Test] @@ -360,7 +387,11 @@ public function canCopyToLanguageChildIfContainerOfDefaultLanguageMaxitemsIsReac $this->dataHandler->process_datamap(); $this->dataHandler->process_cmdmap(); self::assertCSVDataSet(__DIR__ . '/Fixtures/Maxitems/CanCopyToLanguageChildIfContainerOfDefaultLanguageMaxitemsIsReachedResult.csv'); - self::assertEmpty($this->dataHandler->errorLog, 'dataHander error log is not empty'); + if ((new Typo3Version())->getMajorVersion() < 14) { + self::assertEmpty($this->dataHandler->errorLog, 'dataHander error log is not empty'); + } else { + self::assertTrue($this->dataHandler->errorLog === [], 'dataHander error log is not empty'); + } } #[Test] @@ -385,7 +416,11 @@ public function canSaveChildInDefaultLanguageWhenTranslatedAndMaxitemsIsReached( $this->dataHandler->start($datamap, [], $this->backendUser); $this->dataHandler->process_datamap(); self::assertCSVDataSet(__DIR__ . '/Fixtures/Maxitems/CanSaveChildInDefaultLanguageWhenTranslatedAndMaxitemsIsReachedResult.csv'); - self::assertEmpty($this->dataHandler->errorLog, 'dataHander error log is not empty'); + if ((new Typo3Version())->getMajorVersion() < 14) { + self::assertEmpty($this->dataHandler->errorLog, 'dataHander error log is not empty'); + } else { + self::assertTrue($this->dataHandler->errorLog === [], 'dataHander error log is not empty'); + } } #[Test] diff --git a/Tests/Functional/Datahandler/Localization/CopyToLanguageSortingTest.php b/Tests/Functional/Datahandler/Localization/CopyToLanguageSortingTest.php index f07ca0ca..1b88143d 100644 --- a/Tests/Functional/Datahandler/Localization/CopyToLanguageSortingTest.php +++ b/Tests/Functional/Datahandler/Localization/CopyToLanguageSortingTest.php @@ -12,9 +12,11 @@ * of the License, or any later version. */ +use B13\Container\Hooks\Datahandler\DatahandlerProcess; use B13\Container\Tests\Functional\Datahandler\AbstractDatahandler; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; +use TYPO3\CMS\Core\Utility\GeneralUtility; class CopyToLanguageSortingTest extends AbstractDatahandler { @@ -108,5 +110,6 @@ public function localizeWithMultipleNestedElements(): void $this->dataHandler->start([], $cmdmap, $this->backendUser); $this->dataHandler->process_cmdmap(); self::assertCSVDataSet(__DIR__ . '/Fixtures/CopyToLanguageSorting/LocalizeWithMultipleNestedElementsResult.csv'); + self::assertFalse((GeneralUtility::makeInstance(DatahandlerProcess::class))->areContentElementRestrictionsLooked()); } } diff --git a/ext_localconf.php b/ext_localconf.php index 3ba2014b..dfe9adf6 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -37,4 +37,8 @@ $datamapHooks, $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'] ); + if ((new \TYPO3\CMS\Core\Information\Typo3Version())->getMajorVersion() > 13) { + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass']['contentElementRestriction'] = \B13\Container\Hooks\Datahandler\ContentElementRestriction\DataHandlerHook::class; + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processCmdmapClass']['contentElementRestriction'] = \B13\Container\Hooks\Datahandler\ContentElementRestriction\DataHandlerHook::class; + } });