Skip to content

Commit 43c6fba

Browse files
committed
[TASK] provide some events
Introduce 2 new PSR-14 Events BeforeContainerConfigurationIsAppliedEvent * change container configuration for 3rd party extensions container you have installed * apply same configuration to all or a set of containers (e.g. gridTemplate) * Note: CType and Grid Structure cannot be changed (but Column Properties of the Grid) BeforeContainerPreviewIsRendered change view object, e.g. add variables to view or change paths
1 parent ef6cc8d commit 43c6fba

16 files changed

+212
-27
lines changed

Classes/Backend/Preview/ContainerPreviewRenderer.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
use B13\Container\Domain\Factory\Exception;
1919
use B13\Container\Domain\Factory\PageView\Backend\ContainerFactory;
2020
use B13\Container\Domain\Service\ContainerService;
21+
use B13\Container\Events\BeforeContainerPreviewIsRenderedEvent;
2122
use B13\Container\Tca\Registry;
2223
use TYPO3\CMS\Backend\Preview\StandardContentPreviewRenderer;
2324
use TYPO3\CMS\Backend\Utility\BackendUtility;
2425
use TYPO3\CMS\Backend\View\BackendLayout\Grid\Grid;
2526
use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumnItem;
2627
use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridRow;
28+
use TYPO3\CMS\Core\EventDispatcher\EventDispatcher;
2729
use TYPO3\CMS\Core\Utility\GeneralUtility;
2830
use TYPO3\CMS\Fluid\View\StandaloneView;
2931

@@ -49,16 +51,23 @@ class ContainerPreviewRenderer extends StandardContentPreviewRenderer
4951
*/
5052
protected $containerService;
5153

54+
/**
55+
* @var EventDispatcher
56+
*/
57+
protected $eventDispatcher;
58+
5259
public function __construct(
5360
Registry $tcaRegistry,
5461
ContainerFactory $containerFactory,
5562
ContainerColumnConfigurationService $containerColumnConfigurationService,
56-
ContainerService $containerService
63+
ContainerService $containerService,
64+
EventDispatcher $eventDispatcher
5765
) {
5866
$this->tcaRegistry = $tcaRegistry;
5967
$this->containerFactory = $containerFactory;
6068
$this->containerColumnConfigurationService = $containerColumnConfigurationService;
6169
$this->containerService = $containerService;
70+
$this->eventDispatcher = $eventDispatcher;
6271
}
6372

