TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
<?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!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Inspired by and partially taken from the Neos.Form package (www.neos.io)
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Form\Domain\Model\Renderable;
|
||||
|
||||
use TYPO3\CMS\Form\Domain\Model\Exception\FormDefinitionConsistencyException;
|
||||
|
||||
/**
|
||||
* Convenience base class which implements common functionality for most
|
||||
* classes which implement CompositeRenderableInterface, i.e. have **child renderable elements**.
|
||||
*
|
||||
* Scope: frontend
|
||||
* **This class is NOT meant to be sub classed by developers.**
|
||||
*/
|
||||
abstract class AbstractCompositeRenderable extends AbstractRenderable implements CompositeRenderableInterface
|
||||
{
|
||||
/**
|
||||
* array of child renderables
|
||||
*
|
||||
* @var \TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface[]
|
||||
*/
|
||||
protected $renderables = [];
|
||||
|
||||
/**
|
||||
* Add a renderable to the list of child renderables.
|
||||
*
|
||||
* This function will be wrapped by the subclasses, f.e. with an "addPage"
|
||||
* or "addElement" method with the correct type hint.
|
||||
*
|
||||
* @param RenderableInterface $renderable
|
||||
* @throws FormDefinitionConsistencyException
|
||||
* @internal
|
||||
*/
|
||||
protected function addRenderable(RenderableInterface $renderable)
|
||||
{
|
||||
if ($renderable->getParentRenderable() !== null) {
|
||||
throw new FormDefinitionConsistencyException(sprintf('The renderable with identifier "%s" is already added to another element (element identifier: "%s").', $renderable->getIdentifier(), $renderable->getParentRenderable()->getIdentifier()), 1325665144);
|
||||
}
|
||||
$renderable->setIndex(count($this->renderables));
|
||||
$renderable->setParentRenderable($this);
|
||||
$this->renderables[] = $renderable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move $renderableToMove before $referenceRenderable
|
||||
*
|
||||
* This function will be wrapped by the subclasses, f.e. with an "movePageBefore"
|
||||
* or "moveElementBefore" method with the correct type hint.
|
||||
*
|
||||
* @param RenderableInterface $renderableToMove
|
||||
* @param RenderableInterface $referenceRenderable
|
||||
* @throws FormDefinitionConsistencyException
|
||||
* @internal
|
||||
*/
|
||||
protected function moveRenderableBefore(RenderableInterface $renderableToMove, RenderableInterface $referenceRenderable)
|
||||
{
|
||||
if ($renderableToMove->getParentRenderable() !== $referenceRenderable->getParentRenderable() || $renderableToMove->getParentRenderable() !== $this) {
|
||||
throw new FormDefinitionConsistencyException('Moved renderables need to be part of the same parent element.', 1326089744);
|
||||
}
|
||||
|
||||
$reorderedRenderables = [];
|
||||
$i = 0;
|
||||
foreach ($this->renderables as $renderable) {
|
||||
if ($renderable === $renderableToMove) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($renderable === $referenceRenderable) {
|
||||
$reorderedRenderables[] = $renderableToMove;
|
||||
$renderableToMove->setIndex($i);
|
||||
$i++;
|
||||
}
|
||||
$reorderedRenderables[] = $renderable;
|
||||
$renderable->setIndex($i);
|
||||
$i++;
|
||||
}
|
||||
$this->renderables = $reorderedRenderables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move $renderableToMove after $referenceRenderable
|
||||
*
|
||||
* This function will be wrapped by the subclasses, f.e. with an "movePageAfter"
|
||||
* or "moveElementAfter" method with the correct type hint.
|
||||
*
|
||||
* @param RenderableInterface $renderableToMove
|
||||
* @param RenderableInterface $referenceRenderable
|
||||
* @throws FormDefinitionConsistencyException
|
||||
* @internal
|
||||
*/
|
||||
protected function moveRenderableAfter(RenderableInterface $renderableToMove, RenderableInterface $referenceRenderable)
|
||||
{
|
||||
if ($renderableToMove->getParentRenderable() !== $referenceRenderable->getParentRenderable() || $renderableToMove->getParentRenderable() !== $this) {
|
||||
throw new FormDefinitionConsistencyException('Moved renderables need to be part of the same parent element.', 1477083145);
|
||||
}
|
||||
|
||||
$reorderedRenderables = [];
|
||||
$i = 0;
|
||||
foreach ($this->renderables as $renderable) {
|
||||
if ($renderable === $renderableToMove) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$reorderedRenderables[] = $renderable;
|
||||
$renderable->setIndex($i);
|
||||
$i++;
|
||||
|
||||
if ($renderable === $referenceRenderable) {
|
||||
$reorderedRenderables[] = $renderableToMove;
|
||||
$renderableToMove->setIndex($i);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
$this->renderables = $reorderedRenderables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all RenderableInterface instances of this composite renderable recursively
|
||||
*
|
||||
* @return RenderableInterface[]
|
||||
* @internal
|
||||
*/
|
||||
public function getRenderablesRecursively(): array
|
||||
{
|
||||
$renderables = [];
|
||||
foreach ($this->renderables as $renderable) {
|
||||
$renderables[] = $renderable;
|
||||
if ($renderable instanceof CompositeRenderableInterface) {
|
||||
$renderables = array_merge($renderables, $renderable->getRenderablesRecursively());
|
||||
}
|
||||
}
|
||||
return $renderables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a renderable from this renderable.
|
||||
*
|
||||
* This function will be wrapped by the subclasses, f.e. with an "removePage"
|
||||
* or "removeElement" method with the correct type hint.
|
||||
*
|
||||
* @param RenderableInterface $renderableToRemove
|
||||
* @throws FormDefinitionConsistencyException
|
||||
* @internal
|
||||
*/
|
||||
protected function removeRenderable(RenderableInterface $renderableToRemove)
|
||||
{
|
||||
if ($renderableToRemove->getParentRenderable() !== $this) {
|
||||
throw new FormDefinitionConsistencyException('The renderable to be removed must be part of the calling parent renderable.', 1326090127);
|
||||
}
|
||||
|
||||
$updatedRenderables = [];
|
||||
foreach ($this->renderables as $renderable) {
|
||||
if ($renderable === $renderableToRemove) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$updatedRenderables[] = $renderable;
|
||||
}
|
||||
$this->renderables = $updatedRenderables;
|
||||
|
||||
$renderableToRemove->onRemoveFromParentRenderable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register this element at the parent form, if there is a connection to the parent form.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function registerInFormIfPossible()
|
||||
{
|
||||
parent::registerInFormIfPossible();
|
||||
foreach ($this->renderables as $renderable) {
|
||||
$renderable->registerInFormIfPossible();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called after a renderable has been removed from its parent
|
||||
* renderable.
|
||||
* This just passes the event down to all child renderables of this composite renderable.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function onRemoveFromParentRenderable()
|
||||
{
|
||||
foreach ($this->renderables as $renderable) {
|
||||
$renderable->onRemoveFromParentRenderable();
|
||||
}
|
||||
parent::onRemoveFromParentRenderable();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,448 @@
|
||||
<?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!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Inspired by and partially taken from the Neos.Form package (www.neos.io)
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Form\Domain\Model\Renderable;
|
||||
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Core\Cache\CacheManager;
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface;
|
||||
use TYPO3\CMS\Extbase\Validation\ValidatorResolver;
|
||||
use TYPO3\CMS\Form\Domain\Model\Exception\FormDefinitionConsistencyException;
|
||||
use TYPO3\CMS\Form\Domain\Model\Exception\ValidatorPresetNotFoundException;
|
||||
use TYPO3\CMS\Form\Domain\Model\FormDefinition;
|
||||
use TYPO3\CMS\Form\Event\BeforeRenderableIsRemovedFromFormEvent;
|
||||
|
||||
/**
|
||||
* Convenience base class which implements common functionality for most
|
||||
* classes which implement RenderableInterface.
|
||||
*
|
||||
* Scope: frontend
|
||||
* **This class is NOT meant to be sub classed by developers.**
|
||||
* @internal
|
||||
*/
|
||||
abstract class AbstractRenderable implements RenderableInterface, VariableRenderableInterface
|
||||
{
|
||||
/**
|
||||
* Abstract "type" of this Renderable. Is used during the rendering process
|
||||
* to determine the template file or the View PHP class being used to render
|
||||
* the particular element.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* The identifier of this renderable
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier;
|
||||
|
||||
/**
|
||||
* The parent renderable
|
||||
*/
|
||||
protected ?CompositeRenderableInterface $parentRenderable = null;
|
||||
|
||||
/**
|
||||
* The label of this renderable
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label = '';
|
||||
|
||||
/**
|
||||
* associative array of rendering options
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $renderingOptions = [];
|
||||
|
||||
/**
|
||||
* The position of this renderable inside the parent renderable.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $index = 0;
|
||||
|
||||
/**
|
||||
* The name of the template file of the renderable.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $templateName = '';
|
||||
|
||||
/**
|
||||
* associative array of rendering variants
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $variants = [];
|
||||
|
||||
protected ?ValidatorResolver $validatorResolver = null;
|
||||
|
||||
protected ?ServerRequestInterface $request = null;
|
||||
|
||||
/**
|
||||
* Get the type of the renderable
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the identifier of the element
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the identifier of the element
|
||||
*/
|
||||
public function setIdentifier(string $identifier)
|
||||
{
|
||||
$this->identifier = $identifier;
|
||||
}
|
||||
|
||||
public function getRequest(): ?ServerRequestInterface
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
public function setRequest(?ServerRequestInterface $request): void
|
||||
{
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set multiple properties of this object at once.
|
||||
* Every property which has a corresponding set* method can be set using
|
||||
* the passed $options array.
|
||||
*/
|
||||
public function setOptions(array $options, bool $resetValidators = false)
|
||||
{
|
||||
if (isset($options['label'])) {
|
||||
$this->setLabel($options['label']);
|
||||
}
|
||||
|
||||
if (isset($options['renderingOptions'])) {
|
||||
foreach ($options['renderingOptions'] as $key => $value) {
|
||||
$this->setRenderingOption($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['validators'])) {
|
||||
$runtimeCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('runtime');
|
||||
$configurationHashes = $runtimeCache->get('formAbstractRenderableConfigurationHashes') ?: [];
|
||||
|
||||
if ($resetValidators) {
|
||||
$this->getRootForm()->getProcessingRule($this->getIdentifier())->removeAllValidators();
|
||||
$configurationHashes = [];
|
||||
}
|
||||
|
||||
foreach ($options['validators'] as $validatorConfiguration) {
|
||||
$configurationHash = md5(
|
||||
spl_object_hash($this)
|
||||
. json_encode($validatorConfiguration)
|
||||
);
|
||||
if (in_array($configurationHash, $configurationHashes)) {
|
||||
continue;
|
||||
}
|
||||
$this->createValidator($validatorConfiguration['identifier'], $validatorConfiguration['options'] ?? []);
|
||||
$configurationHashes[] = $configurationHash;
|
||||
$runtimeCache->set('formAbstractRenderableConfigurationHashes', $configurationHashes);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['variants'])) {
|
||||
foreach ($options['variants'] as $variantConfiguration) {
|
||||
$this->createVariant($variantConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
ArrayUtility::assertAllArrayKeysAreValid(
|
||||
$options,
|
||||
['label', 'defaultValue', 'properties', 'renderingOptions', 'validators', 'formEditor', 'variants']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a validator for the element.
|
||||
*
|
||||
* @throws ValidatorPresetNotFoundException
|
||||
*/
|
||||
public function createValidator(string $validatorIdentifier, array $options = []): ?ValidatorInterface
|
||||
{
|
||||
$validatorsDefinition = $this->getRootForm()->getValidatorsDefinition();
|
||||
if (isset($validatorsDefinition[$validatorIdentifier]) && is_array($validatorsDefinition[$validatorIdentifier]) && isset($validatorsDefinition[$validatorIdentifier]['implementationClassName'])) {
|
||||
$implementationClassName = $validatorsDefinition[$validatorIdentifier]['implementationClassName'];
|
||||
$defaultOptions = $validatorsDefinition[$validatorIdentifier]['options'] ?? [];
|
||||
ArrayUtility::mergeRecursiveWithOverrule($defaultOptions, $options);
|
||||
// @todo: It would be great if Renderable's and FormElements could use DI, but especially
|
||||
// FormElements which extend AbstractRenderable pollute __construct() with manual
|
||||
// arguments. To retrieve the ValidatorResolver, we have to fall back to getContainer()
|
||||
// for now, until this has been resolved.
|
||||
if ($this->validatorResolver === null) {
|
||||
$container = GeneralUtility::getContainer();
|
||||
$this->validatorResolver = $container->get(ValidatorResolver::class);
|
||||
}
|
||||
$validator = $this->validatorResolver->createValidator($implementationClassName, $defaultOptions, $this->request);
|
||||
if ($validator !== null) {
|
||||
$this->addValidator($validator);
|
||||
}
|
||||
return $validator;
|
||||
}
|
||||
throw new ValidatorPresetNotFoundException('The validator preset identified by "' . $validatorIdentifier . '" could not be found, or the implementationClassName was not specified.', 1328710202);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a validator to the element.
|
||||
*/
|
||||
public function addValidator(ValidatorInterface $validator)
|
||||
{
|
||||
$formDefinition = $this->getRootForm();
|
||||
$formDefinition->getProcessingRule($this->getIdentifier())->addValidator($validator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all validators on the element
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getValidators(): \SplObjectStorage
|
||||
{
|
||||
$formDefinition = $this->getRootForm();
|
||||
return $formDefinition->getProcessingRule($this->getIdentifier())->getValidators();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the datatype
|
||||
*/
|
||||
public function setDataType(string $dataType)
|
||||
{
|
||||
$formDefinition = $this->getRootForm();
|
||||
$formDefinition->getProcessingRule($this->getIdentifier())->setDataType($dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the classname of the renderer
|
||||
*/
|
||||
public function getRendererClassName(): string
|
||||
{
|
||||
return $this->getRootForm()->getRendererClassName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all rendering options
|
||||
*/
|
||||
public function getRenderingOptions(): array
|
||||
{
|
||||
return $this->renderingOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the rendering option $key to $value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function setRenderingOption(string $key, $value)
|
||||
{
|
||||
if (is_array($value) && isset($this->renderingOptions[$key]) && is_array($this->renderingOptions[$key])) {
|
||||
ArrayUtility::mergeRecursiveWithOverrule($this->renderingOptions[$key], $value);
|
||||
$this->renderingOptions[$key] = ArrayUtility::removeNullValuesRecursive($this->renderingOptions[$key]);
|
||||
} elseif ($value === null) {
|
||||
unset($this->renderingOptions[$key]);
|
||||
} else {
|
||||
$this->renderingOptions[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent renderable
|
||||
*
|
||||
* @return CompositeRenderableInterface|null
|
||||
*/
|
||||
public function getParentRenderable()
|
||||
{
|
||||
return $this->parentRenderable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parent renderable
|
||||
*/
|
||||
public function setParentRenderable(CompositeRenderableInterface $parentRenderable)
|
||||
{
|
||||
$this->parentRenderable = $parentRenderable;
|
||||
$this->registerInFormIfPossible();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root form this element belongs to
|
||||
*
|
||||
* @throws FormDefinitionConsistencyException
|
||||
*/
|
||||
public function getRootForm(): FormDefinition
|
||||
{
|
||||
$rootRenderable = $this->parentRenderable;
|
||||
while ($rootRenderable !== null && !($rootRenderable instanceof FormDefinition)) {
|
||||
$rootRenderable = $rootRenderable->getParentRenderable();
|
||||
}
|
||||
if ($rootRenderable === null) {
|
||||
throw new FormDefinitionConsistencyException(sprintf('The form element "%s" is not attached to a parent form.', $this->identifier), 1326803398);
|
||||
}
|
||||
|
||||
return $rootRenderable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register this element at the parent form, if there is a connection to the parent form.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function registerInFormIfPossible()
|
||||
{
|
||||
try {
|
||||
$rootForm = $this->getRootForm();
|
||||
$rootForm->registerRenderable($this);
|
||||
} catch (FormDefinitionConsistencyException $exception) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when the renderable is removed from it's parent
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function onRemoveFromParentRenderable()
|
||||
{
|
||||
$event = GeneralUtility::makeInstance(EventDispatcherInterface::class)->dispatch(
|
||||
new BeforeRenderableIsRemovedFromFormEvent($this)
|
||||
);
|
||||
if ($event->isPropagationStopped()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$rootForm = $this->getRootForm();
|
||||
$rootForm->unregisterRenderable($this);
|
||||
} catch (FormDefinitionConsistencyException $exception) {
|
||||
}
|
||||
$this->parentRenderable = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of the renderable
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getIndex(): int
|
||||
{
|
||||
return $this->index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the index of the renderable
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function setIndex(int $index)
|
||||
{
|
||||
$this->index = $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the label of the renderable
|
||||
*/
|
||||
public function getLabel(): string
|
||||
{
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the label which shall be displayed next to the form element
|
||||
*/
|
||||
public function setLabel(string $label)
|
||||
{
|
||||
$this->label = $label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the templateName name of the renderable
|
||||
*/
|
||||
public function getTemplateName(): string
|
||||
{
|
||||
return empty($this->renderingOptions['templateName'])
|
||||
? $this->type
|
||||
: $this->renderingOptions['templateName'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this renderable is enabled
|
||||
*/
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return !isset($this->renderingOptions['enabled']) || (bool)$this->renderingOptions['enabled'] === true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all rendering variants
|
||||
*
|
||||
* @return RenderableVariantInterface[]
|
||||
*/
|
||||
public function getVariants(): array
|
||||
{
|
||||
return $this->variants;
|
||||
}
|
||||
|
||||
public function createVariant(array $options): RenderableVariantInterface
|
||||
{
|
||||
$identifier = $options['identifier'] ?? '';
|
||||
unset($options['identifier']);
|
||||
|
||||
$variant = GeneralUtility::makeInstance(RenderableVariant::class, $identifier, $options, $this);
|
||||
|
||||
$this->addVariant($variant);
|
||||
return $variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified variant to this form element
|
||||
*/
|
||||
public function addVariant(RenderableVariantInterface $variant)
|
||||
{
|
||||
$this->variants[$variant->getIdentifier()] = $variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the specified variant to this form element
|
||||
* regardless of their conditions
|
||||
*/
|
||||
public function applyVariant(RenderableVariantInterface $variant)
|
||||
{
|
||||
$variant->apply();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Inspired by and partially taken from the Neos.Form package (www.neos.io)
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Form\Domain\Model\Renderable;
|
||||
|
||||
/**
|
||||
* Interface which all Form Parts must adhere to **when they have sub elements**.
|
||||
* This includes especially "FormDefinition" and "Page".
|
||||
*
|
||||
* Scope: frontend
|
||||
* **This class is NOT meant to be sub classed by developers.**
|
||||
*/
|
||||
interface CompositeRenderableInterface extends RenderableInterface
|
||||
{
|
||||
/**
|
||||
* Returns all RenderableInterface instances of this composite renderable recursively
|
||||
*
|
||||
* @return \TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface[]
|
||||
* @internal
|
||||
*/
|
||||
public function getRenderablesRecursively(): array;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?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!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Inspired by and partially taken from the Neos.Form package (www.neos.io)
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Form\Domain\Model\Renderable;
|
||||
|
||||
/**
|
||||
* Base interface which all Form Parts except the FormDefinition must adhere
|
||||
* to (i.e. all elements which are NOT the root of a Form).
|
||||
*
|
||||
* Scope: frontend
|
||||
* **This class is NOT meant to be sub classed by developers.**
|
||||
*/
|
||||
interface RenderableInterface extends RootRenderableInterface
|
||||
{
|
||||
/**
|
||||
* Return the parent renderable
|
||||
*
|
||||
* @return CompositeRenderableInterface|null the parent renderable
|
||||
* @internal
|
||||
*/
|
||||
public function getParentRenderable();
|
||||
|
||||
/**
|
||||
* Set the new parent renderable. You should not call this directly;
|
||||
* it is automatically called by addRenderable.
|
||||
*
|
||||
* This method should also register itself at the parent form, if possible.
|
||||
*
|
||||
* @param CompositeRenderableInterface $renderable
|
||||
* @internal
|
||||
*/
|
||||
public function setParentRenderable(CompositeRenderableInterface $renderable);
|
||||
|
||||
/**
|
||||
* Set the index of this renderable inside the parent renderable
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function setIndex(int $index);
|
||||
|
||||
/**
|
||||
* Get the index inside the parent renderable
|
||||
*/
|
||||
public function getIndex(): int;
|
||||
|
||||
/**
|
||||
* This function is called after a renderable has been removed from its parent
|
||||
* renderable. The function should make sure to clean up the internal state,
|
||||
* like resetting $this->parentRenderable or deregistering the renderable
|
||||
* of the form.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function onRemoveFromParentRenderable();
|
||||
|
||||
/**
|
||||
* Register this element at the parent form, if there is a connection to the parent form.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function registerInFormIfPossible();
|
||||
|
||||
/**
|
||||
* Get the template name of the renderable
|
||||
*/
|
||||
public function getTemplateName(): string;
|
||||
|
||||
/**
|
||||
* Returns whether this renderable is enabled
|
||||
*/
|
||||
public function isEnabled(): bool;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?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\Form\Domain\Model\Renderable;
|
||||
|
||||
use TYPO3\CMS\Core\ExpressionLanguage\Resolver;
|
||||
use TYPO3\CMS\Form\Domain\Exception\IdentifierNotValidException;
|
||||
|
||||
/**
|
||||
* Scope: frontend
|
||||
* **This class is NOT meant to be sub classed by developers.**
|
||||
* @internal
|
||||
*/
|
||||
class RenderableVariant implements RenderableVariantInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* @var VariableRenderableInterface
|
||||
*/
|
||||
protected $renderable;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $condition = '';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $applied = false;
|
||||
|
||||
/**
|
||||
* @throws IdentifierNotValidException
|
||||
*/
|
||||
public function __construct(
|
||||
string $identifier,
|
||||
array $options,
|
||||
VariableRenderableInterface $renderable
|
||||
) {
|
||||
if ($identifier === '') {
|
||||
throw new IdentifierNotValidException('The given variant identifier was empty.', 1519998923);
|
||||
}
|
||||
$this->identifier = $identifier;
|
||||
$this->renderable = $renderable;
|
||||
|
||||
if (isset($options['condition']) && is_string($options['condition'])) {
|
||||
$this->condition = $options['condition'];
|
||||
}
|
||||
|
||||
unset($options['condition'], $options['identifier'], $options['variants']);
|
||||
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the specified variant to this form element
|
||||
* regardless of their conditions
|
||||
*/
|
||||
public function apply(): void
|
||||
{
|
||||
$this->renderable->setOptions($this->options, true);
|
||||
$this->applied = true;
|
||||
}
|
||||
|
||||
public function conditionMatches(Resolver $conditionResolver): bool
|
||||
{
|
||||
if (empty($this->condition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool)$conditionResolver->evaluate($this->condition, ['renderable' => $this->renderable]);
|
||||
}
|
||||
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
public function isApplied(): bool
|
||||
{
|
||||
return $this->applied;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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\Form\Domain\Model\Renderable;
|
||||
|
||||
use TYPO3\CMS\Core\ExpressionLanguage\Resolver;
|
||||
|
||||
/**
|
||||
* Scope: frontend
|
||||
* **This class is NOT meant to be sub classed by developers.**
|
||||
* @internal
|
||||
*/
|
||||
interface RenderableVariantInterface
|
||||
{
|
||||
public function getIdentifier(): string;
|
||||
|
||||
/**
|
||||
* Apply the specified variant to this form element
|
||||
* regardless of their conditions
|
||||
*/
|
||||
public function apply(): void;
|
||||
|
||||
public function isApplied(): bool;
|
||||
|
||||
public function conditionMatches(Resolver $conditionResolver): bool;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?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!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Inspired by and partially taken from the Neos.Form package (www.neos.io)
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Form\Domain\Model\Renderable;
|
||||
|
||||
/**
|
||||
* Base interface which all parts of a form must adhere to.
|
||||
*
|
||||
* Scope: frontend
|
||||
* **This class is NOT meant to be sub classed by developers.**
|
||||
*/
|
||||
interface RootRenderableInterface
|
||||
{
|
||||
/**
|
||||
* Abstract "type" of this Renderable. Is used during the rendering process
|
||||
* to determine the template file or the View PHP class being used to render
|
||||
* the particular element.
|
||||
*/
|
||||
public function getType(): string;
|
||||
|
||||
/**
|
||||
* The identifier of this renderable
|
||||
*/
|
||||
public function getIdentifier(): string;
|
||||
|
||||
/**
|
||||
* Get the label which shall be displayed next to the form element
|
||||
*/
|
||||
public function getLabel(): string;
|
||||
|
||||
/**
|
||||
* Get the renderer class name to be used to display this form;
|
||||
* must implement RendererInterface
|
||||
*
|
||||
* @return string the renderer class name
|
||||
*/
|
||||
public function getRendererClassName(): string;
|
||||
|
||||
/**
|
||||
* Get all rendering options
|
||||
*
|
||||
* @return array associative array of rendering options
|
||||
*/
|
||||
public function getRenderingOptions(): array;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?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!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Inspired by and partially taken from the Neos.Form package (www.neos.io)
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Form\Domain\Model\Renderable;
|
||||
|
||||
/**
|
||||
* Scope: frontend
|
||||
* **This class is NOT meant to be sub classed by developers.**
|
||||
*/
|
||||
interface VariableRenderableInterface
|
||||
{
|
||||
/**
|
||||
* Set multiple properties of this object at once.
|
||||
* Every property which has a corresponding set* method can be set using
|
||||
* the passed $options array.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function setOptions(array $options, bool $reset = false);
|
||||
|
||||
/**
|
||||
* Get all rendering variants
|
||||
*
|
||||
* @return RenderableVariantInterface[]
|
||||
*/
|
||||
public function getVariants(): array;
|
||||
|
||||
/**
|
||||
* Adds the specified variant to this form element
|
||||
*/
|
||||
public function addVariant(RenderableVariantInterface $variant);
|
||||
}
|
||||
Reference in New Issue
Block a user