‪TYPO3CMS  ‪main
PaletteAndSingleContainer.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
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 
19 
22 
33 {
37  protected array ‪$resultArray = [];
38 
44  public function ‪render(): array
45  {
46  $languageService = $this->‪getLanguageService();
47 
48  /*
49  * The first code block creates a target structure array to later create the final
50  * HTML string. The single fields and sub containers are rendered here already and
51  * other parts of the return array from children except html are accumulated in
52  * $this->resultArray
53  *
54  $targetStructure = [
55  0 => [
56  'type' => 'palette',
57  'fieldName' => 'palette1',
58  'paletteLegend' => 'palette1',
59  'paletteDescription' => 'palette1Description',
60  'elements' => [
61  0 => [
62  'type' => 'single',
63  'fieldName' => 'paletteName',
64  'fieldHtml' => 'element1',
65  ),
66  1 => [
67  'type' => 'linebreak',
68  ),
69  2 => [
70  'type' => 'single',
71  'fieldName' => 'paletteName',
72  'fieldHtml' => 'element2',
73  ],
74  ],
75  ],
76  1 => [
77  'type' => 'single',
78  'fieldName' => 'element3',
79  'fieldHtml' => 'element3',
80  ],
81  2 => [
82  'type' => 'palette',
83  'fieldName' => 'palette2',
84  'paletteLegend' => '', // Palette label is optional
85  'paletteDescription' => '', // Palette description is optional
86  'elements' => [
87  0 => [
88  'type' => 'single',
89  'fieldName' => 'element4',
90  'fieldHtml' => 'element4',
91  ],
92  1 => [
93  'type' => 'linebreak',
94  ],
95  2 => [
96  'type' => 'single',
97  'fieldName' => 'element5',
98  'fieldHtml' => 'element5',
99  ],
100  ],
101  ],
102  );
103  */
104 
105  // Create an intermediate structure of rendered sub elements and elements nested in palettes
106  $targetStructure = [];
107  $mainStructureCounter = -1;
108  $fieldsArray = $this->data['fieldsArray'];
109  $this->resultArray = $this->‪initializeResultArray();
110  foreach ($fieldsArray as $fieldString) {
111  $fieldConfiguration = $this->‪explodeSingleFieldShowItemConfiguration($fieldString);
112  $fieldName = $fieldConfiguration['fieldName'];
113  if ($fieldName === '--palette--') {
114  $paletteElementArray = $this->‪createPaletteContentArray($fieldConfiguration['paletteName'] ?? '');
115  if (!empty($paletteElementArray)) {
116  $mainStructureCounter++;
117  // If there is no label in ['types']['aType']['showitem'] for this palette: "--palette--;;aPalette",
118  // then use ['palettes']['aPalette']['label'] if given.
119  $paletteLegend = $fieldConfiguration['fieldLabel'];
120  if ($paletteLegend === null && !empty($this->data['processedTca']['palettes'][$fieldConfiguration['paletteName']]['label'])) {
121  $paletteLegend = $this->data['processedTca']['palettes'][$fieldConfiguration['paletteName']]['label'];
122  }
123  // Get description of palette.
124  $paletteDescription = $this->data['processedTca']['palettes'][$fieldConfiguration['paletteName']]['description'] ?? '';
125  $targetStructure[$mainStructureCounter] = [
126  'type' => 'palette',
127  'fieldName' => $fieldConfiguration['paletteName'],
128  'paletteLegend' => $languageService->sL($paletteLegend),
129  'paletteDescription' => $languageService->sL($paletteDescription),
130  'elements' => $paletteElementArray,
131  ];
132  }
133  } else {
134  if (!is_array($this->data['processedTca']['columns'][$fieldName] ?? null)) {
135  continue;
136  }
137  $options = ‪$this->data;
138  $options['fieldName'] = $fieldName;
139  $options['renderType'] = 'singleFieldContainer';
140  $childResultArray = $this->nodeFactory->create($options)->render();
141  if (!empty($childResultArray['html'])) {
142  $mainStructureCounter++;
143  $targetStructure[$mainStructureCounter] = [
144  'type' => 'single',
145  'fieldName' => $fieldConfiguration['fieldName'],
146  'fieldHtml' => $childResultArray['html'],
147  ];
148  }
149  $this->resultArray = $this->‪mergeChildReturnIntoExistingResult($this->resultArray, $childResultArray, false);
150  }
151  }
152 
153  // Compile final content
154  $content = [];
155  foreach ($targetStructure as $element) {
156  if ($element['type'] === 'palette') {
157  $paletteName = $element['fieldName'];
158  $isHiddenPalette = !empty($this->data['processedTca']['palettes'][$paletteName]['isHiddenPalette']);
159  $html = [];
160  $html[] = '<fieldset class="form-section' . ($isHiddenPalette ? ' hide' : '') . '">';
161  if (!empty($element['paletteLegend'])) {
162  $html[] = '<h4 class="form-section-headline">' . htmlspecialchars($element['paletteLegend']) . '</h4>';
163  }
164  if (!empty($element['paletteDescription'])) {
165  $html[] = '<p class="form-section-description text-body-secondary">' . nl2br(htmlspecialchars($element['paletteDescription'])) . '</p>';
166  }
167  $html[] = '<div class="row">' . $this->‪renderInnerPaletteContent($element) . '</div>';
168  $html[] = '</fieldset>';
169  $content[] = implode(LF, $html);
170  } else {
171  $html = [];
172  $html[] = '<fieldset class="form-section">';
173  $html[] = '<div class="form-group t3js-formengine-validation-marker t3js-formengine-palette-field">';
174  $html[] = $element['fieldHtml'];
175  $html[] = '</div>';
176  $html[] = '</fieldset>';
177  $content[] = implode(LF, $html);
178  }
179  }
180 
181  $finalResultArray = ‪$this->resultArray;
182  $finalResultArray['html'] = implode(LF, $content);
183  return $finalResultArray;
184  }
185 
191  protected function ‪createPaletteContentArray(string $paletteName): array
192  {
193  // palette needs a palette name reference, otherwise it does not make sense to try rendering of it
194  if (empty($paletteName) || empty($this->data['processedTca']['palettes'][$paletteName]['showitem'])) {
195  return [];
196  }
197  $resultStructure = [];
198  $foundRealElement = false; // Set to true if not only line breaks were rendered
199  $fieldsArray = ‪GeneralUtility::trimExplode(',', $this->data['processedTca']['palettes'][$paletteName]['showitem'], true);
200  foreach ($fieldsArray as $fieldString) {
201  $fieldArray = $this->‪explodeSingleFieldShowItemConfiguration($fieldString);
202  $fieldName = $fieldArray['fieldName'];
203  if ($fieldName === '--linebreak--') {
204  $resultStructure[] = [
205  'type' => 'linebreak',
206  ];
207  } else {
208  if (!is_array($this->data['processedTca']['columns'][$fieldName] ?? null)) {
209  continue;
210  }
211  $options = ‪$this->data;
212  $options['fieldName'] = $fieldName;
213  $options['renderType'] = 'singleFieldContainer';
214  $singleFieldContentArray = $this->nodeFactory->create($options)->render();
215  if (!empty($singleFieldContentArray['html'])) {
216  $foundRealElement = true;
217  $resultStructure[] = [
218  'type' => 'single',
219  'fieldName' => $fieldName,
220  'fieldHtml' => $singleFieldContentArray['html'],
221  ];
222  }
223  $this->resultArray = $this->‪mergeChildReturnIntoExistingResult($this->resultArray, $singleFieldContentArray, false);
224  }
225  }
226  if ($foundRealElement) {
227  return $resultStructure;
228  }
229  return [];
230  }
231 
238  protected function ‪renderInnerPaletteContent(array $elementArray): string
239  {
240  // Group fields
241  $groupedFields = [];
242  $row = 0;
243  $lastLineWasLinebreak = true;
244  foreach ($elementArray['elements'] as $element) {
245  if ($element['type'] === 'linebreak') {
246  if (!$lastLineWasLinebreak) {
247  $row++;
248  $groupedFields[$row][] = $element;
249  $row++;
250  $lastLineWasLinebreak = true;
251  }
252  } else {
253  $lastLineWasLinebreak = false;
254  $groupedFields[$row][] = $element;
255  }
256  }
257 
258  $result = [];
259  // Process fields
260  foreach ($groupedFields as ‪$fields) {
261  $numberOfItems = count(‪$fields);
262  $colWidth = (int)floor(12 / $numberOfItems);
263  // Column class calculation
264  $colClass = 'col-md-12';
265  $colClear = [];
266  if ($colWidth == 6) {
267  $colClass = 'col col-sm-6';
268  $colClear = [
269  2 => 'd-sm-block d-md-none',
270  ];
271  } elseif ($colWidth === 4) {
272  $colClass = 'col col-sm-4';
273  $colClear = [
274  3 => 'd-sm-block d-md-none',
275  ];
276  } elseif ($colWidth === 3) {
277  $colClass = 'col col-sm-6 col-md-3';
278  $colClear = [
279  2 => 'd-sm-block d-md-none',
280  4 => 'd-sm-block d-md-block d-xl-none',
281  ];
282  } elseif ($colWidth <= 2) {
283  $colClass = 'col col-sm-6 col-md-3 col-lg-2';
284  $colClear = [
285  2 => 'd-sm-block',
286  4 => 'd-sm-block d-md-none',
287  6 => 'd-sm-block d-md-block d-lg-none',
288  ];
289  }
290 
291  // Render fields
292  for ($counter = 0; $counter < $numberOfItems; $counter++) {
293  $element = ‪$fields[$counter];
294  if ($element['type'] === 'linebreak') {
295  if ($counter !== $numberOfItems) {
296  $result[] = '<div class="clearfix"></div>';
297  }
298  } else {
299  $result[] = '<div class="form-group t3js-formengine-validation-marker t3js-formengine-palette-field ' . $colClass . '">';
300  $result[] = $element['fieldHtml'];
301  $result[] = '</div>';
302  // Breakpoints
303  if ($counter + 1 < $numberOfItems && !empty($colClear)) {
304  foreach ($colClear as $rowBreakAfter => $clearClass) {
305  if (($counter + 1) % $rowBreakAfter === 0) {
306  $result[] = '<div class="clearfix ' . $clearClass . '"></div>';
307  }
308  }
309  }
310  }
311  }
312  }
313  return implode(LF, $result);
314  }
315 
317  {
318  return ‪$GLOBALS['LANG'];
319  }
320 }
‪TYPO3\CMS\Backend\Form\AbstractNode\mergeChildReturnIntoExistingResult
‪array mergeChildReturnIntoExistingResult(array $existing, array $childReturn, bool $mergeHtml=true)
Definition: AbstractNode.php:104
‪TYPO3\CMS\Backend\Form\Container\PaletteAndSingleContainer\getLanguageService
‪getLanguageService()
Definition: PaletteAndSingleContainer.php:316
‪TYPO3\CMS\Backend\Form\Container\PaletteAndSingleContainer\renderInnerPaletteContent
‪string renderInnerPaletteContent(array $elementArray)
Definition: PaletteAndSingleContainer.php:238
‪TYPO3\CMS\Backend\Form\Container
Definition: AbstractContainer.php:16
‪TYPO3\CMS\Backend\Form\Container\PaletteAndSingleContainer\createPaletteContentArray
‪createPaletteContentArray(string $paletteName)
Definition: PaletteAndSingleContainer.php:191
‪$fields
‪$fields
Definition: pages.php:5
‪TYPO3\CMS\Backend\Form\Container\AbstractContainer\explodeSingleFieldShowItemConfiguration
‪explodeSingleFieldShowItemConfiguration(string $field)
Definition: AbstractContainer.php:107
‪TYPO3\CMS\Backend\Form\AbstractNode\$data
‪array $data
Definition: AbstractNode.php:35
‪TYPO3\CMS\Backend\Form\Container\AbstractContainer
Definition: AbstractContainer.php:29
‪TYPO3\CMS\Backend\Form\Container\PaletteAndSingleContainer\$resultArray
‪array $resultArray
Definition: PaletteAndSingleContainer.php:37
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Backend\Form\Container\PaletteAndSingleContainer
Definition: PaletteAndSingleContainer.php:33
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static list< string > trimExplode(string $delim, string $string, bool $removeEmptyValues=false, int $limit=0)
Definition: GeneralUtility.php:822
‪TYPO3\CMS\Backend\Form\AbstractNode\initializeResultArray
‪initializeResultArray()
Definition: AbstractNode.php:77
‪TYPO3\CMS\Backend\Form\Container\PaletteAndSingleContainer\render
‪array render()
Definition: PaletteAndSingleContainer.php:44