Skip to content

Commit cc48c21

Browse files
committed
[FEATURE] add ContentAreaProcessor for TYPO3 v14 f:render.contentArea
1 parent 280e759 commit cc48c21

File tree

2 files changed

+130
-0
lines changed

2 files changed

+130
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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+
}

Classes/Tca/Registry.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,19 @@ public function getContainerLabel(string $cType): string
187187
return $GLOBALS['TCA']['tt_content']['containerConfiguration'][$cType]['label'] ?? $cType;
188188
}
189189

190+
public function getColPosName(string $cType, int $colPos): ?string
191+
{
192+
$grid = $this->getGrid($cType);
193+
foreach ($grid as $row) {
194+
foreach ($row as $column) {
195+
if ($column['colPos'] === $colPos) {
196+
return (string)$column['name'];
197+
}
198+
}
199+
}
200+
return null;
201+
}
202+
190203
public function getAvailableColumns(string $cType): array
191204
{
192205
$columns = [];

0 commit comments

Comments
 (0)