Skip to content

Commit

Permalink
WIP|POC:Out of the box grid rendering for backend
Browse files Browse the repository at this point in the history
This is a PoC, not final implementation.

Relates: #68
  • Loading branch information
DanielSiepmann committed Jan 9, 2024
1 parent 7ec3dac commit 9cd2f1f
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 24 deletions.
12 changes: 9 additions & 3 deletions Classes/Backend/Preview/PreviewRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use TYPO3\CMS\Backend\Preview\StandardContentPreviewRenderer;
use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumnItem;
use TYPO3\CMS\ContentBlocks\DataProcessing\ContentBlockDataResolver;
use TYPO3\CMS\ContentBlocks\DataProcessing\GridFactory;
use TYPO3\CMS\ContentBlocks\DataProcessing\RelationResolver;
use TYPO3\CMS\ContentBlocks\Definition\ContentType\ContentType;
use TYPO3\CMS\ContentBlocks\Definition\TableDefinitionCollection;
Expand Down Expand Up @@ -56,7 +57,10 @@ public function renderPageModulePreviewContent(GridColumnItem $item): string
}
$view = GeneralUtility::makeInstance(StandaloneView::class);
$view->setLayoutRootPaths([$contentBlockPrivatePath . '/Layouts']);
$view->setPartialRootPaths([$contentBlockPrivatePath . '/Partials']);
$view->setPartialRootPaths([
'EXT:backend/Resources/Private/Partials',
$contentBlockPrivatePath . '/Partials',
]);
$view->setTemplateRootPaths([$contentBlockPrivatePath]);
$view->setTemplate(ContentBlockPathUtility::getBackendPreviewFileNameWithoutExtension());
$view->setRequest($GLOBALS['TYPO3_REQUEST']);
Expand All @@ -65,12 +69,14 @@ public function renderPageModulePreviewContent(GridColumnItem $item): string
$contentElementTable = ContentType::CONTENT_ELEMENT->getTable();
$contentElementTableDefinition = $this->tableDefinitionCollection->getTable($contentElementTable);

$contentBlockDataResolver = new ContentBlockDataResolver($this->relationResolver, $this->tableDefinitionCollection);
$contentBlockDataResolver = new ContentBlockDataResolver(new GridFactory(), $this->relationResolver, $this->tableDefinitionCollection);
$data = $contentBlockDataResolver->buildContentBlockDataObjectRecursive(
$contentElementDefinition,
$contentElementTableDefinition,
$record,
$contentElementTable
$contentElementTable,
0,
$item->getContext(),
);

$view->assign('data', $data);
Expand Down
77 changes: 57 additions & 20 deletions Classes/DataProcessing/ContentBlockDataResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

namespace TYPO3\CMS\ContentBlocks\DataProcessing;

