9bac977500d0d7f3e1241532746f64fb09a511c7
[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 const PROPERTY_DisableContentElement = 'disableContentElement';
37
38 /**
39 * @var tslib_cObj
40 */
41 protected $localContentObject;
42
43 /**
44 * @var boolean
45 */
46 protected $disableContentElement = FALSE;
47
48 /**
49 * Build model from Typoscript
50 *
51 * @param array $typoscript Typoscript containing all configuration
52 * @return tx_form_Domain_Model_Form The form object containing the child elements
53 */
54 public function buildModelFromTyposcript(array $typoscript) {
55 if (isset($typoscript[self::PROPERTY_DisableContentElement])) {
56 $this->setDisableContentElement($typoscript[self::PROPERTY_DisableContentElement]);
57 }
58
59 $this->setLayoutHandler($typoscript);
60
61 $form = $this->createElement('form', $typoscript);
62
63 return $form;
64 }
65
66 /**
67 * Disables the content element.
68 *
69 * @param boolean $disableContentElement
70 * @return void
71 */
72 public function setDisableContentElement($disableContentElement) {
73 $this->disableContentElement = (bool) $disableContentElement;
74 }
75
76 /**
77 * Rendering of a "numerical array" of Form objects from TypoScript
78 * Creates new object for each element found
79 *
80 * @param tx_form_Domain_Model_Element_Abstract $parentElement Parent model object
81 * @param array $arguments Configuration array
82 * @throws Exception
83 * @return void
84 */
85 public function getChildElementsByIntegerKey(tx_form_Domain_Model_Element_Abstract $parentElement, array $typoscript) {
86 if (is_array($typoscript)) {
87 $keys = t3lib_TStemplate::sortedKeyList($typoscript);
88 foreach ($keys as $key) {
89 $class = $typoscript[$key];
90 if (intval($key) && !strstr($key, '.')) {
91 if (isset($typoscript[$key . '.'])) {
92 $elementArguments = $typoscript[$key . '.'];
93 } else {
94 $elementArguments = array();
95 }
96 $this->setElementType($parentElement, $class, $elementArguments);
97 }
98 }
99 } else {
100 throw new Exception ('Container element with id=' . $parentElement->getElementId() . ' has no configuration which means no children');
101 }
102 }
103
104 /**
105 * Create and add element by type.
106 * This can be a derived Typoscript object by "<",
107 * a form element, or a regular Typoscript object.
108 *
109 * @param tx_form_Domain_Model_Element_Abstract $parentElement The parent for the new element
110 * @param string $class Classname for the element
111 * @param array $arguments Configuration array
112 * @return void
113 */
114 public function setElementType(tx_form_Domain_Model_Element_Abstract $parentElement, $class, array $arguments) {
115 if (in_array($class, tx_form_Common::getInstance()->getFormObjects())) {
116 $this->addElement($parentElement, $class, $arguments);
117
118 } elseif ($this->disableContentElement === FALSE) {
119 if (substr($class, 0, 1) == '<') {
120 $key = trim(substr($class, 1));
121 /** @var $typoscriptParser t3lib_TSparser */
122 $typoscriptParser = t3lib_div::makeInstance('t3lib_TSparser');
123 $oldArguments = $arguments;
124 list($class, $arguments) = $typoscriptParser->getVal($key, $GLOBALS['TSFE']->tmpl->setup);
125 if (is_array($oldArguments) && count($oldArguments)) {
126 $arguments = $this->getLocalConentObject()->joinTSarrays($arguments, $oldArguments);
127 }
128 $GLOBALS['TT']->incStackPointer();
129 $contentObject = array(
130 'cObj' => $class,
131 'cObj.' => $arguments,
132 );
133 $this->addElement($parentElement, 'content', $contentObject);
134 $GLOBALS['TT']->decStackPointer();
135 } else {
136 $contentObject = array(
137 'cObj' => $class,
138 'cObj.' => $arguments,
139 );
140 $this->addElement($parentElement, 'content', $contentObject);
141 }
142 }
143 }
144
145 /**
146 * Add child object to this element
147 *
148 * @param tx_form_Domain_Model_Element_Abstract $parentElement Parent model object
149 * @param string $class Type of element
150 * @param array $arguments Configuration array
151 * @return object
152 */
153 public function addElement(tx_form_Domain_Model_Element_Abstract $parentElement, $class, array $arguments = array()) {
154 $element = $this->createElement($class, $arguments);
155 $parentElement->addElement($element);
156 }
157
158 /**
159 * Create element by loading class
160 * and instantiating the object
161 *
162 * @param string $class Type of element
163 * @param array $arguments Configuration array
164 * @return tx_form_Domain_Model_Element_Abstract
165 */
166 public function createElement($class, array $arguments = array()) {
167 $class = strtolower((string) $class);
168
169 if ($class === 'form') {
170 $className = 'tx_form_Domain_Model_' . ucfirst($class);
171 } else {
172 $className = 'tx_form_Domain_Model_Element_' . ucfirst($class);
173 }
174
175 /** @var $object tx_form_Domain_Model_Element_Abstract */
176 $object = t3lib_div::makeInstance($className);
177
178 if ($object->getElementType() === tx_form_Domain_Model_Element_Abstract::ELEMENT_TYPE_CONTENT) {
179 $object->setData($arguments['cObj'], $arguments['cObj.']);
180 } elseif ($object->getElementType() === tx_form_Domain_Model_Element_Abstract::ELEMENT_TYPE_PLAIN) {
181 $object->setProperties($arguments);
182 } elseif ($object->getElementType() === tx_form_Domain_Model_Element_Abstract::ELEMENT_TYPE_FORM) {
183 $object->setData($arguments['data']);
184 $this->reconstituteElement($object, $arguments);
185 } else {
186 throw new Exception('Element type "' . $object->getElementType() . '" is not supported.');
187 }
188
189 return $object;
190 }
191
192 /**
193 * Reconstitutes the domain model of the accordant element.
194 *
195 * @param tx_form_Domain_Model_Element_Abstract $element
196 * @param array $arguments Configuration array
197 * @return void
198 */
199 protected function reconstituteElement(tx_form_Domain_Model_Element_Abstract $element, array $arguments = array()) {
200 $this->setAttributes($element, $arguments);
201 $this->setAdditionals($element, $arguments);
202
203 if (isset($arguments['filters.'])) {
204 $this->setFilters($element, $arguments['filters.']);
205 }
206
207 $element->setLayout($arguments['layout']);
208 $element->setValue($arguments['value']);
209 $element->setName($arguments['name']);
210
211 $element->setMessagesFromValidation();
212 $element->setErrorsFromValidation();
213 $element->checkFilterAndSetIncomingDataFromRequest();
214
215 $this->getChildElementsByIntegerKey($element, $arguments);
216 }
217
218 /**
219 * Set the attributes
220 *
221 * @param tx_form_Domain_Model_Element_Abstract $element Model object
222 * @param array $arguments Arguments
223 * @return void
224 */
225 public function setAttributes(tx_form_Domain_Model_Element_Abstract $element, array $arguments) {
226 if ($element->hasAllowedAttributes()) {
227 $attributes = $element->getAllowedAttributes();
228 $mandatoryAttributes = $element->getMandatoryAttributes();
229 foreach ($attributes as $attribute => $value) {
230 if (
231 isset($arguments[$attribute]) ||
232 isset($arguments[$attribute . '.']) ||
233 in_array($attribute, $mandatoryAttributes) ||
234 !empty($value)
235 ) {
236 if (!empty($arguments[$attribute])) {
237 $value = $arguments[$attribute];
238 } elseif (!empty($arguments[$attribute . '.'])) {
239 $value = $arguments[$attribute . '.'];
240 }
241
242 try {
243 $element->setAttribute($attribute, $value);
244 } catch (Exception $exception) {
245 throw new Exception ('Cannot call user function for attribute ' . ucfirst($attribute));
246 }
247 }
248 }
249 } else {
250 throw new Exception ('The element with id=' . $element->getElementId() . ' has no default attributes set');
251 }
252 }
253
254 /**
255 * Set the additionals from Element Typoscript configuration
256 *
257 * @param tx_form_Domain_Model_Element_Abstract $element Model object
258 * @param array $arguments Arguments
259 * @return void
260 */
261 public function setAdditionals(tx_form_Domain_Model_Element_Abstract $element, array $arguments) {
262 if (!empty($arguments)) {
263 if ($element->hasAllowedAdditionals()) {
264 $additionals = $element->getAllowedAdditionals();
265 foreach ($additionals as $additional) {
266 if (isset($arguments[$additional . '.']) || isset($arguments[$additional])) {
267 if (isset($arguments[$additional]) && isset($arguments[$additional . '.'])) {
268 $value = $arguments[$additional . '.'];
269 $type = $arguments[$additional];
270 } elseif (isset($arguments[$additional . '.'])) {
271 $value = $arguments[$additional . '.'];
272 $type = 'TEXT';
273 } else {
274 $value['value'] = $arguments[$additional];
275 $type = 'TEXT';
276 }
277
278 try {
279 $element->setAdditional($additional, $type, $value);
280 } catch (Exception $exception) {
281 throw new Exception ('Cannot call user function for additional ' . ucfirst($additional));
282 }
283 }
284 if (isset($arguments['layout.'][$additional]) && $element->additionalIsSet($additional)) {
285 $layout = $arguments['layout.'][$additional];
286 $element->setAdditionalLayout($additional, $layout);
287 }
288 }
289 } else {
290 throw new Exception ('The element with id=' . $element->getElementId() . ' has no additionals set');
291 }
292 }
293 }
294
295 /**
296 * Add the filters according to the settings in the Typoscript array
297 *
298 * @param tx_form_Domain_Model_Element_Abstract $element Model object
299 * @param array $arguments TypoScript
300 * @return void
301 */
302 protected function setFilters(tx_form_Domain_Model_Element_Abstract $element, array $arguments) {
303 $keys = t3lib_TStemplate::sortedKeyList($arguments);
304 foreach ($keys as $key) {
305 $class = $arguments[$key];
306 if (intval($key) && !strstr($key, '.')) {
307 $filterArguments = $arguments[$key . '.'];
308 $filter = $element->makeFilter($class, $filterArguments);
309 $element->addFilter($filter);
310 }
311 }
312 }
313
314 /**
315 * Set the layout handler
316 *
317 * @param array $typoscript TypoScript
318 * @return tx_form_System_Layout The layout handler
319 */
320 public function setLayoutHandler(array $typoscript) {
321 /** @var $layoutHandler tx_form_System_Layout */
322 $layoutHandler = t3lib_div::makeInstance('tx_form_System_Layout'); // singleton
323
324 if (isset($typoscript['layout.'])) {
325 $layoutHandler->setLayout($typoscript['layout.']);
326 }
327
328 return $layoutHandler;
329 }
330
331 /**
332 * Set the request handler
333 *
334 * @param array $typoscript TypoScript
335 * @return tx_form_System_Request The request handler
336 */
337 public function setRequestHandler($typoscript) {
338 $prefix = isset($typoscript['prefix']) ? $typoscript['prefix'] : '';
339 $method = isset($typoscript['method']) ? $typoscript['method'] : '';
340
341 /** @var $requestHandler tx_form_System_Request */
342 $requestHandler = t3lib_div::makeInstance('tx_form_System_Request'); // singleton
343 $requestHandler->setPrefix($prefix);
344 $requestHandler->setMethod($method);
345 $requestHandler->storeFiles();
346
347 return $requestHandler;
348 }
349
350 /**
351 * Set the validation rules
352 *
353 * Makes the validation object and adds rules to it
354 *
355 * @param array $typoscript TypoScript
356 * @return tx_form_System_Validate The validation object
357 */
358 public function setRules(array $typoscript) {
359 $rulesTyposcript = isset($typoscript['rules.']) ? $typoscript['rules.'] : NULL;
360 /** @var $rulesClass tx_form_System_Validate */
361 $rulesClass = t3lib_div::makeInstance('tx_form_System_Validate', $rulesTyposcript); // singleton
362
363 if (is_array($rulesTyposcript)) {
364 $keys = t3lib_TStemplate::sortedKeyList($rulesTyposcript);
365 foreach ($keys as $key) {
366 $class = $rulesTyposcript[$key];
367 if (intval($key) && !strstr($key, '.')) {
368 $elementArguments = $rulesTyposcript[$key . '.'];
369 $rule = $rulesClass->createRule($class, $elementArguments);
370 $rule->setFieldName($elementArguments['element']);
371 $breakOnError = isset($elementArguments['breakOnError']) ? $elementArguments['breakOnError'] : FALSE;
372 $rulesClass->addRule($rule, $elementArguments['element'], $breakOnError);
373 }
374 }
375 }
376
377 return $rulesClass;
378 }
379
380 /**
381 * Gets the local content object.
382 *
383 * @return tslib_cObj
384 */
385 protected function getLocalConentObject() {
386 if (!isset($this->localContentObject)) {
387 $this->localContentObject = t3lib_div::makeInstance('tslib_cObj');
388 }
389 return $this->localContentObject;
390 }
391 }
392 ?>