[BUGFIX] EXT:form - Wizard does not reopen checkboxgroups/ radiogroups
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Classes / Utility / TypoScriptToJsonConverter.php
1 <?php
2 namespace TYPO3\CMS\Form\Utility;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\GeneralUtility;
18 use TYPO3\CMS\Form\Domain\Model\Json\AbstractJsonElement;
19
20 /**
21 * Typoscript to JSON converter
22 *
23 * Takes the incoming TypoScript and converts it to JSON.
24 */
25 class TypoScriptToJsonConverter {
26
27 protected $registeredElementNames = array(
28 'BUTTON',
29 'CHECKBOX',
30 'CHECKBOXGROUP',
31 'FIELDSET',
32 'FILEUPLOAD',
33 'HEADER',
34 'HIDDEN',
35 'IMAGEBUTTON',
36 'OPTGROUP',
37 'OPTION',
38 'PASSWORD',
39 'RADIO',
40 'RADIOGROUP',
41 'RESET',
42 'SELECT',
43 'SUBMIT',
44 'TEXTAREA',
45 'TEXTBLOCK',
46 'TEXTLINE'
47 );
48
49 /**
50 * @var array
51 */
52 protected $nameMapping = array(
53 'checkboxgroup' => 'CheckboxGroup',
54 'radiogroup' => 'RadioGroup',
55 );
56
57 /**
58 * @var array
59 */
60 protected $validationRules;
61
62 /**
63 * Convert TypoScript string to JSON
64 *
65 * @param array $typoscript TypoScript string containing all configuration for the form
66 * @return string The JSON for the form
67 */
68 public function convert(array $typoscript) {
69 $this->setValidationRules($typoscript);
70 $jsonObject = $this->createElement('form', $typoscript);
71 return $jsonObject;
72 }
73
74 /**
75 * Create element by loading class
76 * and instantiating the object
77 *
78 * @param string $class Type of element
79 * @param array $arguments Configuration array
80 * @return AbstractJsonElement
81 * @throws \RuntimeException
82 */
83 public function createElement($class, array $arguments = array()) {
84 $class = strtolower((string)$class);
85 if (!empty($this->nameMapping[$class])) {
86 $class = $this->nameMapping[$class];
87 }
88 $className = 'TYPO3\\CMS\\Form\\Domain\\Model\Json\\' . ucfirst($class) . 'JsonElement';
89 $this->addValidationRules($arguments);
90
91 if (!class_exists($className)) {
92 throw new \RuntimeException('Class "' . $className . '" does not exist', 1440779351);
93 }
94
95 /** @var $object AbstractJsonElement */
96 $object = GeneralUtility::makeInstance($className);
97 $object->setParameters($arguments);
98 if ($object->childElementsAllowed()) {
99 $this->getChildElementsByIntegerKey($object, $arguments);
100 }
101 return $object;
102 }
103
104 /**
105 * Rendering of a "numerical array" of Form objects from TypoScript
106 * Creates new object for each element found
107 *
108 * @param AbstractJsonElement $parentElement Parent model object
109 * @param array $typoscript Configuration array
110 * @return void
111 */
112 protected function getChildElementsByIntegerKey(AbstractJsonElement $parentElement, array $typoscript) {
113 if (is_array($typoscript)) {
114 $keys = \TYPO3\CMS\Core\TypoScript\TemplateService::sortedKeyList($typoscript);
115 foreach ($keys as $key) {
116 $class = $typoscript[$key];
117 if ((int)$key && strpos($key, '.') === FALSE) {
118 if (isset($typoscript[$key . '.'])) {
119 $elementArguments = $typoscript[$key . '.'];
120 } else {
121 $elementArguments = array();
122 }
123 $this->setElementType($parentElement, $class, $elementArguments);
124 }
125 }
126 }
127 }
128
129 /**
130 * Set the element type of the object
131 *
132 * Checks if the typoscript object is part of the FORM or has a predefined
133 * class for name or header object
134 *
135 * @param AbstractJsonElement $parentElement The parent object
136 * @param string $class A predefined class
137 * @param array $arguments Configuration array
138 * @return void
139 */
140 private function setElementType(AbstractJsonElement $parentElement, $class, array $arguments) {
141 if (in_array($class, $this->registeredElementNames)) {
142 if (strstr($arguments['class'], 'predefined-name')) {
143 $class = 'NAME';
144 }
145 $this->addElement($parentElement, $class, $arguments);
146 }
147 }
148
149 /**
150 * Add child object to this element
151 *
152 * @param AbstractJsonElement $parentElement The parent object
153 * @param string $class Type of element
154 * @param array $arguments Configuration array
155 * @return void
156 */
157 public function addElement(AbstractJsonElement $parentElement, $class, array $arguments) {
158 try {
159 $element = $this->createElement($class, $arguments);
160 $parentElement->addElement($element);
161 } catch (\RuntimeException $exception) {
162 // Catch missing classes or element types
163 // There are elements that can be used the
164 // TypoScript-like declaration, which don't
165 // have a counterpart in the ExtJS wizard.
166 }
167 }
168
169 /**
170 * Set the validation rules
171 *
172 * @param array $typoscript Configuration array
173 * @return void
174 */
175 protected function setValidationRules(array $typoscript) {
176 if (isset($typoscript['rules.']) && is_array($typoscript['rules.'])) {
177 $this->validationRules = $typoscript['rules.'];
178 }
179 }
180
181 /**
182 * Add validation rules to an element if available
183 *
184 * In TypoScript the validation rules belong to the form and are connected
185 * to the elements by name. However, in the wizard, they are added to the
186 * element for usability
187 *
188 * @param array $arguments The element arguments
189 * @return void
190 */
191 protected function addValidationRules(array &$arguments) {
192 if (!empty($this->validationRules) && isset($arguments['name'])) {
193 foreach ($this->validationRules as $key => $ruleName) {
194 if ((int)$key && strpos($key, '.') === FALSE) {
195 if (isset($this->validationRules[$key . '.'])) {
196 $ruleConfiguration = $this->validationRules[$key . '.'];
197 if (isset($ruleConfiguration['element']) && $ruleConfiguration['element'] === $arguments['name']) {
198 $arguments['validation'][$ruleName] = $ruleConfiguration;
199 }
200 }
201 }
202 }
203 }
204 }
205
206 }