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