[BUGFIX] Avoid trimming of user login data with spaces at the end/beginning
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / AbstractNode.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Backend\Form;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Psr\Log\LoggerAwareInterface;
19 use Psr\Log\LoggerAwareTrait;
20 use TYPO3\CMS\Core\Utility\ArrayUtility;
21 use TYPO3\CMS\Core\Utility\GeneralUtility;
22
23 /**
24 * Base class for container and single elements - their abstracts extend from here.
25 */
26 abstract class AbstractNode implements NodeInterface, LoggerAwareInterface
27 {
28 use LoggerAwareTrait;
29
30 /**
31 * Instance of the node factory to create sub elements, container and single element expansions.
32 *
33 * @var NodeFactory
34 */
35 protected $nodeFactory;
36
37 /**
38 * Main data array to work on, given from parent to child elements
39 *
40 * @var array
41 */
42 protected $data = [];
43
44 /**
45 * A list of default field information added to the element / container.
46 *
47 * @var array
48 */
49 protected $defaultFieldInformation = [];
50
51 /**
52 * A list of default field controls added to the element / container.
53 * This property is often reset by single elements.
54 *
55 * @var array
56 */
57 protected $defaultFieldControl = [];
58
59 /**
60 * A list of default field wizards added to the element / container.
61 * This property is often reset by single elements.
62 *
63 * @var array
64 */
65 protected $defaultFieldWizard = [];
66
67 /**
68 * Set data to data array and register node factory to render sub elements
69 *
70 * @param NodeFactory $nodeFactory
71 * @param array $data
72 */
73 public function __construct(NodeFactory $nodeFactory, array $data)
74 {
75 $this->data = $data;
76 $this->nodeFactory = $nodeFactory;
77 }
78
79 /**
80 * Handler for single nodes
81 *
82 * @return array As defined in initializeResultArray() of AbstractNode
83 */
84 abstract public function render();
85
86 /**
87 * Initialize the array that is returned to parent after calling. This structure
88 * is identical for *all* nodes. Parent will merge the return of a child with its
89 * own stuff and in itself return an array of the same structure.
90 *
91 * @return array
92 */
93 protected function initializeResultArray(): array
94 {
95 return [
96 'additionalJavaScriptPost' => [],
97 'additionalHiddenFields' => [],
98 'additionalInlineLanguageLabelFiles' => [],
99 'stylesheetFiles' => [],
100 // can hold strings or arrays,
101 // string = requireJS module,
102 // array = requireJS module + callback e.g. array('TYPO3/Foo/Bar', 'function() {}')
103 'requireJsModules' => [],
104 'inlineData' => [],
105 'html' => '',
106 ];
107 }
108
109 /**
110 * Merge existing data with a child return array.
111 * The incoming $childReturn array should be initialized
112 * using initializeResultArray() beforehand.
113 *
114 * @param array $existing Currently merged array
115 * @param array $childReturn Array returned by child
116 * @param bool $mergeHtml If false, the ['html'] section of $childReturn will NOT be added to $existing
117 * @return array Result array
118 */
119 protected function mergeChildReturnIntoExistingResult(array $existing, array $childReturn, bool $mergeHtml = true): array
120 {
121 if ($mergeHtml && !empty($childReturn['html'])) {
122 $existing['html'] .= LF . $childReturn['html'];
123 }
124 foreach ($childReturn['additionalJavaScriptPost'] ?? [] as $value) {
125 $existing['additionalJavaScriptPost'][] = $value;
126 }
127 foreach ($childReturn['additionalHiddenFields'] ?? [] as $value) {
128 $existing['additionalHiddenFields'][] = $value;
129 }
130 foreach ($childReturn['stylesheetFiles'] ?? [] as $value) {
131 $existing['stylesheetFiles'][] = $value;
132 }
133 foreach ($childReturn['requireJsModules'] ?? [] as $module) {
134 $existing['requireJsModules'][] = $module;
135 }
136 foreach ($childReturn['additionalInlineLanguageLabelFiles'] ?? [] as $inlineLanguageLabelFile) {
137 $existing['additionalInlineLanguageLabelFiles'][] = $inlineLanguageLabelFile;
138 }
139 if (!empty($childReturn['inlineData'])) {
140 $existingInlineData = $existing['inlineData'];
141 $childInlineData = $childReturn['inlineData'];
142 ArrayUtility::mergeRecursiveWithOverrule($existingInlineData, $childInlineData);
143 $existing['inlineData'] = $existingInlineData;
144 }
145 return $existing;
146 }
147
148 /**
149 * Build JSON string for validations rules.
150 *
151 * @param array $config
152 * @return string
153 */
154 protected function getValidationDataAsJsonString(array $config): string
155 {
156 $validationRules = [];
157 if (!empty($config['eval'])) {
158 $evalList = GeneralUtility::trimExplode(',', $config['eval'], true);
159 foreach ($evalList as $evalType) {
160 $validationRules[] = [
161 'type' => $evalType,
162 ];
163 }
164 }
165 if (!empty($config['range'])) {
166 $newValidationRule = [
167 'type' => 'range',
168 ];
169 if (!empty($config['range']['lower'])) {
170 $newValidationRule['lower'] = $config['range']['lower'];
171 }
172 if (!empty($config['range']['upper'])) {
173 $newValidationRule['upper'] = $config['range']['upper'];
174 }
175 $validationRules[] = $newValidationRule;
176 }
177 if (!empty($config['maxitems']) || !empty($config['minitems'])) {
178 $minItems = isset($config['minitems']) ? (int)$config['minitems'] : 0;
179 $maxItems = isset($config['maxitems']) ? (int)$config['maxitems'] : 99999;
180 $type = $config['type'] ?: 'range';
181 $validationRules[] = [
182 'type' => $type,
183 'minItems' => $minItems,
184 'maxItems' => $maxItems
185 ];
186 }
187 if (!empty($config['required'])) {
188 $validationRules[] = ['type' => 'required'];
189 }
190 return json_encode($validationRules);
191 }
192 }