TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
<?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\FormElements;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Extbase\Validation\Validator\NotEmptyValidator;
|
||||
use TYPO3\CMS\Form\Domain\Exception\IdentifierNotValidException;
|
||||
use TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable;
|
||||
|
||||
/**
|
||||
* A base form element, which is the starting point for creating custom (PHP-based)
|
||||
* Form Elements.
|
||||
*
|
||||
* A *FormElement* is a part of a *Page*, which in turn is part of a FormDefinition.
|
||||
* See {@link FormDefinition} for an in-depth explanation.
|
||||
*
|
||||
* Subclassing this class is a good starting-point for implementing custom PHP-based
|
||||
* Form Elements.
|
||||
*
|
||||
* Most of the functionality and API is implemented in {@link \TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable}, so
|
||||
* make sure to check out this class as well.
|
||||
*
|
||||
* Still, it is quite rare that you need to subclass this class; often
|
||||
* you can just use the {@link \TYPO3\CMS\Form\Domain\Model\FormElements\GenericFormElement} and replace some templates.
|
||||
*
|
||||
* Scope: frontend
|
||||
* **This class is meant to be sub classed by developers.**
|
||||
*/
|
||||
abstract class AbstractFormElement extends AbstractRenderable implements FormElementInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $properties = [];
|
||||
|
||||
/**
|
||||
* Constructor. Needs this FormElement's identifier and the FormElement type
|
||||
*
|
||||
* @param string $identifier The FormElement's identifier
|
||||
* @param string $type The Form Element Type
|
||||
* @throws IdentifierNotValidException
|
||||
*/
|
||||
public function __construct(string $identifier, string $type)
|
||||
{
|
||||
if (strlen($identifier) === 0) {
|
||||
throw new IdentifierNotValidException('The given identifier string is empty.', 1477082502);
|
||||
}
|
||||
$this->identifier = $identifier;
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method in your custom FormElements if needed
|
||||
*/
|
||||
public function initializeFormElement() {}
|
||||
|
||||
/**
|
||||
* Get the global unique identifier of the element
|
||||
*/
|
||||
public function getUniqueIdentifier(): string
|
||||
{
|
||||
$formDefinition = $this->getRootForm();
|
||||
$uniqueIdentifier = sprintf('%s-%s', $formDefinition->getIdentifier(), $this->identifier);
|
||||
$uniqueIdentifier = (string)preg_replace('/[^a-zA-Z0-9_-]/', '_', $uniqueIdentifier);
|
||||
return lcfirst($uniqueIdentifier);
|
||||
}
|
||||
|
||||
public function setOptions(array $options, bool $resetValidators = false)
|
||||
{
|
||||
if (isset($options['defaultValue'])) {
|
||||
$this->setDefaultValue($options['defaultValue']);
|
||||
}
|
||||
|
||||
if (isset($options['properties'])) {
|
||||
foreach ($options['properties'] as $key => $value) {
|
||||
$this->setProperty($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
parent::setOptions($options, $resetValidators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default value of the element
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefaultValue()
|
||||
{
|
||||
$formDefinition = $this->getRootForm();
|
||||
return $formDefinition->getElementDefaultValueByIdentifier($this->identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default value of the element
|
||||
*
|
||||
* @param mixed $defaultValue
|
||||
*/
|
||||
public function setDefaultValue($defaultValue)
|
||||
{
|
||||
$formDefinition = $this->getRootForm();
|
||||
$currentDefaultValue = $formDefinition->getElementDefaultValueByIdentifier($this->identifier);
|
||||
if (is_array($currentDefaultValue) && is_array($defaultValue)) {
|
||||
ArrayUtility::mergeRecursiveWithOverrule($currentDefaultValue, $defaultValue);
|
||||
$defaultValue = ArrayUtility::removeNullValuesRecursive($currentDefaultValue);
|
||||
}
|
||||
$formDefinition->addElementDefaultValue($this->identifier, $defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the element is required
|
||||
*/
|
||||
public function isRequired(): bool
|
||||
{
|
||||
foreach ($this->getValidators() as $validator) {
|
||||
if ($validator instanceof NotEmptyValidator) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a property of the element
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setProperty(string $key, $value)
|
||||
{
|
||||
if (is_array($value) && isset($this->properties[$key]) && is_array($this->properties[$key])) {
|
||||
ArrayUtility::mergeRecursiveWithOverrule($this->properties[$key], $value);
|
||||
$this->properties[$key] = ArrayUtility::removeNullValuesRecursive($this->properties[$key]);
|
||||
} elseif ($value === null) {
|
||||
unset($this->properties[$key]);
|
||||
} else {
|
||||
$this->properties[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all properties
|
||||
*/
|
||||
public function getProperties(): array
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
<?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\FormElements;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Form\Domain\Exception\IdentifierNotValidException;
|
||||
use TYPO3\CMS\Form\Domain\Exception\TypeDefinitionNotFoundException;
|
||||
use TYPO3\CMS\Form\Domain\Exception\TypeDefinitionNotValidException;
|
||||
use TYPO3\CMS\Form\Domain\Model\Exception\FormDefinitionConsistencyException;
|
||||
use TYPO3\CMS\Form\Domain\Model\Renderable\AbstractCompositeRenderable;
|
||||
|
||||
/**
|
||||
* A base class for "section-like" form parts like "Page" or "Section" (which
|
||||
* is rendered as "Fieldset")
|
||||
*
|
||||
* This class contains multiple FormElements ({@link FormElementInterface}).
|
||||
*
|
||||
* Please see {@link FormDefinition} for an in-depth explanation.
|
||||
*
|
||||
* **This class is NOT meant to be sub classed by developers.**
|
||||
* Scope: frontend
|
||||
*/
|
||||
abstract class AbstractSection extends AbstractCompositeRenderable
|
||||
{
|
||||
/**
|
||||
* @var FormElementInterface[]
|
||||
*/
|
||||
protected $renderables = [];
|
||||
|
||||
/**
|
||||
* Constructor. Needs the identifier and type of this element
|
||||
*
|
||||
* @param string $identifier The Section identifier
|
||||
* @param string $type The Section type
|
||||
* @throws IdentifierNotValidException if the identifier was no non-empty string
|
||||
*/
|
||||
public function __construct(string $identifier, string $type)
|
||||
{
|
||||
if ($identifier === '') {
|
||||
throw new IdentifierNotValidException('The given identifier was empty.', 1477082501);
|
||||
}
|
||||
|
||||
$this->identifier = $identifier;
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the child Form Elements
|
||||
*
|
||||
* @return FormElementInterface[] The Page's elements
|
||||
*/
|
||||
public function getElements(): array
|
||||
{
|
||||
return $this->renderables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the child Form Elements
|
||||
*
|
||||
* @return FormElementInterface[] The Page's elements
|
||||
*/
|
||||
public function getElementsRecursively(): array
|
||||
{
|
||||
return $this->getRenderablesRecursively();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new form element at the end of the section
|
||||
*
|
||||
* @param FormElementInterface $formElement The form element to add
|
||||
* @throws FormDefinitionConsistencyException if FormElement is already added to a section
|
||||
*/
|
||||
public function addElement(FormElementInterface $formElement)
|
||||
{
|
||||
$this->addRenderable($formElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a form element with the given $identifier and attach it to this section/page.
|
||||
*
|
||||
* - Create Form Element object based on the given $typeName
|
||||
* - set defaults inside the Form Element (based on the parent form's field defaults)
|
||||
* - attach Form Element to this Section/Page
|
||||
* - return the newly created Form Element object
|
||||
*
|
||||
*
|
||||
* @param string $identifier Identifier of the new form element
|
||||
* @param string $typeName type of the new form element
|
||||
* @return FormElementInterface the newly created form element
|
||||
* @throws TypeDefinitionNotFoundException
|
||||
* @throws TypeDefinitionNotValidException
|
||||
*/
|
||||
public function createElement(string $identifier, string $typeName): FormElementInterface
|
||||
{
|
||||
$formDefinition = $this->getRootForm();
|
||||
|
||||
$typeDefinitions = $formDefinition->getTypeDefinitions();
|
||||
if (isset($typeDefinitions[$typeName])) {
|
||||
$typeDefinition = $typeDefinitions[$typeName];
|
||||
} else {
|
||||
$renderingOptions = $formDefinition->getRenderingOptions();
|
||||
$skipUnknownElements = isset($renderingOptions['skipUnknownElements']) && $renderingOptions['skipUnknownElements'] === true;
|
||||
if (!$skipUnknownElements) {
|
||||
throw new TypeDefinitionNotFoundException(sprintf('Type "%s" not found. Probably some configuration is missing.', $typeName), 1382364019);
|
||||
}
|
||||
|
||||
$element = GeneralUtility::makeInstance(UnknownFormElement::class, $identifier, $typeName);
|
||||
$this->addElement($element);
|
||||
return $element;
|
||||
}
|
||||
|
||||
if (!isset($typeDefinition['implementationClassName'])) {
|
||||
throw new TypeDefinitionNotFoundException(sprintf('The "implementationClassName" was not set in type definition "%s".', $typeName), 1325689855);
|
||||
}
|
||||
|
||||
$implementationClassName = $typeDefinition['implementationClassName'];
|
||||
$element = GeneralUtility::makeInstance($implementationClassName, $identifier, $typeName);
|
||||
if (!$element instanceof FormElementInterface) {
|
||||
throw new TypeDefinitionNotValidException(sprintf('The "implementationClassName" for element "%s" ("%s") does not implement the FormElementInterface.', $identifier, $implementationClassName), 1327318156);
|
||||
}
|
||||
unset($typeDefinition['implementationClassName']);
|
||||
|
||||
$this->addElement($element);
|
||||
$element->setOptions($typeDefinition);
|
||||
|
||||
$element->initializeFormElement();
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move FormElement $element before $referenceElement.
|
||||
*
|
||||
* Both $element and $referenceElement must be direct descendants of this Section/Page.
|
||||
*
|
||||
* @param FormElementInterface $elementToMove
|
||||
* @param FormElementInterface $referenceElement
|
||||
*/
|
||||
public function moveElementBefore(FormElementInterface $elementToMove, FormElementInterface $referenceElement)
|
||||
{
|
||||
$this->moveRenderableBefore($elementToMove, $referenceElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move FormElement $element after $referenceElement
|
||||
*
|
||||
* Both $element and $referenceElement must be direct descendants of this Section/Page.
|
||||
*
|
||||
* @param FormElementInterface $elementToMove
|
||||
* @param FormElementInterface $referenceElement
|
||||
*/
|
||||
public function moveElementAfter(FormElementInterface $elementToMove, FormElementInterface $referenceElement)
|
||||
{
|
||||
$this->moveRenderableAfter($elementToMove, $referenceElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove $elementToRemove from this Section/Page
|
||||
*/
|
||||
public function removeElement(FormElementInterface $elementToRemove)
|
||||
{
|
||||
$this->removeRenderable($elementToRemove);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?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\FormElements;
|
||||
|
||||
use TYPO3\CMS\Extbase\Property\TypeConverter\DateTimeConverter;
|
||||
|
||||
/**
|
||||
* A date form element
|
||||
*
|
||||
* Scope: frontend
|
||||
*/
|
||||
class Date extends AbstractFormElement implements StringableFormElementInterface
|
||||
{
|
||||
/**
|
||||
* Initializes the Form Element by setting the data type to "DateTime"
|
||||
* @internal
|
||||
*/
|
||||
public function initializeFormElement()
|
||||
{
|
||||
$this->setDataType(\DateTime::class);
|
||||
/** @var \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration $propertyMappingConfiguration */
|
||||
$propertyMappingConfiguration = $this->getRootForm()->getProcessingRule($this->getIdentifier())->getPropertyMappingConfiguration();
|
||||
// @see https://www.w3.org/TR/2011/WD-html-markup-20110405/input.date.html#input.date.attrs.value
|
||||
// 'Y-m-d' = https://tools.ietf.org/html/rfc3339#section-5.6 -> full-date
|
||||
$propertyMappingConfiguration->setTypeConverterOption(DateTimeConverter::class, DateTimeConverter::CONFIGURATION_DATE_FORMAT, 'Y-m-d');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateTime $value
|
||||
*/
|
||||
public function valueToString($value): string
|
||||
{
|
||||
$dateFormat = $this->properties['displayFormat'] ?? 'Y-m-d';
|
||||
|
||||
return $value->format($dateFormat);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?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\FormElements;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception\FolderDoesNotExistException;
|
||||
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
|
||||
use TYPO3\CMS\Form\Mvc\Property\TypeConverter\UploadedFileReferenceConverter;
|
||||
|
||||
/**
|
||||
* A generic file upload form element
|
||||
*
|
||||
* Scope: frontend
|
||||
*/
|
||||
class FileUpload extends AbstractFormElement
|
||||
{
|
||||
/**
|
||||
* Initializes the Form Element by setting the data type to an Extbase File Reference
|
||||
* @internal
|
||||
*/
|
||||
public function initializeFormElement()
|
||||
{
|
||||
$this->setDataType(FileReference::class);
|
||||
|
||||
// Set the property mapping configuration for the file upload element.
|
||||
// * Add the UploadedFileReferenceConverter to convert an uploaded file to a
|
||||
// FileReference (single upload) or ObjectStorage (multiple uploads).
|
||||
// * Setup the storage:
|
||||
// If the property "saveToFileMount" exist for this element it will be used.
|
||||
// If this file mount or the property "saveToFileMount" does not exist
|
||||
// the default storage "1:/user_uploads/" will be used. Uploads are placed
|
||||
// in a dedicated sub-folder (e.g. ".../form_<40-chars-hash>/actual.file").
|
||||
$typeConverter = GeneralUtility::makeInstance(UploadedFileReferenceConverter::class);
|
||||
/** @var \TYPO3\CMS\Extbase\Property\PropertyMappingConfiguration $propertyMappingConfiguration */
|
||||
$propertyMappingConfiguration = $this->getRootForm()
|
||||
->getProcessingRule($this->getIdentifier())
|
||||
->getPropertyMappingConfiguration()
|
||||
->setTypeConverter($typeConverter);
|
||||
|
||||
$uploadConfiguration = [
|
||||
UploadedFileReferenceConverter::CONFIGURATION_UPLOAD_CONFLICT_MODE => 'rename',
|
||||
];
|
||||
|
||||
// In preview mode (Form Editor backend module), skip upload folder resolution
|
||||
// entirely. File uploads are non-functional during preview and resolving the
|
||||
// target folder may throw access permission exceptions for backend users who
|
||||
// do not have access to the configured upload storage.
|
||||
if (!($this->getRootForm()->getRenderingOptions()['previewMode'] ?? false)) {
|
||||
$saveToFileMountIdentifier = $this->getProperties()['saveToFileMount'] ?? '';
|
||||
if ($this->checkSaveFileMountAccess($saveToFileMountIdentifier)) {
|
||||
$uploadConfiguration[UploadedFileReferenceConverter::CONFIGURATION_UPLOAD_FOLDER] = $saveToFileMountIdentifier;
|
||||
} else {
|
||||
// @todo Why should uploaded files be stored to the same directory as the *.form.yaml definitions?
|
||||
$persistenceIdentifier = $this->getRootForm()->getPersistenceIdentifier();
|
||||
if (!empty($persistenceIdentifier)) {
|
||||
$pathinfo = PathUtility::pathinfo($persistenceIdentifier);
|
||||
$saveToFileMountIdentifier = $pathinfo['dirname'];
|
||||
if ($this->checkSaveFileMountAccess($saveToFileMountIdentifier)) {
|
||||
$uploadConfiguration[UploadedFileReferenceConverter::CONFIGURATION_UPLOAD_FOLDER] = $saveToFileMountIdentifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$propertyMappingConfiguration->setTypeConverterOptions(UploadedFileReferenceConverter::class, $uploadConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
protected function checkSaveFileMountAccess(string $saveToFileMountIdentifier): bool
|
||||
{
|
||||
if (empty($saveToFileMountIdentifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PathUtility::isExtensionPath($saveToFileMountIdentifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||
|
||||
try {
|
||||
$resourceFactory->getFolderObjectFromCombinedIdentifier($saveToFileMountIdentifier);
|
||||
return true;
|
||||
} catch (\InvalidArgumentException|InsufficientFolderAccessPermissionsException|FolderDoesNotExistException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?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\FormElements;
|
||||
|
||||
use TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface;
|
||||
use TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface;
|
||||
|
||||
/**
|
||||
* A base form element interface, which can be the starting point for creating
|
||||
* custom (PHP-based) Form Elements.
|
||||
*
|
||||
* A *FormElement* is a part of a *Page*, which in turn is part of a FormDefinition.
|
||||
* See {@link FormDefinition} for an in-depth explanation.
|
||||
*
|
||||
* **Often, you should rather subclass {@link AbstractFormElement} instead of
|
||||
* implementing this interface.**
|
||||
*
|
||||
* Scope: frontend
|
||||
*/
|
||||
interface FormElementInterface extends RenderableInterface
|
||||
{
|
||||
/**
|
||||
* Will be called as soon as the element is (tried to be) added to a form
|
||||
* @see registerInFormIfPossible()
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function initializeFormElement();
|
||||
|
||||
/**
|
||||
* Returns a unique identifier of this element.
|
||||
* While element identifiers are only unique within one form,
|
||||
* this includes the identifier of the form itself, making it "globally" unique
|
||||
*
|
||||
* @return string the "globally" unique identifier of this element
|
||||
*/
|
||||
public function getUniqueIdentifier(): string;
|
||||
|
||||
/**
|
||||
* Get the default value with which the Form Element should be initialized
|
||||
* during display.
|
||||
*
|
||||
* @return mixed the default value for this Form Element
|
||||
*/
|
||||
public function getDefaultValue();
|
||||
|
||||
/**
|
||||
* Set the default value with which the Form Element should be initialized
|
||||
* during display.
|
||||
*
|
||||
* @param mixed $defaultValue the default value for this Form Element
|
||||
*/
|
||||
public function setDefaultValue($defaultValue);
|
||||
|
||||
/**
|
||||
* Set an element-specific configuration property.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setProperty(string $key, $value);
|
||||
|
||||
/**
|
||||
* Get all element-specific configuration properties
|
||||
*/
|
||||
public function getProperties(): array;
|
||||
|
||||
/**
|
||||
* Set a rendering option
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setRenderingOption(string $key, $value);
|
||||
|
||||
/**
|
||||
* Returns the child validators of the ConjunctionValidator that is registered for this element
|
||||
*
|
||||
* @return \SplObjectStorage<ValidatorInterface>
|
||||
* @internal
|
||||
*/
|
||||
public function getValidators(): \SplObjectStorage;
|
||||
|
||||
/**
|
||||
* Registers a validator for this element
|
||||
*/
|
||||
public function addValidator(ValidatorInterface $validator);
|
||||
|
||||
/**
|
||||
* Set the target data type for this element
|
||||
*
|
||||
* @param string $dataType the target data type
|
||||
*/
|
||||
public function setDataType(string $dataType);
|
||||
|
||||
/**
|
||||
* Whether or not this element is required
|
||||
*/
|
||||
public function isRequired(): bool;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?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\FormElements;
|
||||
|
||||
/**
|
||||
* A generic form element
|
||||
*
|
||||
* Scope: frontend
|
||||
*/
|
||||
class GenericFormElement extends AbstractFormElement {}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?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\FormElements;
|
||||
|
||||
/**
|
||||
* A grid column, being part of a grid container
|
||||
*
|
||||
* This class contains multiple FormElements ({@link FormElementInterface}).
|
||||
*
|
||||
* Please see {@link FormDefinition} for an in-depth explanation.
|
||||
*
|
||||
* Scope: frontend
|
||||
* **This class is NOT meant to be sub classed by developers.**
|
||||
*/
|
||||
class GridColumn extends Section implements GridColumnInterface {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?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\FormElements;
|
||||
|
||||
/**
|
||||
* Scope: frontend
|
||||
*/
|
||||
interface GridColumnInterface extends FormElementInterface {}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?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\FormElements;
|
||||
|
||||
/**
|
||||
* A grid row, being part of a grid container
|
||||
*
|
||||
* This class contains multiple FormElements ({@link FormElementInterface}).
|
||||
*
|
||||
* Please see {@link FormDefinition} for an in-depth explanation.
|
||||
*
|
||||
* Scope: frontend
|
||||
* **This class is NOT meant to be sub classed by developers.**
|
||||
*/
|
||||
class GridRow extends Section implements GridRowInterface {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?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\FormElements;
|
||||
|
||||
/**
|
||||
* Scope: frontend
|
||||
*/
|
||||
interface GridRowInterface extends FormElementInterface {}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?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\FormElements;
|
||||
|
||||
use TYPO3\CMS\Form\Domain\Model\FormDefinition;
|
||||
use TYPO3\CMS\Form\Domain\Model\Renderable\CompositeRenderableInterface;
|
||||
use TYPO3\CMS\Form\Exception as FormException;
|
||||
|
||||
/**
|
||||
* A Page, being part of a bigger FormDefinition. It contains numerous FormElements
|
||||
* as children.
|
||||
*
|
||||
* A FormDefinition consists of multiple Pages, where only one page is visible
|
||||
* at any given time.
|
||||
*
|
||||
* Most of the API of this object is implemented in {@link AbstractSection},
|
||||
* so make sure to review this class as well.
|
||||
*
|
||||
* Please see {@link FormDefinition} for an in-depth explanation.
|
||||
*
|
||||
* Scope: frontend
|
||||
* **This class is NOT meant to be sub classed by developers.**
|
||||
*/
|
||||
class Page extends AbstractSection
|
||||
{
|
||||
/**
|
||||
* Constructor. Needs this Page's identifier
|
||||
*
|
||||
* @param string $identifier The Page's identifier
|
||||
* @param string $type The Page's type
|
||||
* @throws \TYPO3\CMS\Form\Domain\Exception\IdentifierNotValidException if the identifier was no non-empty string
|
||||
*/
|
||||
public function __construct(string $identifier, string $type = 'Page')
|
||||
{
|
||||
parent::__construct($identifier, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parent renderable
|
||||
*
|
||||
* @throws FormException
|
||||
*/
|
||||
public function setParentRenderable(CompositeRenderableInterface $parentRenderable)
|
||||
{
|
||||
if (!($parentRenderable instanceof FormDefinition)) {
|
||||
throw new FormException(sprintf('The specified parentRenderable must be a FormDefinition, got "%s"', get_debug_type($parentRenderable)), 1329233747);
|
||||
}
|
||||
parent::setParentRenderable($parentRenderable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
<?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\FormElements;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Extbase\Validation\Validator\NotEmptyValidator;
|
||||
|
||||
/**
|
||||
* A Section, being part of a bigger Page
|
||||
*
|
||||
* This class contains multiple FormElements ({@link FormElementInterface}).
|
||||
*
|
||||
* Please see {@link FormDefinition} for an in-depth explanation.
|
||||
*
|
||||
* Scope: frontend
|
||||
* **This class is NOT meant to be sub classed by developers.**
|
||||
*/
|
||||
class Section extends AbstractSection implements FormElementInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $properties = [];
|
||||
|
||||
/**
|
||||
* Will be called as soon as the element is (tried to be) added to a form
|
||||
* @see registerInFormIfPossible()
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function initializeFormElement() {}
|
||||
|
||||
public function setOptions(array $options, bool $resetValidators = false)
|
||||
{
|
||||
if (isset($options['properties'])) {
|
||||
foreach ($options['properties'] as $key => $value) {
|
||||
$this->setProperty($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
parent::setOptions($options, $resetValidators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique identifier of this element.
|
||||
* While element identifiers are only unique within one form,
|
||||
* this includes the identifier of the form itself, making it "globally" unique
|
||||
*
|
||||
* @return string the "globally" unique identifier of this element
|
||||
*/
|
||||
public function getUniqueIdentifier(): string
|
||||
{
|
||||
$formDefinition = $this->getRootForm();
|
||||
return sprintf('%s-%s', $formDefinition->getIdentifier(), $this->identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default value with which the Form Element should be initialized
|
||||
* during display.
|
||||
* Note: This is currently not used for section elements
|
||||
*
|
||||
* @return mixed the default value for this Form Element
|
||||
*/
|
||||
public function getDefaultValue()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default value with which the Form Element should be initialized
|
||||
* during display.
|
||||
* Note: This is currently ignored for section elements
|
||||
*
|
||||
* @param mixed $defaultValue the default value for this Form Element
|
||||
*/
|
||||
public function setDefaultValue($defaultValue) {}
|
||||
|
||||
/**
|
||||
* Get all element-specific configuration properties
|
||||
*/
|
||||
public function getProperties(): array
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an element-specific configuration property.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setProperty(string $key, $value)
|
||||
{
|
||||
if (is_array($value) && isset($this->properties[$key]) && is_array($this->properties[$key])) {
|
||||
ArrayUtility::mergeRecursiveWithOverrule($this->properties[$key], $value);
|
||||
$this->properties[$key] = ArrayUtility::removeNullValuesRecursive($this->properties[$key]);
|
||||
} elseif ($value === null) {
|
||||
unset($this->properties[$key]);
|
||||
} else {
|
||||
$this->properties[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this element is required
|
||||
*/
|
||||
public function isRequired(): bool
|
||||
{
|
||||
foreach ($this->getValidators() as $validator) {
|
||||
if ($validator instanceof NotEmptyValidator) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?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\FormElements;
|
||||
|
||||
/**
|
||||
* Interface for form elements capable of converting their complex values to string
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
interface StringableFormElementInterface
|
||||
{
|
||||
public function valueToString($value): string;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?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\FormElements;
|
||||
|
||||
use TYPO3\CMS\Form\Domain\Exception\IdentifierNotValidException;
|
||||
use TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable;
|
||||
|
||||
/**
|
||||
* A Form Element that has no definition.
|
||||
*
|
||||
* Scope: frontend
|
||||
*/
|
||||
class UnknownFormElement extends AbstractRenderable implements FormElementInterface
|
||||
{
|
||||
/**
|
||||
* Constructor. Needs this FormElement's identifier and the FormElement type
|
||||
*
|
||||
* @param string $identifier The FormElement's identifier
|
||||
* @param string $type The Form Element Type
|
||||
* @throws IdentifierNotValidException
|
||||
*/
|
||||
public function __construct(string $identifier, string $type)
|
||||
{
|
||||
if ($identifier === '') {
|
||||
throw new IdentifierNotValidException('The given identifier was empty.', 1382364370);
|
||||
}
|
||||
$this->identifier = $identifier;
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the form element
|
||||
*/
|
||||
public function initializeFormElement() {}
|
||||
|
||||
/**
|
||||
* Returns a unique identifier of this element.
|
||||
* While element identifiers are only unique within one form,
|
||||
* this includes the identifier of the form itself, making it "globally" unique
|
||||
*
|
||||
* @return string the "globally" unique identifier of this element
|
||||
*/
|
||||
public function getUniqueIdentifier(): string
|
||||
{
|
||||
$formDefinition = $this->getRootForm();
|
||||
$uniqueIdentifier = sprintf('%s-%s', $formDefinition->getIdentifier(), $this->identifier);
|
||||
$uniqueIdentifier = (string)preg_replace('/[^a-zA-Z0-9-_]/', '_', $uniqueIdentifier);
|
||||
return lcfirst($uniqueIdentifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the template name of the renderable
|
||||
*/
|
||||
public function getTemplateName(): string
|
||||
{
|
||||
return 'UnknownElement';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed the default value for this Form Element
|
||||
* @internal
|
||||
*/
|
||||
public function getDefaultValue()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not used in this implementation
|
||||
*
|
||||
* @param mixed $defaultValue the default value for this Form Element
|
||||
* @internal
|
||||
*/
|
||||
public function setDefaultValue($defaultValue) {}
|
||||
|
||||
/**
|
||||
* Not used in this implementation
|
||||
*
|
||||
* @param mixed $value
|
||||
* @internal
|
||||
*/
|
||||
public function setProperty(string $key, $value) {}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function getProperties(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function isRequired(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user