[TASK] Use null coalescing operator where possible
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / Container / FlexFormElementContainer.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form\Container;
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\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
19 use TYPO3\CMS\Core\Localization\LanguageService;
20 use TYPO3\CMS\Core\Type\Bitmask\JsConfirmation;
21
22 /**
23 * The container handles single elements.
24 *
25 * This one is called by FlexFormTabsContainer, FlexFormNoTabsContainer or FlexFormContainerContainer.
26 * For single fields, the code is similar to SingleFieldContainer, processing will end up in single
27 * element classes depending on specific renderType of an element. Additionally, it determines if a
28 * section is handled and hands over to FlexFormSectionContainer in this case.
29 */
30 class FlexFormElementContainer extends AbstractContainer
31 {
32 /**
33 * Entry method
34 *
35 * @return array As defined in initializeResultArray() of AbstractNode
36 */
37 public function render()
38 {
39 $flexFormDataStructureArray = $this->data['flexFormDataStructureArray'];
40 $flexFormRowData = $this->data['flexFormRowData'];
41 $flexFormFormPrefix = $this->data['flexFormFormPrefix'];
42 $parameterArray = $this->data['parameterArray'];
43
44 $languageService = $this->getLanguageService();
45 $resultArray = $this->initializeResultArray();
46 foreach ($flexFormDataStructureArray as $flexFormFieldName => $flexFormFieldArray) {
47 if (
48 // No item array found at all
49 !is_array($flexFormFieldArray)
50 // Not a section or container and not a list of single items
51 || (!isset($flexFormFieldArray['type']) && !is_array($flexFormFieldArray['config']))
52 // Type passthrough is not rendered
53 || (isset($flexFormFieldArray['config']['type']) && $flexFormFieldArray['config']['type'] === 'passthrough')
54 ) {
55 continue;
56 }
57
58 if ($flexFormFieldArray['type'] === 'array') {
59 // Section
60 if (empty($flexFormFieldArray['section'])) {
61 $resultArray['html'] = LF . 'Section expected at ' . $flexFormFieldName . ' but not found';
62 continue;
63 }
64
65 $options = $this->data;
66 $options['flexFormDataStructureArray'] = $flexFormFieldArray;
67 $options['flexFormRowData'] = $flexFormRowData[$flexFormFieldName]['el'] ?? [];
68 $options['flexFormFieldName'] = $flexFormFieldName;
69 $options['renderType'] = 'flexFormSectionContainer';
70 $sectionContainerResult = $this->nodeFactory->create($options)->render();
71 $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $sectionContainerResult);
72 } else {
73 // Set up options for single element
74 $fakeParameterArray = [
75 'fieldConf' => [
76 'label' => $languageService->sL(trim($flexFormFieldArray['label'])),
77 'config' => $flexFormFieldArray['config'],
78 'children' => $flexFormFieldArray['children'],
79 'onChange' => $flexFormFieldArray['onChange'],
80 ],
81 'fieldChangeFunc' => $parameterArray['fieldChangeFunc'],
82 'label' => $parameterArray['label'],
83 ];
84
85 $alertMsgOnChange = '';
86 if (isset($fakeParameterArray['fieldConf']['onChange']) && $fakeParameterArray['fieldConf']['onChange'] === 'reload') {
87 if ($this->getBackendUserAuthentication()->jsConfirmation(JsConfirmation::TYPE_CHANGE)) {
88 $alertMsgOnChange = 'top.TYPO3.Modal.confirm('
89 . 'TYPO3.lang["FormEngine.refreshRequiredTitle"],'
90 . ' TYPO3.lang["FormEngine.refreshRequiredContent"]'
91 . ')'
92 . '.on('
93 . '"button.clicked",'
94 . ' function(e) { if (e.target.name == "ok" && TBE_EDITOR.checkSubmit(-1)) { TBE_EDITOR.submitForm() } top.TYPO3.Modal.dismiss(); }'
95 . ');';
96 } else {
97 $alertMsgOnChange = 'if (TBE_EDITOR.checkSubmit(-1)){ TBE_EDITOR.submitForm();}';
98 }
99 }
100 if ($alertMsgOnChange) {
101 $fakeParameterArray['fieldChangeFunc']['alert'] = $alertMsgOnChange;
102 }
103
104 $originalFieldName = $parameterArray['itemFormElName'];
105 $fakeParameterArray['itemFormElName'] = $parameterArray['itemFormElName'] . $flexFormFormPrefix . '[' . $flexFormFieldName . '][vDEF]';
106 if ($fakeParameterArray['itemFormElName'] !== $originalFieldName) {
107 // If calculated itemFormElName is different from originalFieldName
108 // change the originalFieldName in TBE_EDITOR_fieldChanged. This is
109 // especially relevant for wizards writing their content back to hidden fields
110 if (!empty($fakeParameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'])) {
111 $fakeParameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = str_replace($originalFieldName, $fakeParameterArray['itemFormElName'], $fakeParameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged']);
112 }
113 }
114 $fakeParameterArray['itemFormElID'] = $parameterArray['itemFormElID'] . '_' . preg_replace('/[^a-zA-Z0-9_-]/', '_', $flexFormFieldName);
115 if (isset($flexFormRowData[$flexFormFieldName]['vDEF'])) {
116 $fakeParameterArray['itemFormElValue'] = $flexFormRowData[$flexFormFieldName]['vDEF'];
117 } else {
118 $fakeParameterArray['itemFormElValue'] = $fakeParameterArray['fieldConf']['config']['default'];
119 }
120
121 $options = $this->data;
122 // Set either flexFormFieldName or flexFormContainerFieldName, depending on if we are a "regular" field or a flex container section field
123 if (empty($options['flexFormFieldName'])) {
124 $options['flexFormFieldName'] = $flexFormFieldName;
125 } else {
126 $options['flexFormContainerFieldName'] = $flexFormFieldName;
127 }
128 $options['parameterArray'] = $fakeParameterArray;
129 $options['elementBaseName'] = $this->data['elementBaseName'] . $flexFormFormPrefix . '[' . $flexFormFieldName . '][vDEF]';
130
131 if (!empty($flexFormFieldArray['config']['renderType'])) {
132 $options['renderType'] = $flexFormFieldArray['config']['renderType'];
133 } else {
134 // Fallback to type if no renderType is given
135 $options['renderType'] = $flexFormFieldArray['config']['type'];
136 }
137 $childResult = $this->nodeFactory->create($options)->render();
138
139 // Possible line breaks in the label through xml: \n => <br/>, usage of nl2br() not possible, so it's done through str_replace (?!)
140 $processedTitle = str_replace('\\n', '<br />', htmlspecialchars($fakeParameterArray['fieldConf']['label']));
141 $html = [];
142 $html[] = '<div class="form-section">';
143 $html[] = '<div class="form-group t3js-formengine-palette-field t3js-formengine-validation-marker">';
144 $html[] = '<label class="t3js-formengine-label">';
145 $html[] = BackendUtility::wrapInHelp($parameterArray['_cshKey'], $flexFormFieldName, $processedTitle);
146 $html[] = '</label>';
147 $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
148 $html[] = $childResult['html'];
149 $html[] = '</div>';
150 $html[] = '</div>';
151 $html[] = '</div>';
152
153 $resultArray['html'] .= implode(LF, $html);
154 $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $childResult, false);
155 }
156 }
157
158 return $resultArray;
159 }
160
161 /**
162 * @return LanguageService
163 */
164 protected function getLanguageService()
165 {
166 return $GLOBALS['LANG'];
167 }
168
169 /**
170 * @return BackendUserAuthentication
171 */
172 protected function getBackendUserAuthentication()
173 {
174 return $GLOBALS['BE_USER'];
175 }
176 }