[!!!][TASK] Improve flex and TCA handling in FormEngine
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / Container / FlexFormSectionContainer.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\Core\Authentication\BackendUserAuthentication;
18 use TYPO3\CMS\Core\Imaging\Icon;
19 use TYPO3\CMS\Core\Imaging\IconFactory;
20 use TYPO3\CMS\Core\Utility\GeneralUtility;
21 use TYPO3\CMS\Lang\LanguageService;
22
23 /**
24 * Handle flex form sections.
25 *
26 * This container is created by FlexFormElementContainer if a "single" element is in
27 * fact a section. For each existing section container it creates as FlexFormContainerContainer
28 * to render its inner fields.
29 * Additionally, a button for each possible container is rendered with information for the
30 * ajax controller that fetches one on click.
31 */
32 class FlexFormSectionContainer extends AbstractContainer
33 {
34 /**
35 * Entry method
36 *
37 * @return array As defined in initializeResultArray() of AbstractNode
38 */
39 public function render()
40 {
41 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
42 $languageService = $this->getLanguageService();
43
44 $flexFormDataStructureIdentifier = $this->data['flexFormDataStructureIdentifier'];
45 $flexFormDataStructureArray = $this->data['flexFormDataStructureArray'];
46 $flexFormRowData = $this->data['flexFormRowData'];
47 $flexFormFieldName = $this->data['flexFormFieldName'];
48 $flexFormSheetName = $this->data['flexFormSheetName'];
49
50 $userHasAccessToDefaultLanguage = $this->getBackendUserAuthentication()->checkLanguageAccess(0);
51
52 $resultArray = $this->initializeResultArray();
53
54 // Render each existing container
55 foreach ($flexFormDataStructureArray['children'] as $flexFormContainerIdentifier => $containerDataStructure) {
56 $existingContainerData = $flexFormRowData[$flexFormContainerIdentifier];
57 // @todo: This relies on the fact that "_TOGGLE" is *below* the real data in the saved xml structure
58 $existingSectionContainerDataStructureType = key($existingContainerData);
59 $existingContainerData = $existingContainerData[$existingSectionContainerDataStructureType];
60 $options = $this->data;
61 $options['flexFormRowData'] = $existingContainerData['el'];
62 $options['flexFormDataStructureArray'] = $containerDataStructure;
63 $options['flexFormFormPrefix'] = $this->data['flexFormFormPrefix'] . '[' . $flexFormFieldName . ']' . '[el]';
64 $options['flexFormContainerName'] = $existingSectionContainerDataStructureType;
65 $options['flexFormContainerIdentifier'] = $flexFormContainerIdentifier;
66 $options['flexFormContainerElementCollapsed'] = (bool)$existingContainerData['el']['_TOGGLE'];
67 $options['renderType'] = 'flexFormContainerContainer';
68 $flexFormContainerContainerResult = $this->nodeFactory->create($options)->render();
69 $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $flexFormContainerContainerResult);
70 }
71
72 // "New container" handling: Creates buttons for each possible container with all relevant information for the ajax call.
73 $containerTemplatesHtml = [];
74 foreach ($flexFormDataStructureArray['el'] as $flexFormContainerName => $flexFormFieldDefinition) {
75 $containerTitle = '';
76 if (!empty(trim($flexFormFieldDefinition['title']))) {
77 $containerTitle = $languageService->sL(trim($flexFormFieldDefinition['title']));
78 }
79 $containerTemplateHtml = [];
80 $containerTemplateHtml[] = '<a';
81 $containerTemplateHtml[] = 'href="#"';
82 $containerTemplateHtml[] = 'class="btn btn-default t3js-flex-container-add"';
83 $containerTemplateHtml[] = 'data-vanillauid="' . (int)$this->data['vanillaUid'] . '"';
84 // no int cast for databaseRow uid, this can be "NEW1234..."
85 $containerTemplateHtml[] = 'data-databaserowuid="' . htmlspecialchars($this->data['databaseRow']['uid']) . '"';
86 $containerTemplateHtml[] = 'data-command="' . htmlspecialchars($this->data['command']) . '"';
87 $containerTemplateHtml[] = 'data-tablename="' . htmlspecialchars($this->data['tableName']) . '"';
88 $containerTemplateHtml[] = 'data-fieldname="' . htmlspecialchars($this->data['fieldName']) . '"';
89 $containerTemplateHtml[] = 'data-recordtypevalue="' . $this->data['recordTypeValue'] . '"';
90 $containerTemplateHtml[] = 'data-datastructureidentifier="' . htmlspecialchars($flexFormDataStructureIdentifier) . '"';
91 $containerTemplateHtml[] = 'data-flexformsheetname="' . htmlspecialchars($flexFormSheetName) . '"';
92 $containerTemplateHtml[] = 'data-flexformfieldname="' . htmlspecialchars($flexFormFieldName) . '"';
93 $containerTemplateHtml[] = 'data-flexformcontainername="' . htmlspecialchars($flexFormContainerName) . '"';
94 $containerTemplateHtml[] = '>';
95 $containerTemplateHtml[] = $iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)->render();
96 $containerTemplateHtml[] = htmlspecialchars(GeneralUtility::fixed_lgd_cs($containerTitle, 30));
97 $containerTemplateHtml[] = '</a>';
98 $containerTemplatesHtml[] = implode(LF, $containerTemplateHtml);
99 }
100 // Create new elements links
101 $createElementsHtml = [];
102 if ($userHasAccessToDefaultLanguage) {
103 $createElementsHtml[] = '<div class="t3-form-field-add-flexsection">';
104 $createElementsHtml[] = '<div class="btn-group">';
105 $createElementsHtml[] = implode('', $containerTemplatesHtml);
106 $createElementsHtml[] = '</div>';
107 $createElementsHtml[] = '</div>';
108 }
109
110 $sectionTitle = '';
111 if (!empty(trim($flexFormDataStructureArray['title']))) {
112 $sectionTitle = $languageService->sL(trim($flexFormDataStructureArray['title']));
113 }
114
115 // Wrap child stuff
116 $toggleAll = htmlspecialchars($languageService->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.toggleall'));
117 $html = [];
118 $html[] = '<div class="panel panel-tab">';
119 $html[] = '<div class="panel-body">';
120 $html[] = '<div class="t3-form-field-container t3-form-flex">';
121 $html[] = '<div class="t3-form-field-label-flexsection">';
122 $html[] = '<h4>';
123 $html[] = htmlspecialchars($sectionTitle);
124 $html[] = '</h4>';
125 $html[] = '</div>';
126 $html[] = '<div class="t3js-form-field-toggle-flexsection t3-form-flexsection-toggle">';
127 $html[] = '<a class="btn btn-default" href="#" title="' . $toggleAll . '">';
128 $html[] = $iconFactory->getIcon('actions-move-right', Icon::SIZE_SMALL)->render() . $toggleAll;
129 $html[] = '</a>';
130 $html[] = '</div>';
131 $html[] = '<div';
132 $html[] = 'class="panel-group panel-hover t3-form-field-container-flexsection t3-flex-container"';
133 $html[] = 'data-t3-flex-allow-restructure="' . ($userHasAccessToDefaultLanguage ? '1' : '0') . '"';
134 $html[] = '>';
135 $html[] = $resultArray['html'];
136 $html[] = '</div>';
137 $html[] = implode(LF, $createElementsHtml);
138 $html[] = '</div>';
139 $html[] = '</div>';
140 $html[] = '</div>';
141
142 $resultArray['html'] = implode(LF, $html);
143
144 return $resultArray;
145 }
146
147 /**
148 * @return BackendUserAuthentication
149 */
150 protected function getBackendUserAuthentication()
151 {
152 return $GLOBALS['BE_USER'];
153 }
154
155 /**
156 * @return LanguageService
157 */
158 protected function getLanguageService()
159 {
160 return $GLOBALS['LANG'];
161 }
162 }