[BUGFIX] Wrong content element rendering in system extension form
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Classes / Domain / Factory / Typoscript.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2008 Patrick Broens (patrick@patrickbroens.nl)
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 *
17 * This script is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
24
25 /**
26 * Typoscript factory for form
27 *
28 * Takes the incoming Typoscipt and adds all the necessary form objects
29 * according to the configuration.
30 *
31 * @author Patrick Broens <patrick@patrickbroens.nl>
32 * @package TYPO3
33 * @subpackage form
34 */
35 class tx_form_Domain_Factory_Typoscript implements t3lib_Singleton {
36 /**
37 * @var tslib_cObj
38 */
39 protected $localContentObject;
40
41 /**
42 * Build model from Typoscript
43 *
44 * @param array $typoscript Typoscript containing all configuration
45 * @return tx_form_Domain_Model_Form The form object containing the child elements
46 */
47 public function buildModelFromTyposcript(array $typoscript) {
48 $this->setLayoutHandler($typoscript);
49
50 $form = $this->createElement('form', $typoscript);
51
52 return $form;
53 }
54
55 /**
56 * Rendering of a "numerical array" of Form objects from TypoScript
57 * Creates new object for each element found
58 *
59 * @param tx_form_Domain_Model_Element_Abstract $parentElement Parent model object
60 * @param array $arguments Configuration array
61 * @throws Exception
62 * @return void
63 */
64 public function getChildElementsByIntegerKey(tx_form_Domain_Model_Element_Abstract $parentElement, array $typoscript) {
65 if (is_array($typoscript)) {
66 $keys = t3lib_TStemplate::sortedKeyList($typoscript);
67 foreach ($keys as $key) {
68 $class = $typoscript[$key];
69 if (intval($key) && !strstr($key, '.')) {
70 if (isset($typoscript[$key . '.'])) {
71 $elementArguments = $typoscript[$key . '.'];
72 } else {
73 $elementArguments = array();
74 }
75 $this->setElementType($parentElement, $class, $elementArguments);
76 }
77 }
78 } else {
79 throw new Exception ('Container element with id=' . $parentElement->getElementId() . ' has no configuration which means no children');
80 }
81 }
82
83 /**
84 * Create and add element by type.
85 * This can be a derived Typoscript object by "<",
86 * a form element, or a regular Typoscript object.
87 *
88 * @param tx_form_Domain_Model_Element_Abstract $parentElement The parent for the new element
89 * @param string $class Classname for the element
90 * @param array $arguments Configuration array
91 * @return void
92 */
93 public function setElementType(tx_form_Domain_Model_Element_Abstract $parentElement, $class, array $arguments) {
94 if (substr($class, 0, 1) == '<') {
95 $key = trim(substr($class, 1));
96 /** @var $typoscriptParser t3lib_TSparser */
97 $typoscriptParser = t3lib_div::makeInstance('t3lib_TSparser');
98 $oldArguments = $arguments;
99 list($class, $arguments) = $typoscriptParser->getVal($key, $GLOBALS['TSFE']->tmpl->setup);
100 if (is_array($oldArguments) && count($oldArguments)) {
101 $arguments = $this->getLocalConentObject()->joinTSarrays($arguments, $oldArguments);
102 }
103 $GLOBALS['TT']->incStackPointer();
104 $contentObject = array(
105 'cObj' => $class,
106 'cObj.' => $arguments,
107 );
108 $this->addElement($parentElement, 'content', $contentObject);
109 $GLOBALS['TT']->decStackPointer();
110 } elseif (in_array($class, tx_form_Common::getInstance()->getFormObjects())) {
111 try {
112 $this->addElement($parentElement, $class, $arguments);
113 } catch (Exception $exception) {
114 throw $exception;
115 }
116 } else {
117 $contentObject = array(
118 'cObj' => $class,
119 'cObj.' => $arguments,
120 );
121 $this->addElement($parentElement, 'content', $contentObject);
122 }
123 }
124
125 /**
126 * Add child object to this element
127 *
128 * @param tx_form_Domain_Model_Element_Abstract $parentElement Parent model object
129 * @param string $class Type of element
130 * @param array $arguments Configuration array
131 * @return object
132 */
133 public function addElement(tx_form_Domain_Model_Element_Abstract $parentElement, $class, array $arguments = array()) {
134 $element = $this->createElement($class, $arguments);
135 $parentElement->addElement($element);
136 }
137
138 /**
139 * Create element by loading class
140 * and instantiating the object
141 *
142 * @param string $class Type of element
143 * @param array $arguments Configuration array
144 * @return tx_form_Domain_Model_Element_Abstract
145 */
146 public function createElement($class, array $arguments = array()) {
147 $class = strtolower((string) $class);
148
149 if ($class === 'form') {
150 $className = 'tx_form_Domain_Model_' . ucfirst($class);
151 } else {
152 $className = 'tx_form_Domain_Model_Element_' . ucfirst($class);
153 }
154
155 /** @var $object tx_form_Domain_Model_Element_Abstract */
156 $object = t3lib_div::makeInstance($className);
157
158 if ($class === 'content') {
159 $object->setData($arguments['cObj'], $arguments['cObj.']);
160 } else {
161 $object->setData($arguments['data']);
162 $this->reconstituteElement($object, $arguments);
163 }
164
165 return $object;
166 }
167
168 /**
169 * Reconstitutes the domain model of the accordant element.
170 *
171 * @param tx_form_Domain_Model_Element_Abstract $element
172 * @param array $arguments Configuration array
173 * @return void
174 */
175 protected function reconstituteElement(tx_form_Domain_Model_Element_Abstract $element, array $arguments = array()) {
176 $this->setAttributes($element, $arguments);
177 $this->setAdditionals($element, $arguments);
178
179 if (isset($arguments['filters.'])) {
180 $this->setFilters($element, $arguments['filters.']);
181 }
182
183 $element->setLayout($arguments['layout']);
184 $element->setValue($arguments['value']);
185 $element->setName($arguments['name']);
186
187 $element->setMessagesFromValidation();
188 $element->setErrorsFromValidation();
189 $element->checkFilterAndSetIncomingDataFromRequest();
190
191 $this->getChildElementsByIntegerKey($element, $arguments);
192 }
193
194 /**
195 * Set the attributes
196 *
197 * @param tx_form_Domain_Model_Element_Abstract $element Model object
198 * @param array $arguments Arguments
199 * @return void
200 */
201 public function setAttributes(tx_form_Domain_Model_Element_Abstract $element, array $arguments) {
202 if ($element->hasAllowedAttributes()) {
203 $attributes = $element->getAllowedAttributes();
204 $mandatoryAttributes = $element->getMandatoryAttributes();
205 foreach ($attributes as $attribute => $value) {
206 if (
207 isset($arguments[$attribute]) ||
208 isset($arguments[$attribute . '.']) ||
209 in_array($attribute, $mandatoryAttributes) ||
210 !empty($value)
211 ) {
212 if (!empty($arguments[$attribute])) {
213 $value = $arguments[$attribute];
214 } elseif (!empty($arguments[$attribute . '.'])) {
215 $value = $arguments[$attribute . '.'];
216 }
217
218 try {
219 $element->setAttribute($attribute, $value);
220 } catch (Exception $exception) {
221 throw new Exception ('Cannot call user function for attribute ' . ucfirst($attribute));
222 }
223 }
224 }
225 } else {
226 throw new Exception ('The element with id=' . $element->getElementId() . ' has no default attributes set');
227 }
228 }
229
230 /**
231 * Set the additionals from Element Typoscript configuration
232 *
233 * @param tx_form_Domain_Model_Element_Abstract $element Model object
234 * @param array $arguments Arguments
235 * @return void
236 */
237 public function setAdditionals(tx_form_Domain_Model_Element_Abstract $element, array $arguments) {
238 if (!empty($arguments)) {
239 if ($element->hasAllowedAdditionals()) {
240 $additionals = $element->getAllowedAdditionals();
241 foreach ($additionals as $additional) {
242 if (isset($arguments[$additional . '.']) || isset($arguments[$additional])) {
243 if (isset($arguments[$additional]) && isset($arguments[$additional . '.'])) {
244 $value = $arguments[$additional . '.'];
245 $type = $arguments[$additional];
246 } elseif (isset($arguments[$additional . '.'])) {
247 $value = $arguments[$additional . '.'];
248 $type = 'TEXT';
249 } else {
250 $value['value'] = $arguments[$additional];
251 $type = 'TEXT';
252 }
253
254 try {
255 $element->setAdditional($additional, $type, $value);
256 } catch (Exception $exception) {
257 throw new Exception ('Cannot call user function for additional ' . ucfirst($additional));
258 }
259 }
260 if (isset($arguments['layout.'][$additional]) && $element->additionalIsSet($additional)) {
261 $layout = $arguments['layout.'][$additional];
262 $element->setAdditionalLayout($additional, $layout);
263 }
264 }
265 } else {
266 throw new Exception ('The element with id=' . $element->getElementId() . ' has no additionals set');
267 }
268 }
269 }
270
271 /**
272 * Add the filters according to the settings in the Typoscript array
273 *
274 * @param tx_form_Domain_Model_Element_Abstract $element Model object
275 * @param array $arguments TypoScript
276 * @return void
277 */
278 protected function setFilters(tx_form_Domain_Model_Element_Abstract $element, array $arguments) {
279 $keys = t3lib_TStemplate::sortedKeyList($arguments);
280 foreach ($keys as $key) {
281 $class = $arguments[$key];
282 if (intval($key) && !strstr($key, '.')) {
283 $filterArguments = $arguments[$key . '.'];
284 $filter = $element->makeFilter($class, $filterArguments);
285 $element->addFilter($filter);
286 }
287 }
288 }
289
290 /**
291 * Set the layout handler
292 *
293 * @param array $typoscript TypoScript
294 * @return tx_form_System_Layout The layout handler
295 */
296 public function setLayoutHandler(array $typoscript) {
297 /** @var $layoutHandler tx_form_System_Layout */
298 $layoutHandler = t3lib_div::makeInstance('tx_form_System_Layout'); // singleton
299
300 if (isset($typoscript['layout.'])) {
301 $layoutHandler->setLayout($typoscript['layout.']);
302 }
303
304 return $layoutHandler;
305 }
306
307 /**
308 * Set the request handler
309 *
310 * @param array $typoscript TypoScript
311 * @return tx_form_System_Request The request handler
312 */
313 public function setRequestHandler($typoscript) {
314 $prefix = isset($typoscript['prefix']) ? $typoscript['prefix'] : '';
315 $method = isset($typoscript['method']) ? $typoscript['method'] : '';
316
317 /** @var $requestHandler tx_form_System_Request */
318 $requestHandler = t3lib_div::makeInstance('tx_form_System_Request'); // singleton
319 $requestHandler->setPrefix($prefix);
320 $requestHandler->setMethod($method);
321 $requestHandler->storeFiles();
322
323 return $requestHandler;
324 }
325
326 /**
327 * Set the validation rules
328 *
329 * Makes the validation object and adds rules to it
330 *
331 * @param array $typoscript TypoScript
332 * @return tx_form_System_Validate The validation object
333 */
334 public function setRules(array $typoscript) {
335 $rulesTyposcript = isset($typoscript['rules.']) ? $typoscript['rules.'] : NULL;
336 /** @var $rulesClass tx_form_System_Validate */
337 $rulesClass = t3lib_div::makeInstance('tx_form_System_Validate', $rulesTyposcript); // singleton
338
339 if (is_array($rulesTyposcript)) {
340 $keys = t3lib_TStemplate::sortedKeyList($rulesTyposcript);
341 foreach ($keys as $key) {
342 $class = $rulesTyposcript[$key];
343 if (intval($key) && !strstr($key, '.')) {
344 $elementArguments = $rulesTyposcript[$key . '.'];
345 $rule = $rulesClass->createRule($class, $elementArguments);
346 $rule->setFieldName($elementArguments['element']);
347 $breakOnError = isset($elementArguments['breakOnError']) ? $elementArguments['breakOnError'] : FALSE;
348 $rulesClass->addRule($rule, $elementArguments['element'], $breakOnError);
349 }
350 }
351 }
352
353 return $rulesClass;
354 }
355
356 /**
357 * Gets the local content object.
358 *
359 * @return tslib_cObj
360 */
361 protected function getLocalConentObject() {
362 if (!isset($this->localContentObject)) {
363 $this->localContentObject = t3lib_div::makeInstance('tslib_cObj');
364 }
365 return $this->localContentObject;
366 }
367 }
368 ?>