Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUGFIX] custom backend templates #577

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Build/phpstan11-7.4.neon
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ parameters:
- %currentWorkingDirectory%/Tests/Functional/Listener/ContentUsedOnPageTest.php
- %currentWorkingDirectory%/Classes/Listener/RecordSummaryForLocalization.php
- %currentWorkingDirectory%/Classes/Listener/PageTsConfig.php
- %currentWorkingDirectory%/Classes/Listener/PageContentPreviewRendering.php

1 change: 1 addition & 0 deletions Build/phpstan11.neon
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ parameters:
- %currentWorkingDirectory%/Tests/Functional/Listener/ContentUsedOnPageTest.php
- %currentWorkingDirectory%/Classes/Listener/RecordSummaryForLocalization.php
- %currentWorkingDirectory%/Classes/Listener/PageTsConfig.php
- %currentWorkingDirectory%/Classes/Listener/PageContentPreviewRendering.php

121 changes: 18 additions & 103 deletions Classes/Backend/Preview/ContainerPreviewRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,122 +12,37 @@
* of the License, or any later version.
*/

use B13\Container\Backend\Grid\ContainerGridColumn;
use B13\Container\Backend\Grid\ContainerGridColumnItem;
use B13\Container\Backend\Service\NewContentUrlBuilder;
use B13\Container\Domain\Factory\Exception;
use B13\Container\Domain\Factory\PageView\Backend\ContainerFactory;
use B13\Container\Events\BeforeContainerPreviewIsRenderedEvent;
use B13\Container\Tca\Registry;
use Psr\EventDispatcher\EventDispatcherInterface;

use TYPO3\CMS\Backend\Preview\StandardContentPreviewRenderer;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Backend\View\BackendLayout\Grid\Grid;
use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumnItem;
use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridRow;
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
use TYPO3\CMS\Core\Information\Typo3Version;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;

