[TASK] Remove ext:dbal from installation steps
[Packages/TYPO3.CMS.git] / typo3 / sysext / form / Classes / Domain / Builder / ElementBuilder.php
1 <?php
2 namespace TYPO3\CMS\Form\Domain\Builder;
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\MathUtility;
18 use TYPO3\CMS\Form\Domain\Model\Element;
19
20 /**
21 * Builder for Element domain models.
22 */
23 class ElementBuilder
24 {
25 /**
26 * @param FormBuilder $formBuilder
27 * @param Element $element
28 * @param array $userDefinedTypoScript
29 * @return ElementBuilder
30 */
31 public static function create(FormBuilder $formBuilder, Element $element, array $userDefinedTypoScript)
32 {
33 /** @var ElementBuilder $elementBuilder */
34 $elementBuilder = \TYPO3\CMS\Form\Utility\FormUtility::getObjectManager()->get(ElementBuilder::class);
35 $elementBuilder->setFormBuilder($formBuilder);
36 $elementBuilder->setElement($element);
37 $elementBuilder->setUserConfiguredElementTyposcript($userDefinedTypoScript);
38 return $elementBuilder;
39 }
40
41 /**
42 * @var \TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository
43 */
44 protected $typoScriptRepository;
45
46 /**
47 * @var \TYPO3\CMS\Extbase\Service\TypoScriptService
48 */
49 protected $typoScriptService;
50
51 /**
52 * @var array
53 */
54 protected $userConfiguredElementTyposcript = [];
55
56 /**
57 * @var array
58 */
59 protected $htmlAttributes = [];
60
61 /**
62 * @var array
63 */
64 protected $additionalArguments = [];
65
66 /**
67 * @var array
68 */
69 protected $wildcardPrefixes = [];
70
71 /**
72 * @var FormBuilder
73 */
74 protected $formBuilder;
75
76 /**
77 * @var Element
78 */
79 protected $element;
80
81 /**
82 * @param \TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository $typoScriptRepository
83 * @return void
84 */
85 public function injectTypoScriptRepository(\TYPO3\CMS\Form\Domain\Repository\TypoScriptRepository $typoScriptRepository)
86 {
87 $this->typoScriptRepository = $typoScriptRepository;
88 }
89
90 /**
91 * @param \TYPO3\CMS\Extbase\Service\TypoScriptService $typoScriptService
92 * @return void
93 */
94 public function injectTypoScriptService(\TYPO3\CMS\Extbase\Service\TypoScriptService $typoScriptService)
95 {
96 $this->typoScriptService = $typoScriptService;
97 }
98
99 /**
100 * @param FormBuilder $formBuilder
101 */
102 public function setFormBuilder(FormBuilder $formBuilder)
103 {
104 $this->formBuilder = $formBuilder;
105 }
106
107 /**
108 * @param Element $element
109 */
110 public function setElement(Element $element)
111 {
112 $this->element = $element;
113 }
114
115 /**
116 * Set the fluid partial path to the element
117 *
118 * @return void
119 */
120 public function setPartialPaths()
121 {
122 $this->setElementPartialPath();
123 }
124
125 /**
126 * Set the fluid partial path to the element
127 *
128 * @return void
129 */
130 protected function setElementPartialPath()
131 {
132 if (!isset($this->userConfiguredElementTyposcript['partialPath'])) {
133 $partialPath = $this->typoScriptRepository->getDefaultFluidTemplate($this->element->getElementType());
134 } else {
135 $partialPath = $this->userConfiguredElementTyposcript['partialPath'];
136 unset($this->userConfiguredElementTyposcript['partialPath']);
137 }
138 $this->element->setPartialPath($partialPath);
139 }
140
141 /**
142 * Set the fluid partial path to the element
143 *
144 * @return void
145 */
146 public function setVisibility()
147 {
148 $visibility = false;
149 if ($this->formBuilder->getControllerAction() === 'show') {
150 if (!isset($this->userConfiguredElementTyposcript['visibleInShowAction'])) {
151 $visibility = (bool)$this->typoScriptRepository->getModelConfigurationByScope($this->element->getElementType(), 'visibleInShowAction');
152 } else {
153 $visibility = (bool)$this->userConfiguredElementTyposcript['visibleInShowAction'];
154 }
155 } elseif ($this->formBuilder->getControllerAction() === 'confirmation') {
156 if (!isset($this->userConfiguredElementTyposcript['visibleInConfirmationAction'])) {
157 $visibility = (bool)$this->typoScriptRepository->getModelConfigurationByScope($this->element->getElementType(), 'visibleInConfirmationAction');
158 } else {
159 $visibility = (bool)$this->userConfiguredElementTyposcript['visibleInConfirmationAction'];
160 }
161 } elseif ($this->formBuilder->getControllerAction() === 'process') {
162 if (!isset($this->userConfiguredElementTyposcript['visibleInMail'])) {
163 $visibility = (bool)$this->typoScriptRepository->getModelConfigurationByScope($this->element->getElementType(), 'visibleInMail');
164 } else {
165 $visibility = (bool)$this->userConfiguredElementTyposcript['visibleInMail'];
166 }
167 }
168 $this->element->setShowElement($visibility);
169 }
170
171 /**
172 * Find all prefix-* attributes and return the
173 * found prefixs. Than delete them from the htmlAttributes array
174 *
175 * @return void
176 */
177 public function setHtmlAttributeWildcards()
178 {
179 foreach ($this->htmlAttributes as $attributeName => $attributeValue) {
180 if (strpos($attributeName, '-*') > 0) {
181 $prefix = substr($attributeName, 0, -1);
182 $this->wildcardPrefixes[] = $prefix;
183 unset($this->htmlAttributes[$attributeName]);
184 }
185 }
186 }
187
188 /**
189 * Overlay user defined html attribute values
190 * To determine whats a html attribute, the htmlAttributes
191 * array is used. If a html attribute value is found in userConfiguredElementTyposcript
192 * this value is set to htmlAttributes and removed from userConfiguredElementTyposcript.
193 *
194 * @return void
195 */
196 public function overlayUserdefinedHtmlAttributeValues()
197 {
198 foreach ($this->htmlAttributes as $attributeName => $attributeValue) {
199 $attributeNameWithoutDot = rtrim($attributeName, '.');
200 $attributeNameToSet = $attributeNameWithoutDot;
201
202 if ($this->arrayKeyExists($attributeNameWithoutDot, $this->userConfiguredElementTyposcript)) {
203 $attributeValue = $this->formBuilder->getFormUtility()->renderItem(
204 $this->userConfiguredElementTyposcript[$attributeNameWithoutDot . '.'],
205 $this->userConfiguredElementTyposcript[$attributeNameWithoutDot]
206 );
207 $this->htmlAttributes[$attributeNameToSet] = $attributeValue;
208 }
209
210 unset($this->userConfiguredElementTyposcript[$attributeNameWithoutDot . '.']);
211 unset($this->userConfiguredElementTyposcript[$attributeNameWithoutDot]);
212 }
213
214 // the prefix-* magic
215 $ignoreKeys = [];
216 foreach ($this->userConfiguredElementTyposcript as $attributeName => $attributeValue) {
217 // ignore child elements
218 if (
219 MathUtility::canBeInterpretedAsInteger($attributeName)
220 || isset($ignoreKeys[$attributeName])
221 ) {
222 $ignoreKeys[$attributeName . '.'] = true;
223 continue;
224 }
225
226 foreach ($this->wildcardPrefixes as $wildcardPrefix) {
227 if (strpos($attributeName, $wildcardPrefix) !== 0) {
228 continue;
229 }
230 $attributeNameWithoutDot = rtrim($attributeName, '.');
231 $attributeValue = $this->formBuilder->getFormUtility()->renderItem(
232 $this->userConfiguredElementTyposcript[$attributeNameWithoutDot . '.'],
233 $this->userConfiguredElementTyposcript[$attributeNameWithoutDot]
234 );
235 $this->htmlAttributes[$attributeNameWithoutDot] = $attributeValue;
236 $ignoreKeys[$attributeNameWithoutDot . '.'] = true;
237 unset($this->userConfiguredElementTyposcript[$attributeNameWithoutDot . '.']);
238 unset($this->userConfiguredElementTyposcript[$attributeNameWithoutDot]);
239 break;
240 }
241 }
242 }
243
244 /**
245 * If fixedHtmlAttributeValues are defined for this element
246 * then overwrite the html attribute value
247 *
248 * @return void
249 */
250 public function overlayFixedHtmlAttributeValues()
251 {
252 $fixedHtmlAttributeValues = $this->typoScriptRepository->getModelConfigurationByScope($this->element->getElementType(), 'fixedHtmlAttributeValues.');
253 if (is_array($fixedHtmlAttributeValues)) {
254 foreach ($fixedHtmlAttributeValues as $attributeName => $attributeValue) {
255 $this->htmlAttributes[$attributeName] = $attributeValue;
256 }
257 }
258 }
259
260 /**
261 * Move htmlAttributes to additionalArguments that must be passed
262 * as a view helper argument
263 *
264 * @return void
265 */
266 public function moveHtmlAttributesToAdditionalArguments()
267 {
268 $htmlAttributesUsedByTheViewHelperDirectly = $this->typoScriptRepository->getModelConfigurationByScope($this->element->getElementType(), 'htmlAttributesUsedByTheViewHelperDirectly.');
269 if (is_array($htmlAttributesUsedByTheViewHelperDirectly)) {
270 foreach ($htmlAttributesUsedByTheViewHelperDirectly as $attributeName) {
271 if (array_key_exists($attributeName, $this->htmlAttributes)) {
272 $this->additionalArguments[$attributeName] = $this->htmlAttributes[$attributeName];
273 unset($this->htmlAttributes[$attributeName]);
274 }
275 }
276 }
277 }
278
279 /**
280 * Set the viewhelper default arguments in the additionalArguments array
281 *
282 * @return void
283 */
284 public function setViewHelperDefaulArgumentsToAdditionalArguments()
285 {
286 $viewHelperDefaultArguments = $this->typoScriptRepository->getModelConfigurationByScope($this->element->getElementType(), 'viewHelperDefaultArguments.');
287 if (is_array($viewHelperDefaultArguments)) {
288 foreach ($viewHelperDefaultArguments as $viewHelperDefaulArgumentName => $viewHelperDefaulArgumentValue) {
289 $viewHelperDefaulArgumentNameWithoutDot = rtrim($viewHelperDefaulArgumentName, '.');
290 $this->additionalArguments[$viewHelperDefaulArgumentNameWithoutDot] = $viewHelperDefaulArgumentValue;
291 }
292 }
293 unset($this->userConfiguredElementTyposcript['viewHelperDefaultArguments']);
294 }
295
296 /**
297 * Move all userdefined properties to the additionalArguments
298 * array. Ignore the child elements
299 *
300 * @return void
301 */
302 public function moveAllOtherUserdefinedPropertiesToAdditionalArguments()
303 {
304 $viewHelperDefaultArguments = $this->typoScriptRepository->getModelConfigurationByScope($this->element->getElementType(), 'viewHelperDefaultArguments.');
305 $ignoreKeys = [];
306
307 foreach ($this->userConfiguredElementTyposcript as $attributeName => $attributeValue) {
308 // ignore child elements
309 if (
310 MathUtility::canBeInterpretedAsInteger($attributeName)
311 || isset($ignoreKeys[$attributeName])
312 || $attributeName == 'postProcessor.'
313 || $attributeName == 'rules.'
314 || $attributeName == 'filters.'
315 || $attributeName == 'layout'
316 ) {
317 $ignoreKeys[$attributeName . '.'] = true;
318 continue;
319 }
320 $attributeNameWithoutDot = rtrim($attributeName, '.');
321 $attributeNameToSet = $attributeNameWithoutDot;
322
323 if (
324 isset($viewHelperDefaultArguments[$attributeName])
325 || isset($viewHelperDefaultArguments[$attributeNameWithoutDot])
326 ) {
327 $this->formBuilder->getFormUtility()->renderArrayItems($attributeValue);
328 $attributeValue = $this->typoScriptService->convertTypoScriptArrayToPlainArray($attributeValue);
329 } else {
330 $attributeValue = $this->formBuilder->getFormUtility()->renderItem(
331 $this->userConfiguredElementTyposcript[$attributeNameWithoutDot . '.'],
332 $this->userConfiguredElementTyposcript[$attributeNameWithoutDot]
333 );
334 }
335 $this->additionalArguments[$attributeNameToSet] = $attributeValue;
336 $ignoreKeys[$attributeNameToSet . '.'] = true;
337 $ignoreKeys[$attributeNameToSet] = true;
338
339 unset($this->userConfiguredElementTyposcript[$attributeNameWithoutDot . '.']);
340 unset($this->userConfiguredElementTyposcript[$attributeNameWithoutDot]);
341 }
342 // remove "stdWrap." from "additionalArguments" on
343 // the FORM Element
344 if (
345 !$this->formBuilder->getConfiguration()->getContentElementRendering()
346 && $this->element->getElementType() == 'FORM'
347 ) {
348 unset($this->additionalArguments['stdWrap']);
349 unset($this->additionalArguments['stdWrap.']);
350 }
351 }
352
353 /**
354 * Set the name and id attribute
355 *
356 * @return array
357 */
358 public function setNameAndId()
359 {
360 if (
361 $this->element->getParentElement()
362 && (int)$this->typoScriptRepository->getModelConfigurationByScope($this->element->getParentElement()->getElementType(), 'childrenInheritName') == 1
363 ) {
364 $this->htmlAttributes['name'] = $this->element->getParentElement()->getName();
365 $this->additionalArguments['multiple'] = '1';
366 $name = $this->sanitizeNameAttribute($this->userConfiguredElementTyposcript['name']);
367 $this->element->setName($name);
368 } else {
369 $this->htmlAttributes['name'] = $this->sanitizeNameAttribute($this->htmlAttributes['name']);
370 $this->element->setName($this->htmlAttributes['name']);
371 }
372 $this->htmlAttributes['id'] = $this->sanitizeIdAttribute($this->htmlAttributes['id']);
373 $this->element->setId($this->htmlAttributes['id']);
374 }
375
376 /**
377 * If the name is not defined it is automatically generated
378 * using the following syntax: id-{element_counter}
379 * The name attribute will be transformed if it contains some
380 * non allowed characters:
381 * - spaces are changed into hyphens
382 * - remove all characters except a-z A-Z 0-9 _ -
383 *
384 * @param string $name
385 * @return string
386 */
387 public function sanitizeNameAttribute($name)
388 {
389 $name = $this->formBuilder->getFormUtility()->sanitizeNameAttribute($name);
390 if (empty($name)) {
391 $name = 'id-' . $this->element->getElementCounter();
392 }
393 return $name;
394 }
395
396 /**
397 * If the id is not defined it is automatically generated
398 * using the following syntax: field-{element_counter}
399 * The id attribute will be transformed if it contains some
400 * non allowed characters:
401 * - spaces are changed into hyphens
402 * - if the id start with a integer then transform it to field-{integer}
403 * - remove all characters expect a-z A-Z 0-9 _ - : .
404 *
405 * @param string $id
406 * @return string
407 */
408 protected function sanitizeIdAttribute($id)
409 {
410 $id = $this->formBuilder->getFormUtility()->sanitizeIdAttribute($id);
411 if (empty($id)) {
412 $id = 'field-' . $this->element->getElementCounter();
413 }
414 return $id;
415 }
416
417 /**
418 * Check if a needle exists in a array.
419 *
420 * @param string $needle
421 * @param array $haystack
422 * @return bool TRUE if found
423 */
424 protected function arrayKeyExists($needle, array $haystack = [])
425 {
426 return (
427 isset($haystack[$needle]) || isset($haystack[$needle . '.'])
428 );
429 }
430
431 /**
432 * Get the current html attributes
433 *
434 * @return array
435 */
436 public function getHtmlAttributes()
437 {
438 return $this->htmlAttributes;
439 }
440
441 /**
442 * Set the current html attributes
443 *
444 * @param array $htmlAttributes
445 */
446 public function setHtmlAttributes(array $htmlAttributes)
447 {
448 $this->htmlAttributes = $htmlAttributes;
449 }
450
451 /**
452 * Get the current additional arguments
453 *
454 * @return array
455 */
456 public function getAdditionalArguments()
457 {
458 return $this->additionalArguments;
459 }
460
461 /**
462 * Set the current additional arguments
463 *
464 * @param array $additionalArguments
465 */
466 public function setAdditionalArguments(array $additionalArguments)
467 {
468 $this->additionalArguments = $additionalArguments;
469 }
470
471 /**
472 * Get the current wildcard prefixes
473 *
474 * @return array
475 */
476 public function getWildcardPrefixes()
477 {
478 return $this->wildcardPrefixes;
479 }
480
481 /**
482 * Set the current wildcard prefixes
483 *
484 * @param array $wildcardPrefixes
485 */
486 public function setWildcardPrefixes(array $wildcardPrefixes)
487 {
488 $this->wildcardPrefixes = $wildcardPrefixes;
489 }
490
491 /**
492 * Get the current Element
493 *
494 * @return array
495 */
496 public function getUserConfiguredElementTyposcript()
497 {
498 return $this->userConfiguredElementTyposcript;
499 }
500
501 /**
502 * Set the current Element
503 *
504 * @param array $userConfiguredElementTyposcript
505 */
506 public function setUserConfiguredElementTyposcript(array $userConfiguredElementTyposcript)
507 {
508 $this->userConfiguredElementTyposcript = $userConfiguredElementTyposcript;
509 }
510 }