6473
public function renderPageModulePreviewContent(GridColumnItem $item): string
@@ -74,7 +83,7 @@ public function renderPageModulePreviewContent(GridColumnItem $item): string
7483
return $content;
7584
}
7685
$containerGrid = $this->tcaRegistry->getGrid($record['CType']);
77-
foreach ($containerGrid as $row => $cols) {
86+
foreach ($containerGrid as $cols) {
7887
$rowObject = GeneralUtility::makeInstance(GridRow::class, $context);
7988
foreach ($cols as $col) {
8089
$newContentElementAtTopTarget = $this->containerService->getNewContentElementAtTopTargetInColumn($container, $col['colPos']);
@@ -107,8 +116,12 @@ public function renderPageModulePreviewContent(GridColumnItem $item): string
107116
$view->assign('newContentTitle', $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:newContentElement'));
108117
$view->assign('newContentTitleShort', $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:content'));
109118
$view->assign('allowEditContent', $this->getBackendUser()->check('tables_modify', 'tt_content'));
119+
// keep compatibility
110120
$view->assign('containerGrid', $grid);
121+
$view->assign('grid', $grid);
111122
$view->assign('containerRecord', $record);
123+
$beforeContainerPreviewIsRendered = new BeforeContainerPreviewIsRenderedEvent($container, $view);
124+
$this->eventDispatcher->dispatch($beforeContainerPreviewIsRendered);
112125
$rendered = $view->render();
113126

114127
return $content . $rendered;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace B13\Container\Events;
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\Tca\ContainerConfiguration;
16+
17+
final class BeforeContainerConfigurationIsAppliedEvent
18+
{
19+
protected ContainerConfiguration $containerConfiguration;
20+
protected bool $skip = false;
21+
22+
public function __construct(ContainerConfiguration $containerConfiguration)
23+
{
24+
$this->containerConfiguration = $containerConfiguration;
25+
}
26+
27+
public function skip(): void
28+
{
29+
$this->skip = true;
30+
}
31+
32+
public function shouldBeSkipped(): bool
33+
{
34+
return $this->skip;
35+
}
36+
37+
public function getContainerConfiguration(): ContainerConfiguration
38+
{
39+
return $this->containerConfiguration;
40+
}
41+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace B13\Container\Events;
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\Model\Container;
16+
use TYPO3\CMS\Fluid\View\StandaloneView;
17+
18+
final class BeforeContainerPreviewIsRenderedEvent
19+
{
20+
protected Container $container;
21+
22+
protected StandaloneView $view;
23+
24+
public function __construct(Container $container, StandaloneView $view)
25+
{
26+
$this->container = $container;
27+
$this->view = $view;
28+
}
29+
30+
public function getContainer(): Container
31+
{
32+
return $this->container;
33+
}
34+
35+
public function getView(): StandaloneView
36+
{
37+
return $this->view;
38+
}
39+
}

Classes/Tca/ContainerConfiguration.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,31 @@ public function getGrid(): array
218218
return $this->grid;
219219
}
220220

221+
public function getDescription(): string
222+
{
223+
return $this->description;
224+
}
225+
226+
public function getIcon(): string
227+
{
228+
return $this->icon;
229+
}
230+
231+
public function getBackendTemplate(): ?string
232+
{
233+
return $this->backendTemplate;
234+
}
235+
236+
public function isRegisterInNewContentElementWizard(): bool
237+
{
238+
return $this->registerInNewContentElementWizard;
239+
}
240+
241+
public function getDefaultValues(): array
242+
{
243+
return $this->defaultValues;
244+
}
245+
221246
/**
222247
* @return string[]
223248
*/
@@ -249,6 +274,43 @@ public function setDefaultValues(array $defaultValues): ContainerConfiguration
249274
return $this;
250275
}
251276

277+
protected function setLabel(string $label): ContainerConfiguration
278+
{
279+
$this->label = $label;
280+
return $this;
281+
}
282+
283+
public function setDescription(string $description): ContainerConfiguration
284+
{
285+
$this->description = $description;
286+
return $this;
287+
}
288+
289+
public function getGridTemplate(): string
290+
{
291+
return $this->gridTemplate;
292+
}
293+
294+
public function changeGridColumnConfiguration(int $colPos, array $override): void
295+
{
296+
$rows = $this->getGrid();
297+
$modRows = [];
298+
$columnConfigurationFields = ['name', 'allowed', 'disallowed', 'maxitems', 'colspan'];
299+
foreach ($rows as &$columns) {
300+
foreach ($columns as &$column) {
301+
if ((int)$column['colPos'] === $colPos) {
302+
foreach ($columnConfigurationFields as $field) {
303+
if (isset($override[$field])) {
304+
$column[$field] = $override[$field];
305+
}
306+
}
307+
}
308+
}
309+
$modRows[] = $columns;
310+
}
311+
$this->grid = $modRows;
312+
}
313+
252314
/**
253315
* @return mixed[]
254316
*/

Classes/Tca/Registry.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
* of the License, or any later version.
1313
*/
1414

15+
use B13\Container\Events\BeforeContainerConfigurationIsAppliedEvent;
16+
use TYPO3\CMS\Core\EventDispatcher\EventDispatcher;
1517
use TYPO3\CMS\Core\Imaging\IconProvider\BitmapIconProvider;
1618
use TYPO3\CMS\Core\Imaging\IconProvider\SvgIconProvider;
1719
use TYPO3\CMS\Core\Imaging\IconRegistry;
@@ -22,11 +24,23 @@
2224

2325
class Registry implements SingletonInterface
2426
{
27+
protected EventDispatcher $eventDispatcher;
28+
29+
public function __construct(EventDispatcher $eventDispatcher)
30+
{
31+
$this->eventDispatcher = $eventDispatcher;
32+
}
33+
2534
/**
2635
* @param ContainerConfiguration $containerConfiguration
2736
*/
2837
public function configureContainer(ContainerConfiguration $containerConfiguration): void
2938
{
39+
$beforeContainerConfigurationIsAppliedEvent = new BeforeContainerConfigurationIsAppliedEvent($containerConfiguration);
40+
$this->eventDispatcher->dispatch($beforeContainerConfigurationIsAppliedEvent);
41+
if ($beforeContainerConfigurationIsAppliedEvent->shouldBeSkipped()) {
42+
return;
43+
}
3044
if ((GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() >= 12) {
3145
ExtensionManagementUtility::addTcaSelectItem(
3246
'tt_content',
@@ -109,6 +123,7 @@ public function getContentDefenderConfiguration(string $cType, int $colPos): arr
109123
$contentDefenderConfiguration['allowed.'] = $column['allowed'] ?? [];
110124
$contentDefenderConfiguration['disallowed.'] = $column['disallowed'] ?? [];
111125
$contentDefenderConfiguration['maxitems'] = $column['maxitems'] ?? 0;
126+
return $contentDefenderConfiguration;
112127
}
113128
}
114129
}
@@ -167,10 +182,7 @@ public function getRegisteredCTypes(): array
167182

168183
public function getGrid(string $cType): array
169184
{
170-
if (empty($GLOBALS['TCA']['tt_content']['containerConfiguration'][$cType]['grid'])) {
171-
return [];
172-
}
173-
return $GLOBALS['TCA']['tt_content']['containerConfiguration'][$cType]['grid'];
185+
return $GLOBALS['TCA']['tt_content']['containerConfiguration'][$cType]['grid'] ?? [];
174186
}
175187

176188
public function getGridTemplate(string $cType): ?string

Configuration/Services.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ services:
1313
- '../Classes/Tca/ContainerConfiguration.php'
1414
- '../Classes/**/Exception.php'
1515

16+
B13\Container\Tca\Registry:
17+
public: true
1618
B13\Container\Backend\Preview\ContainerPreviewRenderer:
1719
public: true
1820
B13\Container\Hooks\UsedRecords:

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,18 @@ The html template file goes in the folder that you have defined in your TypoScri
165165

166166
With explicit colPos defined use `{children_200|201}` as set in the example above
167167

168+
## PSR-14 Events
169+
170+
### BeforeContainerConfigurationIsAppliedEvent
171+
172+
* change container configuration for 3rd party extensions container you have installed
173+
* apply same configuration to all or a set of containers (e.g. ``gridTemplate``)
174+
* **Note** CType and Grid Structure cannot be changed (but Column Properties of the Grid)
175+
176+
### BeforeContainerPreviewIsRendered
177+
178+
change view object, e.g. add variables to view or change paths
179+
168180
## Concepts
169181
- Complete registration is done with one PHP call to TCA Registry
170182
- A container in the TYPO3 backend Page module is rendered like a page itself (see View/ContainerLayoutView)

Resources/Private/Templates/Grid.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
data-namespace-typo3-fluid="true"
44
>
55

6-
<f:if condition="{containerGrid}">
7-
<f:render partial="PageLayout/Grid" arguments="{grid: containerGrid, hideRestrictedColumns: hideRestrictedColumns, newContentTitle: newContentTitle, newContentTitleShort: newContentTitleShort, allowEditContent: allowEditContent}" />
6+
<f:if condition="{grid}">
7+
<f:render partial="PageLayout/Grid" arguments="{_all}" />
88
</f:if>
99

1010
</html>

Tests/Unit/Domain/Factory/PageView/ContainerFactoryTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function containerByUidReturnsNullIfNoRecordInDatabaseIsFound(): void
3232
->onlyMethods(['fetchOneRecord'])
3333
->getMock();
3434
$database->expects(self::once())->method('fetchOneRecord')->with(1)->willReturn(null);
35-
$tcaRegistry = $this->getMockBuilder(Registry::class)->getMock();
35+
$tcaRegistry = $this->getMockBuilder(Registry::class)->disableOriginalConstructor()->getMock();
3636
$context = $this->getMockBuilder(Context::class)->getMock();
3737
$containerFactory = $this->getMockBuilder($this->buildAccessibleProxy(ContainerFactory::class))
3838
->setConstructorArgs(['database' => $database, 'tcaRegistry' => $tcaRegistry, 'context' => $context])

Tests/Unit/Domain/Service/ContainerServiceTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public function setupDataProvider()
6868
*/
6969
public function getFirstNewContentElementTargetInColumnTest(array $containerRecord, array $childRecords, int $targetColPos, int $expectedTarget): void
7070
{
71-
$tcaRegistry = $this->getMockBuilder(Registry::class)->onlyMethods(['getAllAvailableColumnsColPos'])->getMock();
71+
$tcaRegistry = $this->getMockBuilder(Registry::class)->disableOriginalConstructor()->onlyMethods(['getAllAvailableColumnsColPos'])->getMock();
7272
$tcaRegistry->expects(self::any())->method('getAllAvailableColumnsColPos')->willReturn($this->allContainerColumns);
7373
$containerFactory = $this->getMockBuilder(ContainerFactory::class)->disableOriginalConstructor()->getMock();
7474
$container = new Container($containerRecord, $childRecords, 0);

Tests/Unit/Hooks/Datahandler/CommandMapBeforeStartHookTest.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function rewriteCommandMapTargetForTopAtContainerTest(): void
4141
->getMock();
4242
$containerService->expects(self::once())->method('getNewContentElementAtTopTargetInColumn')->with($container, 2)->willReturn(-4);
4343
$database = $this->getMockBuilder(Database::class)->getMock();
44-
$tcaRegistry = $this->getMockBuilder(Registry::class)->getMock();
44+
$tcaRegistry = $this->getMockBuilder(Registry::class)->disableOriginalConstructor()->getMock();
4545
$dataHandlerHook = $this->getMockBuilder($this->buildAccessibleProxy(CommandMapBeforeStartHook::class))
4646
->setConstructorArgs(['containerFactory' => $containerFactory, 'tcaRegistry' => $tcaRegistry, 'database' => $database, 'containerService' => $containerService])
4747
->onlyMethods([])
@@ -94,7 +94,7 @@ public function rewriteSimpleCommandMapTestForIntoContainer(): void
9494
$containerFactory = $this->getMockBuilder(ContainerFactory::class)->disableOriginalConstructor()->getMock();
9595
$containerService = $this->getMockBuilder(ContainerService::class)->disableOriginalConstructor()->getMock();
9696
$database = $this->getMockBuilder(Database::class)->onlyMethods(['fetchOneRecord'])->getMock();
97-
$tcaRegistry = $this->getMockBuilder(Registry::class)->getMock();
97+
$tcaRegistry = $this->getMockBuilder(Registry::class)->disableOriginalConstructor()->getMock();
9898
$database->expects(self::once())->method('fetchOneRecord')->with(1)->willReturn($copyAfterRecord);
9999
$dataHandlerHook = $this->getMockBuilder($this->buildAccessibleProxy(CommandMapBeforeStartHook::class))
100100
->setConstructorArgs(['containerFactory' => $containerFactory, 'tcaRegistry' => $tcaRegistry, 'database' => $database, 'containerService' => $containerService])
@@ -143,7 +143,7 @@ public function rewriteSimpleCommandMapTestForAfterContainer(): void
143143
$containerFactory = $this->getMockBuilder(ContainerFactory::class)->disableOriginalConstructor()->getMock();
144144
$containerService = $this->getMockBuilder(ContainerService::class)->disableOriginalConstructor()->getMock();
145145
$database = $this->getMockBuilder(Database::class)->onlyMethods(['fetchOneRecord'])->getMock();
146-
$tcaRegistry = $this->getMockBuilder(Registry::class)->onlyMethods(['isContainerElement'])->getMock();
146+
$tcaRegistry = $this->getMockBuilder(Registry::class)->disableOriginalConstructor()->onlyMethods(['isContainerElement'])->getMock();
147147
$database->expects(self::once())->method('fetchOneRecord')->with(1)->willReturn($copyAfterRecord);
148148
$tcaRegistry->expects(self::once())->method('isContainerElement')->with('container-ctype')->willReturn(true);
149149
$dataHandlerHook = $this->getMockBuilder($this->buildAccessibleProxy(CommandMapBeforeStartHook::class))
@@ -184,7 +184,7 @@ public function extractContainerIdFromColPosInDatamapSetsContainerIdToSplittedCo
184184
{
185185
$database = $this->getMockBuilder(Database::class)->getMock();
186186
$containerFactory = $this->getMockBuilder(ContainerFactory::class)->disableOriginalConstructor()->getMock();
187-
$tcaRegistry = $this->getMockBuilder(Registry::class)->getMock();
187+
$tcaRegistry = $this->getMockBuilder(Registry::class)->disableOriginalConstructor()->getMock();
188188
$containerService = $this->getMockBuilder(ContainerService::class)->disableOriginalConstructor()->getMock();
189189
$dataHandlerHook = $this->getMockBuilder($this->buildAccessibleProxy(CommandMapBeforeStartHook::class))
190190
->setConstructorArgs(['containerFactory' => $containerFactory, 'tcaRegistry' => $tcaRegistry, 'database' => $database, 'containerService' => $containerService])
@@ -227,7 +227,7 @@ public function extractContainerIdFromColPosInDatamapSetsContainerIdToSplittedCo
227227
{
228228
$database = $this->getMockBuilder(Database::class)->getMock();
229229
$containerFactory = $this->getMockBuilder(ContainerFactory::class)->disableOriginalConstructor()->getMock();
230-
$tcaRegistry = $this->getMockBuilder(Registry::class)->getMock();
230+
$tcaRegistry = $this->getMockBuilder(Registry::class)->disableOriginalConstructor()->getMock();
231231
$containerService = $this->getMockBuilder(ContainerService::class)->disableOriginalConstructor()->getMock();
232232
$dataHandlerHook = $this->getMockBuilder($this->buildAccessibleProxy(CommandMapBeforeStartHook::class))
233233
->setConstructorArgs(['containerFactory' => $containerFactory, 'tcaRegistry' => $tcaRegistry, 'database' => $database, 'containerService' => $containerService])
@@ -257,7 +257,7 @@ public function extractContainerIdFromColPosInDatamapSetsContainerIdToZeroValue(
257257
{
258258
$database = $this->getMockBuilder(Database::class)->getMock();
259259
$containerFactory = $this->getMockBuilder(ContainerFactory::class)->disableOriginalConstructor()->getMock();
260-
$tcaRegistry = $this->getMockBuilder(Registry::class)->getMock();
260+
$tcaRegistry = $this->getMockBuilder(Registry::class)->disableOriginalConstructor()->getMock();
261261
$containerService = $this->getMockBuilder(ContainerService::class)->disableOriginalConstructor()->getMock();
262262
$dataHandlerHook = $this->getMockBuilder($this->buildAccessibleProxy(CommandMapBeforeStartHook::class))
263263
->setConstructorArgs(['containerFactory' => $containerFactory, 'tcaRegistry' => $tcaRegistry, 'database' => $database, 'containerService' => $containerService])

Tests/Unit/Hooks/Datahandler/DatamapBeforeStartHookTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public function datamapForLocalizationsExtendsDatamapWithLocalizations(): void
3939
->getMock();
4040
$database->expects(self::once())->method('fetchOverlayRecords')->with($defaultRecord)->willReturn([['uid' => 3]]);
4141
$database->expects(self::once())->method('fetchOneRecord')->with(2)->willReturn($defaultRecord);
42-
$containerRegistry = $this->getMockBuilder(Registry::class)->getMock();
42+
$containerRegistry = $this->getMockBuilder(Registry::class)->disableOriginalConstructor()->getMock();
4343
$containerService = $this->getMockBuilder(ContainerService::class)->disableOriginalConstructor()->getMock();
4444
$dataHandlerHook = $this->getMockBuilder($this->buildAccessibleProxy(DatamapBeforeStartHook::class))
4545
->setConstructorArgs([

0 commit comments

Comments
 (0)