class ContainerPreviewRenderer extends StandardContentPreviewRenderer
{
/**
* @var Registry
*/
protected $tcaRegistry;

/**
* @var ContainerFactory
*/
protected $containerFactory;

protected NewContentUrlBuilder $newContentUrlBuilder;

/**
* @var EventDispatcherInterface
*/
protected $eventDispatcher;
protected GridRenderer $gridRenderer;
protected FrontendInterface $runtimeCache;

public function __construct(
Registry $tcaRegistry,
ContainerFactory $containerFactory,
NewContentUrlBuilder $newContentUrlBuilder,
EventDispatcherInterface $eventDispatcher
) {
$this->eventDispatcher = $eventDispatcher;
$this->tcaRegistry = $tcaRegistry;
$this->containerFactory = $containerFactory;
$this->newContentUrlBuilder = $newContentUrlBuilder;
public function __construct(GridRenderer $gridRenderer, FrontendInterface $runtimeCache) {
$this->gridRenderer = $gridRenderer;
$this->runtimeCache = $runtimeCache;
}

public function renderPageModulePreviewContent(GridColumnItem $item): string
public function renderPageModulePreviewHeader(GridColumnItem $item): string
{
$content = parent::renderPageModulePreviewContent($item);
$context = $item->getContext();
$record = $item->getRecord();
$grid = GeneralUtility::makeInstance(Grid::class, $context);
try {
$container = $this->containerFactory->buildContainer((int)$record['uid']);
} catch (Exception $e) {
// not a container
return $content;
}
$containerGrid = $this->tcaRegistry->getGrid($record['CType']);
foreach ($containerGrid as $cols) {
$rowObject = GeneralUtility::makeInstance(GridRow::class, $context);
foreach ($cols as $col) {
$defVals = $this->getDefValsForContentDefenderAllowsOnlyOneSpecificContentType($record['CType'], (int)$col['colPos']);
$url = $this->newContentUrlBuilder->getNewContentUrlAtTopOfColumn($context, $container, (int)$col['colPos'], $defVals);
$columnObject = GeneralUtility::makeInstance(ContainerGridColumn::class, $context, $col, $container, $url, $defVals !== null);
$rowObject->addColumn($columnObject);
if (isset($col['colPos'])) {
$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);
$columnObject->addItem($columnItem);
}
}
}
$grid->addRow($rowObject);
}

$gridTemplate = $this->tcaRegistry->getGridTemplate($record['CType']);
$partialRootPaths = $this->tcaRegistry->getGridPartialPaths($record['CType']);
$layoutRootPaths = $this->tcaRegistry->getGridLayoutPaths($record['CType']);
$view = GeneralUtility::makeInstance(StandaloneView::class);
$view->setPartialRootPaths($partialRootPaths);
$view->setLayoutRootPaths($layoutRootPaths);
$view->setTemplatePathAndFilename($gridTemplate);

$view->assign('hideRestrictedColumns', (bool)(BackendUtility::getPagesTSconfig($context->getPageId())['mod.']['web_layout.']['hideRestrictedCols'] ?? false));
$view->assign('newContentTitle', $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:newContentElement'));
$view->assign('newContentTitleShort', $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:content'));
$view->assign('allowEditContent', $this->getBackendUser()->check('tables_modify', 'tt_content'));
// keep compatibility
$view->assign('containerGrid', $grid);
$view->assign('grid', $grid);
$view->assign('containerRecord', $record);
$view->assign('context', $context);
$beforeContainerPreviewIsRendered = new BeforeContainerPreviewIsRenderedEvent($container, $view, $grid, $item);
$this->eventDispatcher->dispatch($beforeContainerPreviewIsRendered);
$rendered = $view->render();

return $content . $rendered;
$this->runtimeCache->set('tx_container_current_gridColumItem', $item);
return parent::renderPageModulePreviewHeader($item);
}

protected function getDefValsForContentDefenderAllowsOnlyOneSpecificContentType(string $cType, int $colPos): ?array
public function renderPageModulePreviewContent(GridColumnItem $item): string
{
$contentDefefenderConfiguration = $this->tcaRegistry->getContentDefenderConfiguration($cType, $colPos);
$allowedCTypes = GeneralUtility::trimExplode(',', $contentDefefenderConfiguration['allowed.']['CType'] ?? '', true);
$allowedListTypes = GeneralUtility::trimExplode(',', $contentDefefenderConfiguration['allowed.']['list_type'] ?? '', true);
if (count($allowedCTypes) === 1) {
if ($allowedCTypes[0] !== 'list') {
return ['CType' => $allowedCTypes[0]];
}
if (count($allowedListTypes) === 1) {
return ['CType' => 'list', 'list_type' => $allowedListTypes[0]];
}
if ((GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() > 11) {
return parent::renderPageModulePreviewContent($item);
}
return null;
$record = $item->getRecord();
$record['tx_container_grid'] = $this->gridRenderer->renderGrid($record, $item->getContext());
$item->setRecord($record);
return parent::renderPageModulePreviewContent($item);
}
}
135 changes: 135 additions & 0 deletions Classes/Backend/Preview/GridRenderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<?php

declare(strict_types=1);

namespace B13\Container\Backend\Preview;

/*
* This file is part of TYPO3 CMS-based extension "container" by b13.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*/

use B13\Container\Backend\Grid\ContainerGridColumn;
use B13\Container\Backend\Grid\ContainerGridColumnItem;
use B13\Container\Backend\Service\NewContentUrlBuilder;
use B13\Container\Domain\Factory\Exception;
use B13\Container\Domain\Factory\PageView\Backend\ContainerFactory;
use B13\Container\Events\BeforeContainerPreviewIsRenderedEvent;
use B13\Container\Tca\Registry;
use Psr\EventDispatcher\EventDispatcherInterface;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Backend\View\BackendLayout\Grid\Grid;
use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumnItem;
use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridRow;
use TYPO3\CMS\Backend\View\PageLayoutContext;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Fluid\View\StandaloneView;

class GridRenderer
{

protected Registry $tcaRegistry;
protected ContainerFactory $containerFactory;
protected NewContentUrlBuilder $newContentUrlBuilder;
protected EventDispatcherInterface $eventDispatcher;
protected FrontendInterface $runtimeCache;

public function __construct(
Registry $tcaRegistry,
ContainerFactory $containerFactory,
NewContentUrlBuilder $newContentUrlBuilder,
EventDispatcherInterface $eventDispatcher,
FrontendInterface $runtimeCache
) {
$this->eventDispatcher = $eventDispatcher;
$this->tcaRegistry = $tcaRegistry;
$this->containerFactory = $containerFactory;
$this->newContentUrlBuilder = $newContentUrlBuilder;
$this->runtimeCache = $runtimeCache;
}

public function renderGrid(array $record, PageLayoutContext $context): string
{
$grid = GeneralUtility::makeInstance(Grid::class, $context);
try {
$container = $this->containerFactory->buildContainer((int)$record['uid']);
} catch (Exception $e) {
// not a container
return '';
}
$containerGrid = $this->tcaRegistry->getGrid($record['CType']);
foreach ($containerGrid as $cols) {
$rowObject = GeneralUtility::makeInstance(GridRow::class, $context);
foreach ($cols as $col) {
$defVals = $this->getDefValsForContentDefenderAllowsOnlyOneSpecificContentType($record['CType'], (int)$col['colPos']);
$url = $this->newContentUrlBuilder->getNewContentUrlAtTopOfColumn($context, $container, (int)$col['colPos'], $defVals);
$columnObject = GeneralUtility::makeInstance(ContainerGridColumn::class, $context, $col, $container, $url, $defVals !== null);
$rowObject->addColumn($columnObject);
if (isset($col['colPos'])) {
$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);
$columnObject->addItem($columnItem);
}
}
}
$grid->addRow($rowObject);
}

$gridTemplate = $this->tcaRegistry->getGridTemplate($record['CType']);
$partialRootPaths = $this->tcaRegistry->getGridPartialPaths($record['CType']);
$layoutRootPaths = $this->tcaRegistry->getGridLayoutPaths($record['CType']);
$view = GeneralUtility::makeInstance(StandaloneView::class);
$view->setPartialRootPaths($partialRootPaths);
$view->setLayoutRootPaths($layoutRootPaths);
$view->setTemplatePathAndFilename($gridTemplate);

$view->assign('hideRestrictedColumns', (bool)(BackendUtility::getPagesTSconfig($context->getPageId())['mod.']['web_layout.']['hideRestrictedCols'] ?? false));
$view->assign('newContentTitle', $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:newContentElement'));
$view->assign('newContentTitleShort', $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_layout.xlf:content'));
$view->assign('allowEditContent', $this->getBackendUser()->check('tables_modify', 'tt_content'));
// keep compatibility
$view->assign('containerGrid', $grid);
$view->assign('grid', $grid);
$view->assign('containerRecord', $record);
$view->assign('context', $context);
$parentGridColumnItem = $this->runtimeCache->get('tx_container_current_gridColumItem');
$beforeContainerPreviewIsRendered = new BeforeContainerPreviewIsRenderedEvent($container, $view, $grid, $parentGridColumnItem);
$this->eventDispatcher->dispatch($beforeContainerPreviewIsRendered);
$rendered = $view->render();
return $rendered;
}

protected function getDefValsForContentDefenderAllowsOnlyOneSpecificContentType(string $cType, int $colPos): ?array
{
$contentDefefenderConfiguration = $this->tcaRegistry->getContentDefenderConfiguration($cType, $colPos);
$allowedCTypes = GeneralUtility::trimExplode(',', $contentDefefenderConfiguration['allowed.']['CType'] ?? '', true);
$allowedListTypes = GeneralUtility::trimExplode(',', $contentDefefenderConfiguration['allowed.']['list_type'] ?? '', true);
if (count($allowedCTypes) === 1) {
if ($allowedCTypes[0] !== 'list') {
return ['CType' => $allowedCTypes[0]];
}
if (count($allowedListTypes) === 1) {
return ['CType' => 'list', 'list_type' => $allowedListTypes[0]];
}
}
return null;
}

protected function getBackendUser(): BackendUserAuthentication
{
return $GLOBALS['BE_USER'];
}

protected function getLanguageService(): LanguageService
{
return $GLOBALS['LANG'];
}
}
1 change: 1 addition & 0 deletions Classes/Events/BeforeContainerPreviewIsRenderedEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public function getGrid(): Grid

public function getItem(): GridColumnItem
{
trigger_error('gridColumItem property will be removed on next major release', E_USER_DEPRECATED);
return $this->item;
}
}
39 changes: 39 additions & 0 deletions Classes/Listener/PageContentPreviewRendering.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace B13\Container\Listener;

/*
* This file is part of TYPO3 CMS-based extension "container" by b13.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*/

use B13\Container\Backend\Preview\GridRenderer;
use B13\Container\Tca\Registry;
use TYPO3\CMS\Backend\View\Event\PageContentPreviewRenderingEvent;

class PageContentPreviewRendering
{
protected GridRenderer $gridRenderer;
protected Registry $tcaRegistry;

public function __construct(GridRenderer $gridRenderer, Registry $tcaRegistry)
{
$this->gridRenderer = $gridRenderer;
$this->tcaRegistry = $tcaRegistry;
}

public function __invoke(PageContentPreviewRenderingEvent $event): void
{
$record = $event->getRecord();
if (!$this->tcaRegistry->isContainerElement($record['CType'])) {
return;
}
$record['tx_container_grid'] = $this->gridRenderer->renderGrid($record, $event->getPageLayoutContext());
$event->setRecord($record);
}
}
4 changes: 2 additions & 2 deletions Classes/Tca/ContainerConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class ContainerConfiguration
*/
protected $icon = 'EXT:container/Resources/Public/Icons/Extension.svg';

protected ?string $backendTemplate = null;
protected string $backendTemplate = 'EXT:container/Resources/Private/Templates/Container.html';

/**
* @var string
Expand Down Expand Up @@ -228,7 +228,7 @@ public function getIcon(): string
return $this->icon;
}

public function getBackendTemplate(): ?string
public function getBackendTemplate(): string
{
return $this->backendTemplate;
}
Expand Down
6 changes: 2 additions & 4 deletions Classes/Tca/Registry.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ public function configureContainer(ContainerConfiguration $containerConfiguratio
]
);
}

$GLOBALS['TCA']['tt_content']['types'][$containerConfiguration->getCType()]['previewRenderer'] = \B13\Container\Backend\Preview\ContainerPreviewRenderer::class;


if ((GeneralUtility::makeInstance(Typo3Version::class))->getMajorVersion() >= 13) {
if (!isset($GLOBALS['TCA']['tt_content']['types'][$containerConfiguration->getCType()]['creationOptions'])) {
$GLOBALS['TCA']['tt_content']['types'][$containerConfiguration->getCType()]['creationOptions'] = [];
Expand Down Expand Up @@ -266,12 +266,10 @@ public function getPageTsString(): string
}
$groupedByGroup[$group][$cType] = $containerConfiguration;
}
if ($containerConfiguration['backendTemplate'] !== null) {
$pageTs .= LF . 'mod.web_layout.tt_content.preview {
$pageTs .= LF . 'mod.web_layout.tt_content.preview {
' . $cType . ' = ' . $containerConfiguration['backendTemplate'] . '
}
';
}
}
$typo3Version = GeneralUtility::makeInstance(Typo3Version::class);
if ($typo3Version->getMajorVersion() > 12) {
Expand Down
Loading
Loading