diff --git a/Build/phpstan-baseline-13.neon b/Build/phpstan-baseline-13.neon index 07678c3e..a34f1638 100644 --- a/Build/phpstan-baseline-13.neon +++ b/Build/phpstan-baseline-13.neon @@ -61,3 +61,7 @@ parameters: message: "#^Access to an undefined property B13\\\\Container\\\\Backend\\\\ContextMenu\\\\RecordContextMenuItemProvider\\:\\:\\$uriBuilder\\.$#" count: 1 path: ../Classes/Backend/ContextMenu/RecordContextMenuItemProvider.php + - + message: "#^Instanceof between array and TYPO3\\\\CMS\\\\Core\\\\Domain\\\\RecordInterface will always evaluate to false\\.$#" + count: 1 + path: ../Classes/Backend/Grid/ContainerGridColumnItem.php diff --git a/Build/phpstan-baseline-14.neon b/Build/phpstan-baseline-14.neon index b048f1a4..f428f1a2 100644 --- a/Build/phpstan-baseline-14.neon +++ b/Build/phpstan-baseline-14.neon @@ -23,3 +23,7 @@ parameters: message: "#^Class TYPO3\\\\CMS\\\\Backend\\\\View\\\\PageLayoutContext constructor invoked with 2 parameters, 5 required\\.$#" count: 1 path: ../Tests/Functional/Integrity/IntegrityTest.php + - + message: "#^Else branch is unreachable because previous condition is always true\\.$#" + count: 1 + path: ../Classes/Backend/Grid/ContainerGridColumnItem.php diff --git a/Classes/Backend/Grid/ContainerGridColumnItem.php b/Classes/Backend/Grid/ContainerGridColumnItem.php index 60d22e71..beb09a03 100644 --- a/Classes/Backend/Grid/ContainerGridColumnItem.php +++ b/Classes/Backend/Grid/ContainerGridColumnItem.php @@ -13,15 +13,17 @@ */ use B13\Container\Domain\Model\Container; +use B13\Container\Tca\Registry; use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumnItem; use TYPO3\CMS\Backend\View\PageLayoutContext; use TYPO3\CMS\Core\Domain\RecordFactory; +use TYPO3\CMS\Core\Domain\RecordInterface; use TYPO3\CMS\Core\Information\Typo3Version; use TYPO3\CMS\Core\Utility\GeneralUtility; class ContainerGridColumnItem extends GridColumnItem { - public function __construct(PageLayoutContext $context, ContainerGridColumn $column, array $record, protected Container $container, protected ?string $newContentUrl) + public function __construct(PageLayoutContext $context, ContainerGridColumn $column, array $record, protected Registry $tcaRegistry, protected Container $container, protected ?string $newContentUrl) { if ((GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() > 13) { $recordFactory = GeneralUtility::makeInstance(RecordFactory::class); @@ -44,7 +46,17 @@ public function getWrapperClassName(): string if ($this->isDisabled()) { $wrapperClassNames[] = 't3-page-ce-hidden t3js-hidden-record'; } - // we do not need a "t3-page-ce-warning" class because we are build from Container + $record = $this->record; + if ($record instanceof RecordInterface) { + if (!$this->tcaRegistry->recordIsAllowedInContainerColumn($record)) { + $wrapperClassNames[] = 't3-page-ce-warning'; + } + } else { + // v13 + if (!$this->tcaRegistry->isAllowedInColumn($record['CType'], (int)$record['colPos'], $this->container->getCType())) { + $wrapperClassNames[] = 't3-page-ce-warning'; + } + } return implode(' ', $wrapperClassNames); } diff --git a/Classes/Backend/Preview/GridRenderer.php b/Classes/Backend/Preview/GridRenderer.php index c3dd040e..fb397369 100644 --- a/Classes/Backend/Preview/GridRenderer.php +++ b/Classes/Backend/Preview/GridRenderer.php @@ -65,7 +65,7 @@ public function renderGrid(array $record, PageLayoutContext $context): string $records = $container->getChildrenByColPos($col['colPos']); foreach ($records as $contentRecord) { $url = $this->newContentUrlBuilder->getNewContentUrlAfterChild($context, $container, (int)$col['colPos'], (int)$contentRecord['uid'], $defVals); - $columnItem = GeneralUtility::makeInstance(ContainerGridColumnItem::class, $context, $columnObject, $contentRecord, $container, $url); + $columnItem = GeneralUtility::makeInstance(ContainerGridColumnItem::class, $context, $columnObject, $contentRecord, $this->tcaRegistry, $container, $url); $columnObject->addItem($columnItem); } } diff --git a/Classes/Listener/PageContentPreviewRendering.php b/Classes/Listener/PageContentPreviewRendering.php index 08ae4032..4f8ba9d3 100644 --- a/Classes/Listener/PageContentPreviewRendering.php +++ b/Classes/Listener/PageContentPreviewRendering.php @@ -19,6 +19,7 @@ use TYPO3\CMS\Core\Attribute\AsEventListener; use TYPO3\CMS\Core\Domain\Record; use TYPO3\CMS\Core\Information\Typo3Version; +use TYPO3\CMS\Core\Localization\LanguageService; #[AsEventListener(identifier: 'tx-container-page-content-preview-rendering', before: 'typo3-backend/fluid-preview/content')] class PageContentPreviewRendering @@ -37,6 +38,14 @@ public function __invoke(PageContentPreviewRenderingEvent $event): void } $record = $event->getRecord(); + if ($this->tcaRegistry->recordIsAllowedInContainerColumn($record) === false) { + $labels = $event->getPageLayoutContext()->getContentTypeLabels(); + $label = $labels[$record->getRecordType()] ?? $record->getRecordType(); + $label = sprintf($this->getLanguageService()->sL('core.core:labels.typeNotAllowedInColumn'), $label); + $content = '' . $label . ''; + $event->setPreviewContent($content); + return; + } $recordType = $record->getRecordType(); if (!$this->tcaRegistry->isContainerElement($recordType)) { return; @@ -47,4 +56,9 @@ public function __invoke(PageContentPreviewRenderingEvent $event): void $event->setRecord($recordWithRenderedGrid); } } + + protected function getLanguageService(): LanguageService + { + return $GLOBALS['LANG']; + } } diff --git a/Classes/Tca/Registry.php b/Classes/Tca/Registry.php index fed2855e..ae14ba28 100644 --- a/Classes/Tca/Registry.php +++ b/Classes/Tca/Registry.php @@ -15,6 +15,7 @@ use B13\Container\Events\BeforeContainerConfigurationIsAppliedEvent; use Psr\EventDispatcher\EventDispatcherInterface; use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; +use TYPO3\CMS\Core\Domain\RecordInterface; use TYPO3\CMS\Core\Imaging\IconProvider\BitmapIconProvider; use TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider; use TYPO3\CMS\Core\Imaging\IconRegistry; @@ -114,6 +115,35 @@ public function getAllowedCTypesInColumn(string $cType, int $colPos): ?array return GeneralUtility::trimExplode(',', $contentDefenderConfiguration['allowedContentTypes'], true); } + public function recordIsAllowedInContainerColumn(RecordInterface $record): bool + { + $recordType = $record->getRecordType(); + if ($record->has('tx_container_parent')) { + $containerRecord = $record->get('tx_container_parent'); + if ($containerRecord instanceof RecordInterface) { + $containerRecordType = $containerRecord->getRecordType(); + if ($this->isContainerElement($containerRecordType)) { + return $this->isAllowedInColumn($recordType, (int)$record->get('colPos'), $containerRecordType); + } + } + } + return true; + } + + public function isAllowedInColumn(string $cType, int $colPos, string $containerCType): bool + { + $contentDefenderConfiguration = $this->getContentDefenderConfiguration($cType, $colPos); + $disallowed = GeneralUtility::trimExplode(',', $contentDefenderConfiguration['disallowedContentTypes'] ?? '', true); + if (in_array($cType, $disallowed)) { + return false; + } + $allowed = $this->getAllowedCTypesInColumn($containerCType, $colPos); + if ($allowed === null) { + return true; + } + return in_array($cType, $allowed); + } + public function getAllAvailableColumnsColPos(string $cType): array { $columns = $this->getAvailableColumns($cType);