Files
cms-backend/Classes/Form/FormDataProvider/TcaFlexPrepare.php
T

129 lines
5.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\Backend\Form\FormDataProvider;
use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
use TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidDataStructureException;
use TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidIdentifierException;
use TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidTcaException;
use TYPO3\CMS\Core\Configuration\FlexForm\Exception\InvalidTcaSchemaException;
use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
use TYPO3\CMS\Core\Schema\Exception\UndefinedSchemaException;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Resolve flex data structure and data values, prepare and normalize.
*
* This is the first data provider in the chain of flex form related providers.
*/
readonly class TcaFlexPrepare implements FormDataProviderInterface
{
public function __construct(
private FlexFormTools $flexFormTools,
) {}
/**
* Resolve flex data structures and prepare flex data values.
*
* Normalize some details to have aligned array nesting for the rest of the
* processing method and the render engine.
*/
public function addData(array $result): array
{
foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfig) {
if (empty($fieldConfig['config']['type']) || $fieldConfig['config']['type'] !== 'flex') {
continue;
}
$result = $this->initializeDataStructure($result, (string)$fieldName);
$result = $this->initializeDataValues($result, (string)$fieldName);
}
return $result;
}
/**
* Fetch / initialize data structure.
*
* The data structures in ['config']['ds'] is initialized here and the dataStructureIdentifier is set.
*/
protected function initializeDataStructure(array $result, string $fieldName): array
{
$dataStructureArray = ['sheets' => ['sDEF' => []]];
if (!isset($result['processedTca']['columns'][$fieldName]['config']['dataStructureIdentifier'])) {
try {
// Actually ['config']['ds'] might already contain the resolved data structure. However,
// since the references value might be a file path and a couple of events exist for flex
// form resolving, we nevertheless need to call getDataStructureIdentifier() and
// parseDataStructureByIdentifier() here.
$schema = $result['tcaSchemata']->get($result['tableName']);
$dataStructureIdentifier = $this->flexFormTools->getDataStructureIdentifier(
$result['processedTca']['columns'][$fieldName],
$result['tableName'],
$fieldName,
$result['databaseRow'],
$schema
);
$dataStructureArray = $this->flexFormTools->parseDataStructureByIdentifier($dataStructureIdentifier, $schema);
// Add the identifier to TCA to use it later during rendering
$result['processedTca']['columns'][$fieldName]['config']['dataStructureIdentifier'] = $dataStructureIdentifier;
} catch (InvalidDataStructureException|InvalidIdentifierException|InvalidTcaException|UndefinedSchemaException) {
// Skip the data structure if it is invalid
}
} elseif (is_array($result['processedTca']['columns'][$fieldName]['config']['ds'] ?? false)) {
// Data structure has been given from outside
$dataStructureArray = $result['processedTca']['columns'][$fieldName]['config']['ds'];
} else {
// Resolve data structure base on given dataStructureIdentifier
try {
$dataStructureArray = $this->flexFormTools->parseDataStructureByIdentifier($result['processedTca']['columns'][$fieldName]['config']['dataStructureIdentifier'], $result['tcaSchemata']->get($result['tableName']));
} catch (InvalidDataStructureException|InvalidIdentifierException|InvalidTcaSchemaException|UndefinedSchemaException) {
// Skip the data structure if it is invalid
}
}
if (!isset($dataStructureArray['meta']) || !is_array($dataStructureArray['meta'])) {
$dataStructureArray['meta'] = [];
}
// Finally add the resolved data Structure to "ds"
$result['processedTca']['columns'][$fieldName]['config']['ds'] = $dataStructureArray;
return $result;
}
/**
* Parse / initialize value from xml string to array
*/
protected function initializeDataValues(array $result, string $fieldName): array
{
$valueArray = [];
if (isset($result['databaseRow'][$fieldName]) && $result['databaseRow'][$fieldName] !== '') {
if (is_array($result['databaseRow'][$fieldName])) {
$valueArray = $result['databaseRow'][$fieldName];
} else {
$valueArray = GeneralUtility::xml2array($result['databaseRow'][$fieldName]);
if (!is_array($valueArray)) {
$valueArray = [];
}
}
}
$valueArray['data'] ??= [];
$valueArray['meta'] ??= [];
$result['databaseRow'][$fieldName] = $valueArray;
return $result;
}
}