Files
cms-core/Classes/Schema/RelationMapBuilder.php

95 lines
3.7 KiB
PHP

<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* 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.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\Schema;
use TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidDataStructureException;
use TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidIdentifierException;
use TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidTcaSchemaException;
use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
/**
* Low-level API to parse TCA to find field types which should be processed, as they contain
* a relation.
*
* This also parses ALL flexforms available, that's why it juggles through all FlexForm
* fields and parses the FlexForms as well.
*
* Everything is stored in a simple "RelationMap" object with an internal array structure.
*
* @internal not part of TYPO3 API as it should not be exposed, although this is really cool and powerful.
*/
final readonly class RelationMapBuilder
{
public function __construct(
private FlexFormTools $flexFormTools
) {}
public function buildFromStructure(array $tca): RelationMap
{
$relationMap = new RelationMap();
foreach ($tca as $table => $tableConfig) {
// What fields can have a relational connection to other tables?
foreach ($tableConfig['columns'] ?? [] as $fieldName => $fieldConfig) {
$fieldConfig = $fieldConfig['config'] ?? null;
if (!in_array($fieldConfig['type'] ?? '', ['select', 'group', 'inline', 'file', 'category', 'flex'], true)) {
continue;
}
if ($fieldConfig['type'] === 'flex') {
$this->addRelationsForFlexFieldToRelationMap($table, $tableConfig, $fieldName, $relationMap);
} else {
$relationMap->add($table, $fieldName, $fieldConfig);
}
}
}
return $relationMap;
}
/**
* Adds relations for a flex field to the relation map.
* Note: Inside a section, it is not possible to add a field with a relation (type 'inline', 'file', 'folder', 'group', 'category').
* See TcaFlexProcess class for details.
*/
private function addRelationsForFlexFieldToRelationMap(string $tableName, array $tableConfig, string $fieldName, RelationMap $relationMap): void
{
foreach (array_merge(['default'], array_keys($tableConfig['types'] ?? [])) as $recordType) {
try {
$dataStructure = $this->flexFormTools->parseDataStructureByIdentifier(json_encode([
'type' => 'tca',
'tableName' => $tableName,
'fieldName' => $fieldName,
'dataStructureKey' => $recordType,
]), $tableConfig);
} catch (InvalidTcaSchemaException|InvalidIdentifierException|InvalidDataStructureException) {
// Skip default on error
continue;
}
if (!is_array($dataStructure['sheets'] ?? null)) {
continue;
}
foreach ($dataStructure['sheets'] as $sheetIdentifier => $sheet) {
foreach ($sheet['ROOT']['el'] as $flexFieldName => $flexFieldConfig) {
$fieldIdentifier = $sheetIdentifier . '/' . $flexFieldName;
$relationMap->add($tableName, $fieldName, $flexFieldConfig['config'] ?? [], $fieldIdentifier);
}
}
}
}
}