use TYPO3\CMS\Backend\View\PageLayoutContext;
use TYPO3\CMS\ContentBlocks\Definition\ContentType\ContentTypeInterface;
use TYPO3\CMS\ContentBlocks\Definition\TableDefinition;
use TYPO3\CMS\ContentBlocks\Definition\TableDefinitionCollection;
Expand All @@ -29,6 +30,7 @@
final class ContentBlockDataResolver
{
public function __construct(
private readonly GridFactory $gridFactory,
private readonly RelationResolver $relationResolver,
private readonly TableDefinitionCollection $tableDefinitionCollection,
) {}
Expand All @@ -38,7 +40,8 @@ public function buildContentBlockDataObjectRecursive(
TableDefinition $tableDefinition,
array $data,
string $table,
$depth = 0
int $depth = 0,
?PageLayoutContext $context

Check failure on line 44 in Classes/DataProcessing/ContentBlockDataResolver.php

View workflow job for this annotation

GitHub Actions / PHPStan TYPO3 12.4 PHP 8.2

Deprecated in PHP 8.0: Required parameter $context follows optional parameter $depth.
): ContentBlockData {
$processedContentBlockData = [];
foreach ($contentTypeDefinition->getColumns() as $column) {
Expand All @@ -52,20 +55,53 @@ public function buildContentBlockDataObjectRecursive(
: $data[$tcaFieldDefinition->getUniqueIdentifier()];

if (is_array($processedField) && $tcaFieldDefinition->getFieldType()->isRelation()) {
$processedField = match ($tcaFieldDefinition->getFieldType()) {
FieldType::COLLECTION => $this->transformCollectionRelation($processedField, $tcaFieldDefinition, $table, $depth),
FieldType::SELECT => $this->transformSelectRelation($processedField, $tcaFieldDefinition, $table, $depth),
FieldType::RELATION => $this->transformRelationRelation($processedField, $tcaFieldDefinition, $table, $depth),
default => $processedField,
};
$processedField = $this->processField(
$tcaFieldDefinition->getFieldType(),
$processedField,
$tcaFieldDefinition,
$table,
$depth,
$context
);
if (isset($processedField['__resolvedGrid'])) {
$processedContentBlockData[$tcaFieldDefinition->getIdentifier() . '_grid'] = $processedField['__resolvedGrid'];
$processedField = $processedField['__resolvedField'];
}
}
$processedContentBlockData[$tcaFieldDefinition->getIdentifier()] = $processedField;
}

return $this->buildContentBlockDataObject($data, $processedContentBlockData, $contentTypeDefinition);
}

private function transformCollectionRelation(array $processedField, TcaFieldDefinition $tcaFieldDefinition, string $table, int $depth): array
private function processField(FieldType $fieldType, array $processedField, TcaFieldDefinition $tcaFieldDefinition, string $table, int $depth, ?PageLayoutContext $context): array|ContentBlockData {
$addGrid = false;

if ($fieldType === FieldType::COLLECTION) {
$processedField = $this->transformCollectionRelation($processedField, $tcaFieldDefinition, $table, $depth, $context);
$addGrid = true;
}
if ($fieldType === FieldType::SELECT) {
$processedField = $this->transformSelectRelation($processedField, $tcaFieldDefinition, $table, $depth, $context);
$addGrid = true;
}
if ($fieldType === FieldType::RELATION) {
$processedField = $this->transformRelationRelation($processedField, $tcaFieldDefinition, $table, $depth, $context);
$addGrid = true;
}

if ($addGrid && $context) {
$tableName = $tcaFieldDefinition->getFieldConfiguration()->getTca()['config']['foreign_table'];
return [
'__resolvedGrid' => $this->gridFactory->build($context, $tcaFieldDefinition->getLabelPath(), (array) $processedField, $tableName),
'__resolvedField' => $processedField,
];
}

return $processedField;
}

private function transformCollectionRelation(array $processedField, TcaFieldDefinition $tcaFieldDefinition, string $table, int $depth, ?PageLayoutContext $context): array
{
$collectionTable = $tcaFieldDefinition->getTca()['config']['foreign_table'] ?? $GLOBALS['TCA'][$table]['columns'][$tcaFieldDefinition->getUniqueIdentifier()]['config']['foreign_table'] ?? '';
if ($this->tableDefinitionCollection->hasTable($collectionTable)) {
Expand All @@ -75,36 +111,36 @@ private function transformCollectionRelation(array $processedField, TcaFieldDefi
if ($typeDefinition === null) {
continue;
}
$processedField[$key] = $this->transformRelation($collectionTableDefinition, $typeDefinition, $processedFieldItem, $collectionTable, $depth);
$processedField[$key] = $this->transformRelation($collectionTableDefinition, $typeDefinition, $processedFieldItem, $collectionTable, $depth, $context);
}
}
return $processedField;
}

private function transformSelectRelation(array $processedField, TcaFieldDefinition $tcaFieldDefinition, string $table, int $depth): array|ContentBlockData
private function transformSelectRelation(array $processedField, TcaFieldDefinition $tcaFieldDefinition, string $table, int $depth, ?PageLayoutContext $context): array|ContentBlockData
{
if (($tcaFieldDefinition->getTca()['config']['renderType'] ?? '') === 'selectSingle') {
$processedField = $this->transformSelectSingleRelation($processedField, $tcaFieldDefinition, $table, $depth);
$processedField = $this->transformSelectSingleRelation($processedField, $tcaFieldDefinition, $table, $depth, $context);
} else {
$processedField = $this->transformSelectMultipleRelation($processedField, $tcaFieldDefinition, $table, $depth);
$processedField = $this->transformSelectMultipleRelation($processedField, $tcaFieldDefinition, $table, $depth, $context);
}
return $processedField;
}

private function transformSelectSingleRelation(array $processedField, TcaFieldDefinition $tcaFieldDefinition, string $table, int $depth): array|ContentBlockData
private function transformSelectSingleRelation(array $processedField, TcaFieldDefinition $tcaFieldDefinition, string $table, int $depth, ?PageLayoutContext $context): array|ContentBlockData
{
$foreignTable = $tcaFieldDefinition->getTca()['config']['foreign_table'] ?? $GLOBALS['TCA'][$table]['columns'][$tcaFieldDefinition->getUniqueIdentifier()]['config']['foreign_table'] ?? '';
if ($this->tableDefinitionCollection->hasTable($foreignTable)) {
$foreignTableDefinition = $this->tableDefinitionCollection->getTable($foreignTable);
$typeDefinition = ContentTypeResolver::resolve($foreignTableDefinition, $processedField);
if ($typeDefinition !== null) {
$processedField = $this->transformRelation($foreignTableDefinition, $typeDefinition, $processedField, $foreignTable, $depth);
$processedField = $this->transformRelation($foreignTableDefinition, $typeDefinition, $processedField, $foreignTable, $depth, $context);
}
}
return $processedField;
}

private function transformSelectMultipleRelation(array $processedField, TcaFieldDefinition $tcaFieldDefinition, string $table, int $depth): array
private function transformSelectMultipleRelation(array $processedField, TcaFieldDefinition $tcaFieldDefinition, string $table, int $depth, ?PageLayoutContext $context): array
{
$foreignTable = $tcaFieldDefinition->getTca()['config']['foreign_table'] ?? $GLOBALS['TCA'][$table]['columns'][$tcaFieldDefinition->getUniqueIdentifier()]['config']['foreign_table'] ?? '';
if ($this->tableDefinitionCollection->hasTable($foreignTable)) {
Expand All @@ -114,13 +150,13 @@ private function transformSelectMultipleRelation(array $processedField, TcaField
if ($typeDefinition === null) {
continue;
}
$processedField[$key] = $this->transformRelation($foreignTableDefinition, $typeDefinition, $processedFieldItem, $foreignTable, $depth);
$processedField[$key] = $this->transformRelation($foreignTableDefinition, $typeDefinition, $processedFieldItem, $foreignTable, $depth, $context);
}
}
return $processedField;
}

private function transformRelationRelation(array $processedField, TcaFieldDefinition $tcaFieldDefinition, string $table, int $depth): array
private function transformRelationRelation(array $processedField, TcaFieldDefinition $tcaFieldDefinition, string $table, int $depth, ?PageLayoutContext $context): array
{
$allowed = $tcaFieldDefinition->getTca()['config']['allowed'] ?? $GLOBALS['TCA'][$table]['columns'][$tcaFieldDefinition->getUniqueIdentifier()]['config']['allowed'] ?? '';
// @todo what to do, if multiple tables are allowed? There is no way to find out, which record belongs to which table.
Expand All @@ -131,20 +167,21 @@ private function transformRelationRelation(array $processedField, TcaFieldDefini
if ($typeDefinition === null) {
continue;
}
$processedField[$key] = $this->transformRelation($foreignTableDefinition, $typeDefinition, $processedFieldItem, $allowed, $depth);
$processedField[$key] = $this->transformRelation($foreignTableDefinition, $typeDefinition, $processedFieldItem, $allowed, $depth, $context);
}
}
return $processedField;
}

private function transformRelation(TableDefinition $tableDefinition, ContentTypeInterface $typeDefinition, array $fieldItem, string $foreignTable, int $depth): ContentBlockData
private function transformRelation(TableDefinition $tableDefinition, ContentTypeInterface $typeDefinition, array $fieldItem, string $foreignTable, int $depth, ?PageLayoutContext $context): ContentBlockData
{
$contentBlockData = $this->buildContentBlockDataObjectRecursive(
$typeDefinition,
$tableDefinition,
$fieldItem,
$foreignTable,
++$depth
++$depth,
$context,
);
return $contentBlockData;
}
Expand Down
2 changes: 1 addition & 1 deletion Classes/DataProcessing/ContentBlocksDataProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function process(
if ($contentTypeDefinition === null) {
return $processedData;
}
$contentBlockDataResolver = new ContentBlockDataResolver($this->relationResolver, $this->tableDefinitionCollection);
$contentBlockDataResolver = new ContentBlockDataResolver(new GridFactory(), $this->relationResolver, $this->tableDefinitionCollection);
$processedData['data'] = $contentBlockDataResolver->buildContentBlockDataObjectRecursive(

Check failure on line 45 in Classes/DataProcessing/ContentBlocksDataProcessor.php

View workflow job for this annotation

GitHub Actions / PHPStan TYPO3 12.4 PHP 8.2

Method TYPO3\CMS\ContentBlocks\DataProcessing\ContentBlockDataResolver::buildContentBlockDataObjectRecursive() invoked with 4 parameters, 6 required.
$contentTypeDefinition,
$tableDefinition,
Expand Down
58 changes: 58 additions & 0 deletions Classes/DataProcessing/GridFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

/*
* Copyright (C) 2024 Daniel Siepmann <coding@daniel-siepmann.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/

namespace TYPO3\CMS\ContentBlocks\DataProcessing;

use TYPO3\CMS\Backend\View\BackendLayout\Grid\Grid;
use TYPO3\CMS\Backend\View\BackendLayout\Grid\GridColumn;
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\Utility\GeneralUtility;

final class GridFactory
{
public function build(PageLayoutContext $context, string $columnName, array $records, string $tableName): Grid {
$column = GeneralUtility::makeInstance(GridColumn::class, $context, [
'name' => $columnName,
]);

foreach ($records as $record) {
$column->addItem(GeneralUtility::makeInstance(
GridColumnItem::class,
$context,
$column,
$record->_raw,
// $tableName,
));
}

$row = GeneralUtility::makeInstance(GridRow::class, $context);
$row->addColumn($column);

$grid = GeneralUtility::makeInstance(Grid::class, $context);
$grid->addRow($row);

return $grid;
}
}

0 comments on commit 9cd2f1f

Please sign in to comment.