‪TYPO3CMS  ‪main
FormDefinition.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
18 /*
19  * Inspired by and partially taken from the Neos.Form package (www.neos.io)
20  */
21 
23 
40 use ‪TYPO3\CMS\Form\Exception as FormException;
42 
224 {
230  protected ‪$renderables = [];
231 
237  protected $finishers = [];
238 
244  protected $processingRules = [];
245 
252  protected $elementsByIdentifier = [];
253 
259  protected $elementDefaultValues = [];
260 
266  protected $rendererClassName = '';
267 
271  protected $typeDefinitions;
272 
276  protected $validatorsDefinition;
277 
281  protected $finishersDefinition;
282 
288  protected $persistenceIdentifier;
289 
299  public function __construct(
300  string ‪$identifier,
301  array $prototypeConfiguration = [],
302  string ‪$type = 'Form',
303  string $persistenceIdentifier = null
304  ) {
305  $this->‪typeDefinitions = $prototypeConfiguration['formElementsDefinition'] ?? [];
306  $this->‪validatorsDefinition = $prototypeConfiguration['validatorsDefinition'] ?? [];
307  $this->finishersDefinition = $prototypeConfiguration['finishersDefinition'] ?? [];
308 
309  if (!is_string(‪$identifier) || strlen(‪$identifier) === 0) {
310  throw new ‪IdentifierNotValidException('The given identifier was not a string or the string was empty.', 1477082503);
311  }
312 
313  $this->identifier = ‪$identifier;
314  $this->type = ‪$type;
315  $this->persistenceIdentifier = (string)$persistenceIdentifier;
316 
317  if ($prototypeConfiguration !== []) {
319  }
320  }
321 
328  protected function ‪initializeFromFormDefaults()
329  {
330  if (!isset($this->‪typeDefinitions[$this->type])) {
331  throw new TypeDefinitionNotFoundException(sprintf('Type "%s" not found. Probably some configuration is missing.', $this->type), 1474905835);
332  }
333  $typeDefinition = $this->‪typeDefinitions[‪$this->type];
334  $this->‪setOptions($typeDefinition);
335  }
336 
344  public function ‪setOptions(array $options, bool $resetFinishers = false)
345  {
346  if (isset($options['rendererClassName'])) {
347  $this->‪setRendererClassName($options['rendererClassName']);
348  }
349  if (isset($options['label'])) {
350  $this->‪setLabel($options['label']);
351  }
352  if (isset($options['renderingOptions'])) {
353  foreach ($options['renderingOptions'] as $key => $value) {
354  $this->‪setRenderingOption($key, $value);
355  }
356  }
357  if (isset($options['finishers'])) {
358  if ($resetFinishers) {
359  $this->finishers = [];
360  }
361  foreach ($options['finishers'] as $finisherConfiguration) {
362  $this->‪createFinisher($finisherConfiguration['identifier'], $finisherConfiguration['options'] ?? []);
363  }
364  }
365 
366  if (isset($options['variants'])) {
367  foreach ($options['variants'] as $variantConfiguration) {
368  $this->‪createVariant($variantConfiguration);
369  }
370  }
371 
373  $options,
374  ['rendererClassName', 'renderingOptions', 'finishers', 'formEditor', 'label', 'variants']
375  );
376  }
377 
391  public function ‪createPage(string ‪$identifier, string $typeName = 'Page'): Page
392  {
393  if (!isset($this->‪typeDefinitions[$typeName])) {
394  throw new TypeDefinitionNotFoundException(sprintf('Type "%s" not found. Probably some configuration is missing.', $typeName), 1474905953);
395  }
396 
397  $typeDefinition = $this->‪typeDefinitions[$typeName];
398 
399  if (!isset($typeDefinition['implementationClassName'])) {
400  throw new TypeDefinitionNotFoundException(sprintf('The "implementationClassName" was not set in type definition "%s".', $typeName), 1477083126);
401  }
402  $implementationClassName = $typeDefinition['implementationClassName'];
403 
405  $page = GeneralUtility::makeInstance($implementationClassName, ‪$identifier, $typeName);
406 
407  if (isset($typeDefinition['label'])) {
408  $page->setLabel($typeDefinition['label']);
409  }
410 
411  if (isset($typeDefinition['renderingOptions'])) {
412  foreach ($typeDefinition['renderingOptions'] as $key => $value) {
413  $page->setRenderingOption($key, $value);
414  }
415  }
416 
417  if (isset($typeDefinition['variants'])) {
418  foreach ($typeDefinition['variants'] as $variantConfiguration) {
419  $page->createVariant($variantConfiguration);
420  }
421  }
422 
424  $typeDefinition,
425  ['implementationClassName', 'label', 'renderingOptions', 'formEditor', 'variants']
426  );
427 
428  $this->‪addPage($page);
429  return $page;
430  }
431 
441  public function ‪addPage(‪Page $page)
442  {
443  $this->‪addRenderable($page);
444  }
445 
451  public function getPages(): array
452  {
453  return ‪$this->renderables;
454  }
455 
461  public function ‪hasPageWithIndex(int ‪$index): bool
462  {
463  return isset($this->‪renderables[$index]);
464  }
465 
475  public function ‪getPageByIndex(int ‪$index)
476  {
477  if (!$this->‪hasPageWithIndex($index)) {
478  throw new FormException(sprintf('There is no page with an index of %d', ‪$index), 1329233627);
479  }
480  return $this->‪renderables[‪$index];
481  }
482 
486  public function ‪addFinisher(‪FinisherInterface $finisher)
487  {
488  $this->finishers[] = $finisher;
489  }
490 
496  public function ‪createFinisher(string $finisherIdentifier, array $options = []): ‪FinisherInterface
497  {
498  if (isset($this->finishersDefinition[$finisherIdentifier]) && is_array($this->finishersDefinition[$finisherIdentifier]) && isset($this->finishersDefinition[$finisherIdentifier]['implementationClassName'])) {
499  $implementationClassName = $this->finishersDefinition[$finisherIdentifier]['implementationClassName'];
500  $defaultOptions = $this->finishersDefinition[$finisherIdentifier]['options'] ?? [];
501  ArrayUtility::mergeRecursiveWithOverrule($defaultOptions, $options);
503  $finisher = GeneralUtility::makeInstance($implementationClassName);
504  $finisher->setFinisherIdentifier($finisherIdentifier);
505  $finisher->setOptions($defaultOptions);
506  $this->‪addFinisher($finisher);
507  return $finisher;
508  }
509  throw new ‪FinisherPresetNotFoundException('The finisher preset identified by "' . $finisherIdentifier . '" could not be found, or the implementationClassName was not specified.', 1328709784);
510  }
511 
517  public function ‪getFinishers(): array
518  {
519  return $this->finishers;
520  }
521 
528  public function ‪registerRenderable(‪RenderableInterface $renderable)
529  {
530  if ($renderable instanceof ‪FormElementInterface) {
531  if (isset($this->‪elementsByIdentifier[$renderable->‪getIdentifier()])) {
532  throw new ‪DuplicateFormElementException(sprintf('A form element with identifier "%s" is already part of the form.', $renderable->‪getIdentifier()), 1325663761);
533  }
534  $this->‪elementsByIdentifier[$renderable->‪getIdentifier()] = $renderable;
535  }
536  }
537 
543  public function ‪unregisterRenderable(RenderableInterface $renderable)
544  {
545  if ($renderable instanceof FormElementInterface) {
546  unset($this->‪elementsByIdentifier[$renderable->getIdentifier()]);
547  }
548  }
549 
555  public function getElements(): array
556  {
557  return $this->elementsByIdentifier;
558  }
559 
568  public function ‪getElementByIdentifier(string $elementIdentifier)
569  {
570  return $this->‪elementsByIdentifier[$elementIdentifier] ?? null;
571  }
572 
580  public function ‪addElementDefaultValue(string $elementIdentifier, $defaultValue)
581  {
582  $this->elementDefaultValues = ‪ArrayUtility::setValueByPath(
583  $this->elementDefaultValues,
584  $elementIdentifier,
585  $defaultValue,
586  '.'
587  );
588  }
589 
598  public function ‪getElementDefaultValueByIdentifier(string $elementIdentifier)
599  {
600  return ‪ObjectAccess::getPropertyPath($this->elementDefaultValues, $elementIdentifier);
601  }
602 
606  public function ‪movePageBefore(Page $pageToMove, Page $referencePage)
607  {
608  $this->‪moveRenderableBefore($pageToMove, $referencePage);
609  }
610 
614  public function ‪movePageAfter(Page $pageToMove, Page $referencePage)
615  {
616  $this->‪moveRenderableAfter($pageToMove, $referencePage);
617  }
618 
622  public function ‪removePage(Page $pageToRemove)
623  {
624  $this->‪removeRenderable($pageToRemove);
625  }
626 
631  public function ‪bind(RequestInterface $request): FormRuntime
632  {
633  $formRuntime = GeneralUtility::makeInstance(FormRuntime::class);
634  $formRuntime->setFormDefinition($this);
635  $formRuntime->setRequest($request);
636  $formRuntime->initialize();
637  return $formRuntime;
638  }
639 
640  public function ‪getProcessingRule(string $propertyPath): ProcessingRule
641  {
642  if (!isset($this->‪processingRules[$propertyPath])) {
643  $this->‪processingRules[$propertyPath] = GeneralUtility::makeInstance(ProcessingRule::class);
644  }
645  return $this->‪processingRules[$propertyPath];
646  }
647 
654  public function getProcessingRules(): array
655  {
656  return $this->processingRules;
657  }
658 
663  public function getTypeDefinitions(): array
664  {
665  return $this->typeDefinitions;
666  }
667 
672  public function getValidatorsDefinition(): array
673  {
674  return $this->validatorsDefinition;
675  }
676 
682  public function ‪getPersistenceIdentifier(): string
683  {
684  return $this->persistenceIdentifier;
685  }
686 
690  public function ‪setRendererClassName(string $rendererClassName)
691  {
692  $this->rendererClassName = $rendererClassName;
693  }
694 
698  public function ‪getRendererClassName(): string
699  {
700  return $this->rendererClassName;
701  }
702 }
‪TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable\$index
‪int $index
Definition: AbstractRenderable.php:79
‪TYPO3\CMS\Form\Domain\Model\Exception\FinisherPresetNotFoundException
Definition: FinisherPresetNotFoundException.php:26
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\typeDefinitions
‪array< string, function getTypeDefinitions():array { return $this-> typeDefinitions
Definition: FormDefinition.php:655
‪TYPO3\CMS\Form\Domain\Model\Exception\FormDefinitionConsistencyException
Definition: FormDefinitionConsistencyException.php:26
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime
Definition: FormRuntime.php:106
‪TYPO3\CMS\Form\Domain\Exception\TypeDefinitionNotFoundException
Definition: TypeDefinitionNotFoundException.php:30
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\addFinisher
‪addFinisher(FinisherInterface $finisher)
Definition: FormDefinition.php:476
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\removePage
‪removePage(Page $pageToRemove)
Definition: FormDefinition.php:612
‪TYPO3\CMS\Form\Domain\Model\Renderable\AbstractCompositeRenderable
Definition: AbstractCompositeRenderable.php:34
‪TYPO3\CMS\Form\Domain\Model\Renderable\AbstractCompositeRenderable\moveRenderableAfter
‪moveRenderableAfter(RenderableInterface $renderableToMove, RenderableInterface $referenceRenderable)
Definition: AbstractCompositeRenderable.php:108
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess\getPropertyPath
‪static mixed getPropertyPath(object|array $subject, string $propertyPath)
Definition: ObjectAccess.php:128
‪TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable\setRenderingOption
‪mixed setRenderingOption(string $key, $value)
Definition: AbstractRenderable.php:250
‪TYPO3\CMS\Form\Domain\Finishers\FinisherInterface
Definition: FinisherInterface.php:31
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\setOptions
‪setOptions(array $options, bool $resetFinishers=false)
Definition: FormDefinition.php:334
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\movePageAfter
‪movePageAfter(Page $pageToMove, Page $referencePage)
Definition: FormDefinition.php:604
‪TYPO3\CMS\Form\Domain\Model\Renderable\AbstractCompositeRenderable\removeRenderable
‪removeRenderable(RenderableInterface $renderableToRemove)
Definition: AbstractCompositeRenderable.php:162
‪TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable\setLabel
‪setLabel(string $label)
Definition: AbstractRenderable.php:368
‪TYPO3\CMS\Form\Domain\Exception\IdentifierNotValidException
Definition: IdentifierNotValidException.php:30
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\renderables
‪array< int, function getPages():array { return $this-> renderables
Definition: FormDefinition.php:443
‪TYPO3\CMS\Form\Domain\Model\Renderable\AbstractCompositeRenderable\moveRenderableBefore
‪moveRenderableBefore(RenderableInterface $renderableToMove, RenderableInterface $referenceRenderable)
Definition: AbstractCompositeRenderable.php:72
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\setRendererClassName
‪setRendererClassName(string $rendererClassName)
Definition: FormDefinition.php:680
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\createPage
‪Page createPage(string $identifier, string $typeName='Page')
Definition: FormDefinition.php:381
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\getPersistenceIdentifier
‪getPersistenceIdentifier()
Definition: FormDefinition.php:672
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\getProcessingRule
‪getProcessingRule(string $propertyPath)
Definition: FormDefinition.php:630
‪TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable\createVariant
‪createVariant(array $options)
Definition: AbstractRenderable.php:401
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\createFinisher
‪createFinisher(string $finisherIdentifier, array $options=[])
Definition: FormDefinition.php:486
‪TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable\$type
‪string $type
Definition: AbstractRenderable.php:49
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\hasPageWithIndex
‪bool hasPageWithIndex(int $index)
Definition: FormDefinition.php:451
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\bind
‪bind(RequestInterface $request)
Definition: FormDefinition.php:621
‪TYPO3\CMS\Extbase\Reflection\ObjectAccess
Definition: ObjectAccess.php:39
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\getElementDefaultValueByIdentifier
‪mixed getElementDefaultValueByIdentifier(string $elementIdentifier)
Definition: FormDefinition.php:588
‪TYPO3\CMS\Form\Domain\Model\FormElements\Page
Definition: Page.php:44
‪TYPO3\CMS\Form\Domain\Model\Renderable\RenderableInterface
Definition: RenderableInterface.php:32
‪TYPO3\CMS\Form\Domain\Model
‪TYPO3\CMS\Form\Exception
Definition: Exception.php:25
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\unregisterRenderable
‪unregisterRenderable(RenderableInterface $renderable)
Definition: FormDefinition.php:533
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\getElementByIdentifier
‪FormElementInterface null getElementByIdentifier(string $elementIdentifier)
Definition: FormDefinition.php:558
‪TYPO3\CMS\Form\Domain\Model\FormElements\FormElementInterface
Definition: FormElementInterface.php:40
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\getRendererClassName
‪getRendererClassName()
Definition: FormDefinition.php:688
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\validatorsDefinition
‪array< string, function getValidatorsDefinition():array { return $this-> validatorsDefinition
Definition: FormDefinition.php:664
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\addElementDefaultValue
‪addElementDefaultValue(string $elementIdentifier, $defaultValue)
Definition: FormDefinition.php:570
‪TYPO3\CMS\Form\Domain\Model\Renderable\AbstractCompositeRenderable\$renderables
‪TYPO3 CMS Form Domain Model Renderable RenderableInterface[] $renderables
Definition: AbstractCompositeRenderable.php:39
‪TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface\getIdentifier
‪getIdentifier()
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\getFinishers
‪list< FinisherInterface > getFinishers()
Definition: FormDefinition.php:507
‪TYPO3\CMS\Form\Domain\Model\FormDefinition
Definition: FormDefinition.php:224
‪TYPO3\CMS\Extbase\Mvc\RequestInterface
Definition: RequestInterface.php:24
‪TYPO3\CMS\Form\Domain\Model\Renderable\VariableRenderableInterface
Definition: VariableRenderableInterface.php:29
‪TYPO3\CMS\Form\Domain\Runtime\FormRuntime
Definition: FormSession.php:18
‪TYPO3\CMS\Core\Utility\ArrayUtility
Definition: ArrayUtility.php:26
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\addPage
‪addPage(Page $page)
Definition: FormDefinition.php:431
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\processingRules
‪array< string, function getProcessingRules():array { return $this-> processingRules
Definition: FormDefinition.php:646
‪TYPO3\CMS\Core\Utility\ArrayUtility\assertAllArrayKeysAreValid
‪static assertAllArrayKeysAreValid(array $arrayToTest, array $allowedArrayKeys)
Definition: ArrayUtility.php:33
‪TYPO3\CMS\Form\Domain\Model\Renderable\AbstractRenderable\$identifier
‪string $identifier
Definition: AbstractRenderable.php:55
‪TYPO3\CMS\Core\Utility\ArrayUtility\setValueByPath
‪static array setValueByPath(array $array, string|array|\ArrayAccess $path, mixed $value, string $delimiter='/')
Definition: ArrayUtility.php:261
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\initializeFromFormDefaults
‪array< int, $renderables=array();protected list< FinisherInterface > $finishers=array();protected array< string, $processingRules=array();protected array< string, $elementsByIdentifier=array();protected array< string, $elementDefaultValues=array();protected string $rendererClassName='';protected array< string, $typeDefinitions;protected array< string, $validatorsDefinition;protected array< string, $finishersDefinition;protected string $persistenceIdentifier;public __construct(string $identifier, array $prototypeConfiguration=[], string $type='Form', string $persistenceIdentifier=null) { $this->typeDefinitions=$prototypeConfiguration[ 'formElementsDefinition'] ??[];$this->validatorsDefinition=$prototypeConfiguration[ 'validatorsDefinition'] ??[];$this->finishersDefinition=$prototypeConfiguration[ 'finishersDefinition'] ??[];if(!is_string( $identifier)||strlen( $identifier)===0) { throw new IdentifierNotValidException( 'The given identifier was not a string or the string was empty.', 1477082503);} $this->identifier=$identifier;$this->type=$type;$this->persistenceIdentifier=(string) $persistenceIdentifier;if( $prototypeConfiguration !==[]) { $this-> initializeFromFormDefaults()
‪TYPO3\CMS\Form\Domain\Model\Renderable\AbstractCompositeRenderable\addRenderable
‪addRenderable(RenderableInterface $renderable)
Definition: AbstractCompositeRenderable.php:51
‪TYPO3\CMS\Form\Domain\Model\Exception\DuplicateFormElementException
Definition: DuplicateFormElementException.php:26
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\elementsByIdentifier
‪array< string, function getElements():array { return $this-> elementsByIdentifier
Definition: FormDefinition.php:547
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\movePageBefore
‪movePageBefore(Page $pageToMove, Page $referencePage)
Definition: FormDefinition.php:596
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\getPageByIndex
‪Page getPageByIndex(int $index)
Definition: FormDefinition.php:465
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\registerRenderable
‪registerRenderable(RenderableInterface $renderable)
Definition: FormDefinition.php:518
‪TYPO3\CMS\Form\Mvc\ProcessingRule
Definition: ProcessingRule.php:36
‪TYPO3\CMS\Form\Domain\Model\FormDefinition\initializeFromFormDefaults
‪initializeFromFormDefaults()
Definition: FormDefinition.php:318