[TASK] Show speaking exception message if form definition is invalid
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Classes / Domain / Factory / ArrayFormFactory.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Form\Domain\Factory;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It originated from the Neos.Form package (www.neos.io)
9 *
10 * It is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU General Public License, either version 2
12 * of the License, or any later version.
13 *
14 * For the full copyright and license information, please read the
15 * LICENSE.txt file that was distributed with this source code.
16 *
17 * The TYPO3 project - inspiring people to share!
18 */
19
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Extbase\Object\ObjectManager;
22 use TYPO3\CMS\Form\Domain\Configuration\ConfigurationService;
23 use TYPO3\CMS\Form\Domain\Exception\IdentifierNotValidException;
24 use TYPO3\CMS\Form\Domain\Exception\RenderingException;
25 use TYPO3\CMS\Form\Domain\Exception\UnknownCompositRenderableException;
26 use TYPO3\CMS\Form\Domain\Model\FormDefinition;
27 use TYPO3\CMS\Form\Domain\Model\FormElements\AbstractSection;
28 use TYPO3\CMS\Form\Domain\Model\Renderable\CompositeRenderableInterface;
29
30 /**
31 * A factory that creates a FormDefinition from an array
32 *
33 * Scope: frontend / backend
34 */
35 class ArrayFormFactory extends AbstractFormFactory
36 {
37
38 /**
39 * Build a form definition, depending on some configuration.
40 *
41 * @param array $configuration
42 * @param string $prototypeName
43 * @return FormDefinition
44 * @throws RenderingException
45 * @internal
46 */
47 public function build(array $configuration, string $prototypeName = null): FormDefinition
48 {
49 if (empty($prototypeName)) {
50 $prototypeName = $configuration['prototypeName'] ?? 'standard';
51 }
52 $persistenceIdentifier = $configuration['persistenceIdentifier'] ?? null;
53
54 if ($configuration['invalid'] === true) {
55 throw new RenderingException($configuration['label'], 1529710560);
56 }
57
58 $prototypeConfiguration = GeneralUtility::makeInstance(ObjectManager::class)
59 ->get(ConfigurationService::class)
60 ->getPrototypeConfiguration($prototypeName);
61
62 $form = GeneralUtility::makeInstance(ObjectManager::class)->get(
63 FormDefinition::class,
64 $configuration['identifier'],
65 $prototypeConfiguration,
66 'Form',
67 $persistenceIdentifier
68 );
69 if (isset($configuration['renderables'])) {
70 foreach ($configuration['renderables'] as $pageConfiguration) {
71 $this->addNestedRenderable($pageConfiguration, $form);
72 }
73 }
74
75 unset($configuration['persistenceIdentifier']);
76 unset($configuration['prototypeName']);
77 unset($configuration['renderables']);
78 unset($configuration['type']);
79 unset($configuration['identifier']);
80 $form->setOptions($configuration);
81
82 $this->triggerFormBuildingFinished($form);
83
84 return $form;
85 }
86
87 /**
88 * Add form elements to the $parentRenderable
89 *
90 * @param array $nestedRenderableConfiguration
91 * @param CompositeRenderableInterface $parentRenderable
92 * @return mixed
93 * @throws IdentifierNotValidException
94 * @throws UnknownCompositRenderableException
95 */
96 protected function addNestedRenderable(array $nestedRenderableConfiguration, CompositeRenderableInterface $parentRenderable)
97 {
98 if (!isset($nestedRenderableConfiguration['identifier'])) {
99 throw new IdentifierNotValidException('Identifier not set.', 1329289436);
100 }
101 if ($parentRenderable instanceof FormDefinition) {
102 $renderable = $parentRenderable->createPage($nestedRenderableConfiguration['identifier'], $nestedRenderableConfiguration['type']);
103 } elseif ($parentRenderable instanceof AbstractSection) {
104 $renderable = $parentRenderable->createElement($nestedRenderableConfiguration['identifier'], $nestedRenderableConfiguration['type']);
105 } else {
106 throw new UnknownCompositRenderableException('Unknown composit renderable "' . get_class($parentRenderable) . '"', 1479593622);
107 }
108
109 if (isset($nestedRenderableConfiguration['renderables']) && is_array($nestedRenderableConfiguration['renderables'])) {
110 $childRenderables = $nestedRenderableConfiguration['renderables'];
111 } else {
112 $childRenderables = [];
113 }
114
115 unset($nestedRenderableConfiguration['type']);
116 unset($nestedRenderableConfiguration['identifier']);
117 unset($nestedRenderableConfiguration['renderables']);
118
119 $renderable->setOptions($nestedRenderableConfiguration);
120
121 if ($renderable instanceof CompositeRenderableInterface) {
122 foreach ($childRenderables as $elementConfiguration) {
123 $this->addNestedRenderable($elementConfiguration, $renderable);
124 }
125 }
126
127 return $renderable;
128 }
129 }