TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
<?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\Domain;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use TYPO3\CMS\Core\Domain\Exception\FlexFieldPropertyException;
|
||||
use TYPO3\CMS\Core\Domain\Exception\FlexFieldPropertyNotFoundException;
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
|
||||
/**
|
||||
* Represents a record's flex form field values.
|
||||
*
|
||||
* @internal not part of public API, as this needs to be streamlined and proven
|
||||
*/
|
||||
class FlexFormFieldValues implements ContainerInterface, \ArrayAccess
|
||||
{
|
||||
public function __construct(
|
||||
protected array $sheets
|
||||
) {}
|
||||
|
||||
public function get(string $id)
|
||||
{
|
||||
if (!$this->has($id)) {
|
||||
throw new FlexFieldPropertyNotFoundException('Flex property "' . $id . '" is not available.', 1731962637);
|
||||
}
|
||||
|
||||
[$sheetName, $propertyPath] = $this->processId($id);
|
||||
|
||||
if ($sheetName === '' && $this->hasMultipleSheets()) {
|
||||
// Get the sheet name for the requested property path - There is one, since has() returned true.
|
||||
foreach ($this->sheets as $name => $sheet) {
|
||||
if (ArrayUtility::isValidPath($sheet, $propertyPath, '.')) {
|
||||
$sheetName = $name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$propertyValue = ArrayUtility::getValueByPath($this->sheets[$sheetName], $propertyPath, '.');
|
||||
if (is_array($propertyValue)) {
|
||||
array_walk_recursive($propertyValue, fn(mixed &$value): mixed => $value = $this->resolveRecordPropertyClosure($propertyPath, $value));
|
||||
} else {
|
||||
$propertyValue = $this->resolveRecordPropertyClosure($propertyPath, $propertyValue);
|
||||
}
|
||||
ArrayUtility::setValueByPath($this->sheets[$sheetName], $propertyPath, $propertyValue, '.');
|
||||
return $propertyValue;
|
||||
}
|
||||
|
||||
public function has(string $id): bool
|
||||
{
|
||||
// If there are no sheets, no value can be determined.
|
||||
if ($this->sheets === []) {
|
||||
return false;
|
||||
}
|
||||
|
||||
[$sheetName, $propertyPath] = $this->processId($id);
|
||||
|
||||
if ($sheetName !== '' && !isset($this->sheets[$sheetName])) {
|
||||
// Given sheet name does not exist
|
||||
return false;
|
||||
}
|
||||
if ($this->hasMultipleSheets()) {
|
||||
if ($sheetName !== '') {
|
||||
return ArrayUtility::isValidPath($this->sheets[$sheetName], $propertyPath, '.');
|
||||
}
|
||||
// In case no sheet name is given, we try to execute fallback handling
|
||||
// by searching for the requested $propertyPath in all sheets.
|
||||
$occurences = [];
|
||||
foreach ($this->sheets as $sheetName => $sheet) {
|
||||
if (ArrayUtility::isValidPath($sheet, $propertyPath, '.')) {
|
||||
$occurences[$sheetName] = $propertyPath;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($occurences) > 1) {
|
||||
// This is a special case, which we handle with an exception to create awareness for the error.
|
||||
throw new FlexFieldPropertyException('Given id is ambigious since the field exists in multiple sheets and no sheet is defined.', 1731962638);
|
||||
}
|
||||
// Whether the requested $propertyPath name exist in a sheet
|
||||
return count($occurences) === 1;
|
||||
}
|
||||
|
||||
// Standard case, whether the $propertyPath exists in the given sheet name
|
||||
return ArrayUtility::isValidPath($this->sheets[$sheetName], $propertyPath, '.');
|
||||
}
|
||||
|
||||
public function offsetExists(mixed $offset): bool
|
||||
{
|
||||
return $this->has($offset);
|
||||
}
|
||||
|
||||
public function offsetGet(mixed $offset): mixed
|
||||
{
|
||||
return $this->get($offset);
|
||||
}
|
||||
|
||||
public function offsetSet(mixed $offset, mixed $value): void
|
||||
{
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
public function offsetUnset(mixed $offset): void
|
||||
{
|
||||
// Not implemented
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter to be used in fluid for accessing field values
|
||||
*/
|
||||
public function getSheets(): array
|
||||
{
|
||||
return $this->sheets;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return $this->getSheets();
|
||||
}
|
||||
|
||||
protected function hasMultipleSheets(): bool
|
||||
{
|
||||
return count($this->sheets) > 1;
|
||||
}
|
||||
|
||||
protected function processId(string $id): array
|
||||
{
|
||||
if (str_contains($id, '/')) {
|
||||
// $id contains a sheet name
|
||||
return explode('/', $id, 2);
|
||||
}
|
||||
if ($this->hasMultipleSheets()) {
|
||||
// $id does not contain a sheet name while there are multiple sheets. Therefore, we
|
||||
// return an empty sheet name. This allows executing fallback handling in has() and get().
|
||||
return ['', $id];
|
||||
}
|
||||
|
||||
// In case the $id does not contain a sheet name, but we have a
|
||||
// single sheet flex form, we fall back to this name automatically.
|
||||
return [key($this->sheets), $id];
|
||||
}
|
||||
|
||||
protected function resolveRecordPropertyClosure(string $id, mixed $propertyValue): mixed
|
||||
{
|
||||
if ($propertyValue instanceof RecordPropertyClosure) {
|
||||
try {
|
||||
$propertyValue = $propertyValue->instantiate();
|
||||
} catch (\Exception $e) {
|
||||
// Consumers of this method can rely on catching ContainerExceptionInterface
|
||||
throw new FlexFieldPropertyException(
|
||||
'An exception occurred while instantiating flex field property "' . $id . '"',
|
||||
1731962735,
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
return $propertyValue;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user