|
| 1 | +<?php |
| 2 | + |
| 3 | +declare(strict_types=1); |
| 4 | + |
| 5 | +namespace B13\Container\DataProcessing; |
| 6 | + |
| 7 | +/* |
| 8 | + * This file is part of TYPO3 CMS-based extension "container" by b13. |
| 9 | + * |
| 10 | + * It is free software; you can redistribute it and/or modify it under |
| 11 | + * the terms of the GNU General Public License, either version 2 |
| 12 | + * of the License, or any later version. |
| 13 | + */ |
| 14 | + |
| 15 | +use B13\Container\Domain\Factory\FrontendContainerFactory; |
| 16 | +use B13\Container\Tca\Registry; |
| 17 | +use Symfony\Component\DependencyInjection\Attribute\Autoconfigure; |
| 18 | +use TYPO3\CMS\Core\Context\Context; |
| 19 | +use TYPO3\CMS\Core\Domain\RecordFactory; |
| 20 | +use TYPO3\CMS\Core\Information\Typo3Version; |
| 21 | +use TYPO3\CMS\Core\Page\ContentArea; |
| 22 | +use TYPO3\CMS\Core\Page\ContentAreaClosure; |
| 23 | +use TYPO3\CMS\Core\Page\ContentAreaCollection; |
| 24 | +use TYPO3\CMS\Core\Page\ContentSlideMode; |
| 25 | +use TYPO3\CMS\Core\Utility\GeneralUtility; |
| 26 | +use TYPO3\CMS\Frontend\ContentObject\ContentDataProcessor; |
| 27 | +use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; |
| 28 | +use TYPO3\CMS\Frontend\ContentObject\DataProcessorInterface; |
| 29 | + |
| 30 | +use function array_map; |
| 31 | + |
| 32 | +/** |
| 33 | + * Automatically detects if content element has container columns |
| 34 | + * adds them lazily to the content variable. |
| 35 | + * The ContentArea can be used in f:render.contentArea ViewHelper |
| 36 | + * |
| 37 | + * Only use this DataProcessor for TYPO3 v14 or higher: |
| 38 | + * |
| 39 | + * typoscript: |
| 40 | + * lib.contentElement.dataProcessing.1773665522 = B13\Container\DataProcessing\ContentAreaProcessor |
| 41 | + * #or |
| 42 | + * tt_content.b13-2cols < lib.contentElement |
| 43 | + * tt_content.b13-2cols { |
| 44 | + * templateName = 2Cols |
| 45 | + * templateRootPaths.10 = EXT:base/Resources/Private/Templates |
| 46 | + * dataProcessing.100 = B13\Container\DataProcessing\ContentAreaProcessor |
| 47 | + * } |
| 48 | + * |
| 49 | + * html: |
| 50 | + * <f:render.contentArea contentArea="{content.200}" /> |
| 51 | + * |
| 52 | + */ |
| 53 | +#[Autoconfigure(public: true)] |
| 54 | +readonly class ContentAreaProcessor implements DataProcessorInterface |
| 55 | +{ |
| 56 | + |
| 57 | + public function __construct( |
| 58 | + protected ContentDataProcessor $contentDataProcessor, |
| 59 | + protected Context $context, |
| 60 | + protected FrontendContainerFactory $frontendContainerFactory, |
| 61 | + protected Registry $tcaRegistry, |
| 62 | + protected RecordFactory $recordFactory, |
| 63 | + protected Typo3Version $typo3Version, |
| 64 | + ) {} |
| 65 | + |
| 66 | + public function process( |
| 67 | + ContentObjectRenderer $cObj, |
| 68 | + array $contentObjectConfiguration, |
| 69 | + array $processorConfiguration, |
| 70 | + array $processedData, |
| 71 | + ): array { |
| 72 | + if ($this->typo3Version->getMajorVersion() <= 13) { |
| 73 | + throw new \Exception(self::class . ' requires TYPO3 v14 or higher', 1773664279); |
| 74 | + } |
| 75 | + |
| 76 | + $record = $cObj->data; |
| 77 | + |
| 78 | + $CType = $record['CType'] ?? ''; |
| 79 | + if (!$this->tcaRegistry->isContainerElement($CType)) { |
| 80 | + return $processedData; |
| 81 | + } |
| 82 | + |
| 83 | + $columnsColPos = $this->tcaRegistry->getAllAvailableColumnsColPos($CType); |
| 84 | + |
| 85 | + $container = null; |
| 86 | + |
| 87 | + $areas = []; |
| 88 | + foreach ($columnsColPos as $colPos) { |
| 89 | + $areas[$colPos] = new ContentAreaClosure( |
| 90 | + function () use (&$container, $CType, $cObj, $record, $colPos): ContentArea { |
| 91 | + $container ??= $this->frontendContainerFactory->buildContainer($cObj, $this->context, (int)$record['uid']); |
| 92 | + |
| 93 | + $contentDefenderConfiguration = $this->tcaRegistry->getContentDefenderConfiguration($CType, $colPos); |
| 94 | + |
| 95 | + $rows = $container->getChildrenByColPos($colPos); |
| 96 | + |
| 97 | + $records = array_map(fn($row) => $this->recordFactory->createFromDatabaseRow('tt_content', $row), $rows); |
| 98 | + return new ContentArea( |
| 99 | + (string)$colPos, |
| 100 | + $this->tcaRegistry->getColPosName($record['CType'], $colPos), |
| 101 | + $colPos, |
| 102 | + ContentSlideMode::None, |
| 103 | + GeneralUtility::trimExplode(',', $contentDefenderConfiguration['allowed.']['CType'] ?? '', true), |
| 104 | + GeneralUtility::trimExplode(',', $contentDefenderConfiguration['disallowed.']['CType'] ?? '', true), |
| 105 | + [ |
| 106 | + 'container' => $container, |
| 107 | + ], |
| 108 | + $records, |
| 109 | + ); |
| 110 | + }, |
| 111 | + ); |
| 112 | + } |
| 113 | + |
| 114 | + $processedData[$processedConfiguration['as'] ?? 'content'] = new ContentAreaCollection($areas); |
| 115 | + return $processedData; |
| 116 | + } |
| 117 | +} |
0 commit comments