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