‪TYPO3CMS  10.4
GroupElement.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
24 
29 {
35  protected ‪$defaultFieldInformation = [
36  'tcaDescription' => [
37  'renderType' => 'tcaDescription',
38  ],
39  ];
40 
46  protected ‪$defaultFieldControl = [
47  'elementBrowser' => [
48  'renderType' => 'elementBrowser',
49  ],
50  'insertClipboard' => [
51  'renderType' => 'insertClipboard',
52  'after' => [ 'elementBrowser' ],
53  ],
54  'editPopup' => [
55  'renderType' => 'editPopup',
56  'disabled' => true,
57  'after' => [ 'insertClipboard' ],
58  ],
59  'addRecord' => [
60  'renderType' => 'addRecord',
61  'disabled' => true,
62  'after' => [ 'editPopup' ],
63  ],
64  'listModule' => [
65  'renderType' => 'listModule',
66  'disabled' => true,
67  'after' => [ 'addRecord' ],
68  ],
69  ];
70 
76  protected ‪$defaultFieldWizard = [
77  'tableList' => [
78  'renderType' => 'tableList',
79  ],
80  'recordsOverview' => [
81  'renderType' => 'recordsOverview',
82  'after' => [ 'tableList' ],
83  ],
84  'localizationStateSelector' => [
85  'renderType' => 'localizationStateSelector',
86  'after' => [ 'recordsOverview' ],
87  ],
88  'otherLanguageContent' => [
89  'renderType' => 'otherLanguageContent',
90  'after' => [ 'localizationStateSelector' ],
91  ],
92  'defaultLanguageDifferences' => [
93  'renderType' => 'defaultLanguageDifferences',
94  'after' => [ 'otherLanguageContent' ],
95  ],
96  ];
97 
105  public function ‪render()
106  {
107  $languageService = $this->‪getLanguageService();
108  $backendUser = $this->‪getBackendUserAuthentication();
109  $resultArray = $this->‪initializeResultArray();
110 
111  $table = $this->data['tableName'];
112  $fieldName = $this->data['fieldName'];
113  $row = $this->data['databaseRow'];
114  $parameterArray = $this->data['parameterArray'];
115  $config = $parameterArray['fieldConf']['config'];
116  $elementName = $parameterArray['itemFormElName'];
117 
118  $selectedItems = $parameterArray['itemFormElValue'];
119  $selectedItemsCount = count($selectedItems);
120 
121  $maxItems = $config['maxitems'];
122  $autoSizeMax = ‪MathUtility::forceIntegerInRange($config['autoSizeMax'], 0);
123  $size = 5;
124  if (isset($config['size'])) {
125  $size = (int)$config['size'];
126  }
127  if ($autoSizeMax >= 1) {
128  $size = ‪MathUtility::forceIntegerInRange($selectedItemsCount + 1, ‪MathUtility::forceIntegerInRange($size, 1), $autoSizeMax);
129  }
130 
131  $internalType = (string)$config['internal_type'];
132  $maxTitleLength = $backendUser->uc['titleLen'];
133 
134  $listOfSelectedValues = [];
135  $selectorOptionsHtml = [];
136  if ($internalType === 'folder') {
137  foreach ($selectedItems as $selectedItem) {
138  $folder = $selectedItem['folder'];
139  $listOfSelectedValues[] = $folder;
140  $selectorOptionsHtml[] =
141  '<option value="' . htmlspecialchars($folder) . '" title="' . htmlspecialchars($folder) . '">'
142  . htmlspecialchars($folder)
143  . '</option>';
144  }
145  } elseif ($internalType === 'db') {
146  foreach ($selectedItems as $selectedItem) {
147  $tableWithUid = $selectedItem['table'] . '_' . $selectedItem['uid'];
148  $listOfSelectedValues[] = $tableWithUid;
149  $title = $selectedItem['title'];
150  if (empty($title)) {
151  $title = '[' . $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title') . ']';
152  }
153  $shortenedTitle = GeneralUtility::fixed_lgd_cs($title, $maxTitleLength);
154  $selectorOptionsHtml[] =
155  '<option value="' . htmlspecialchars($tableWithUid) . '" title="' . htmlspecialchars($title) . '">'
156  . htmlspecialchars($this->‪appendValueToLabelInDebugMode($shortenedTitle, $tableWithUid))
157  . '</option>';
158  }
159  } else {
160  throw new \RuntimeException(
161  'internal_type missing on type="group" field',
162  1485007097
163  );
164  }
165 
166  $fieldInformationResult = $this->‪renderFieldInformation();
167  $fieldInformationHtml = $fieldInformationResult['html'];
168  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
169 
170  if (isset($config['readOnly']) && $config['readOnly']) {
171  // Return early if element is read only
172  $html = [];
173  $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
174  $html[] = $fieldInformationHtml;
175  $html[] = '<div class="form-wizards-wrap">';
176  $html[] = '<div class="form-wizards-element">';
177  $html[] = '<select';
178  $html[] = ' size="' . $size . '"';
179  $html[] = ' disabled="disabled"';
180  $html[] = ' class="form-control tceforms-multiselect"';
181  $html[] = ($maxItems !== 1 && $size !== 1) ? ' multiple="multiple"' : '';
182  $html[] = '>';
183  $html[] = implode(LF, $selectorOptionsHtml);
184  $html[] = '</select>';
185  $html[] = '</div>';
186  $html[] = '<div class="form-wizards-items-aside">';
187  $html[] = '</div>';
188  $html[] = '</div>';
189  $html[] = '</div>';
190  $resultArray['html'] = implode(LF, $html);
191  return $resultArray;
192  }
193 
194  // Need some information if in flex form scope for the suggest element
195  $dataStructureIdentifier = '';
196  $flexFormSheetName = '';
197  $flexFormFieldName = '';
198  $flexFormContainerName = '';
199  $flexFormContainerFieldName = '';
200  if ($this->data['processedTca']['columns'][$fieldName]['config']['type'] === 'flex') {
201  $flexFormConfig = $this->data['processedTca']['columns'][$fieldName];
202  $dataStructureIdentifier = $flexFormConfig['config']['dataStructureIdentifier'];
203  if (!isset($flexFormConfig['config']['dataStructureIdentifier'])) {
204  throw new \RuntimeException(
205  'A data structure identifier must be set in [\'config\'] part of a flex form.'
206  . ' This is usually added by TcaFlexPrepare data processor',
207  1485206970
208  );
209  }
210  if (isset($this->data['flexFormSheetName'])) {
211  $flexFormSheetName = $this->data['flexFormSheetName'];
212  }
213  if (isset($this->data['flexFormFieldName'])) {
214  $flexFormFieldName = $this->data['flexFormFieldName'];
215  }
216  if (isset($this->data['flexFormContainerName'])) {
217  $flexFormContainerName = $this->data['flexFormContainerName'];
218  }
219  if (isset($this->data['flexFormContainerFieldName'])) {
220  $flexFormContainerFieldName = $this->data['flexFormContainerFieldName'];
221  }
222  }
223  // Get minimum characters for suggest from TCA and override by TsConfig
224  $suggestMinimumCharacters = 0;
225  if (isset($config['suggestOptions']['default']['minimumCharacters'])) {
226  $suggestMinimumCharacters = (int)$config['suggestOptions']['default']['minimumCharacters'];
227  }
228  if (isset($parameterArray['fieldTSConfig']['suggest.']['default.']['minimumCharacters'])) {
229  $suggestMinimumCharacters = (int)$parameterArray['fieldTSConfig']['suggest.']['default.']['minimumCharacters'];
230  }
231  $suggestMinimumCharacters = $suggestMinimumCharacters > 0 ? $suggestMinimumCharacters : 2;
232 
233  $itemCanBeSelectedMoreThanOnce = !empty($config['multiple']);
234 
235  $showMoveIcons = true;
236  if (isset($config['hideMoveIcons']) && $config['hideMoveIcons']) {
237  $showMoveIcons = false;
238  }
239  $showDeleteControl = true;
240  if (isset($config['hideDeleteIcon']) && $config['hideDeleteIcon']) {
241  $showDeleteControl = false;
242  }
243 
244  $fieldId = ‪StringUtility::getUniqueId('tceforms-multiselect-');
245 
246  $selectorAttributes = [
247  'id' => $fieldId,
248  'data-formengine-input-name' => htmlspecialchars($elementName),
249  'data-maxitems' => (string)$maxItems,
250  'size' => (string)$size,
251  ];
252  $selectorClasses = [
253  'form-control',
254  'tceforms-multiselect',
255  ];
256  if ($maxItems === 1) {
257  $selectorClasses[] = 'form-select-no-siblings';
258  }
259  $selectorAttributes['class'] = implode(' ', $selectorClasses);
260  if ($maxItems !== 1 && $size !== 1) {
261  $selectorAttributes['multiple'] = 'multiple';
262  }
263 
264  $fieldControlResult = $this->‪renderFieldControl();
265  $fieldControlHtml = $fieldControlResult['html'];
266  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false);
267 
268  $fieldWizardResult = $this->‪renderFieldWizard();
269  $fieldWizardHtml = $fieldWizardResult['html'];
270  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
271 
272  $html = [];
273  $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
274  $html[] = $fieldInformationHtml;
275  $html[] = '<div class="form-wizards-wrap">';
276  if ($internalType === 'db' && (!isset($config['hideSuggest']) || (bool)$config['hideSuggest'] !== true)) {
277  $html[] = '<div class="form-wizards-items-top">';
278  $html[] = '<div class="autocomplete t3-form-suggest-container">';
279  $html[] = '<div class="input-group">';
280  $html[] = '<span class="input-group-addon">';
281  $html[] = $this->iconFactory->getIcon('actions-search', ‪Icon::SIZE_SMALL)->render();
282  $html[] = '</span>';
283  $html[] = '<input type="search" class="t3-form-suggest form-control"';
284  $html[] = ' placeholder="' . $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.findRecord') . '"';
285  $html[] = ' data-fieldname="' . htmlspecialchars($fieldName) . '"';
286  $html[] = ' data-tablename="' . htmlspecialchars($table) . '"';
287  $html[] = ' data-field="' . htmlspecialchars($elementName) . '"';
288  $html[] = ' data-uid="' . htmlspecialchars($this->data['databaseRow']['uid']) . '"';
289  $html[] = ' data-pid="' . htmlspecialchars($this->data['parentPageRow']['uid'] ?? 0) . '"';
290  $html[] = ' data-fieldtype="' . htmlspecialchars($config['type']) . '"';
291  $html[] = ' data-minchars="' . htmlspecialchars((string)$suggestMinimumCharacters) . '"';
292  $html[] = ' data-datastructureidentifier="' . htmlspecialchars($dataStructureIdentifier) . '"';
293  $html[] = ' data-flexformsheetname="' . htmlspecialchars($flexFormSheetName) . '"';
294  $html[] = ' data-flexformfieldname="' . htmlspecialchars($flexFormFieldName) . '"';
295  $html[] = ' data-flexformcontainername="' . htmlspecialchars($flexFormContainerName) . '"';
296  $html[] = ' data-flexformcontainerfieldname="' . htmlspecialchars($flexFormContainerFieldName) . '"';
297  $html[] = '/>';
298  $html[] = '</div>';
299  $html[] = '</div>';
300  $html[] = '</div>';
301  }
302  $html[] = '<div class="form-wizards-element">';
303  $html[] = '<input type="hidden" class="t3js-group-hidden-field" data-formengine-input-name="' . htmlspecialchars($elementName) . '" value="' . $itemCanBeSelectedMoreThanOnce . '" />';
304  $html[] = '<select ' . GeneralUtility::implodeAttributes($selectorAttributes, true) . '>';
305  $html[] = implode(LF, $selectorOptionsHtml);
306  $html[] = '</select>';
307  $html[] = '</div>';
308  $html[] = '<div class="form-wizards-items-aside">';
309  $html[] = '<div class="btn-group-vertical">';
310  if ($maxItems > 1 && $size >=5 && $showMoveIcons) {
311  $html[] = '<a href="#"';
312  $html[] = ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-top"';
313  $html[] = ' data-fieldname="' . htmlspecialchars($elementName) . '"';
314  $html[] = ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_to_top')) . '"';
315  $html[] = '>';
316  $html[] = $this->iconFactory->getIcon('actions-move-to-top', ‪Icon::SIZE_SMALL)->render();
317  $html[] = '</a>';
318  }
319  if ($maxItems > 1 && $size > 1 && $showMoveIcons) {
320  $html[] = '<a href="#"';
321  $html[] = ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-up"';
322  $html[] = ' data-fieldname="' . htmlspecialchars($elementName) . '"';
323  $html[] = ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_up')) . '"';
324  $html[] = '>';
325  $html[] = $this->iconFactory->getIcon('actions-move-up', ‪Icon::SIZE_SMALL)->render();
326  $html[] = '</a>';
327  $html[] = '<a href="#"';
328  $html[] = ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-down"';
329  $html[] = ' data-fieldname="' . htmlspecialchars($elementName) . '"';
330  $html[] = ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_down')) . '"';
331  $html[] = '>';
332  $html[] = $this->iconFactory->getIcon('actions-move-down', ‪Icon::SIZE_SMALL)->render();
333  $html[] = '</a>';
334  }
335  if ($maxItems > 1 && $size >= 5 && $showMoveIcons) {
336  $html[] = '<a href="#"';
337  $html[] = ' class="btn btn-default t3js-btn-option t3js-btn-moveoption-bottom"';
338  $html[] = ' data-fieldname="' . htmlspecialchars($elementName) . '"';
339  $html[] = ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.move_to_bottom')) . '"';
340  $html[] = '>';
341  $html[] = $this->iconFactory->getIcon('actions-move-to-bottom', ‪Icon::SIZE_SMALL)->render();
342  $html[] = '</a>';
343  }
344  if ($showDeleteControl) {
345  $html[] = '<a href="#"';
346  $html[] = ' class="btn btn-default t3js-btn-option t3js-btn-removeoption t3js-revert-unique"';
347  $html[] = ' data-fieldname="' . htmlspecialchars($elementName) . '"';
348  $html[] = ' data-uid="' . htmlspecialchars($row['uid']) . '"';
349  $html[] = ' title="' . htmlspecialchars($languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.remove_selected')) . '"';
350  $html[] = '>';
351  $html[] = $this->iconFactory->getIcon('actions-selection-delete', ‪Icon::SIZE_SMALL)->render();
352  $html[] = '</a>';
353  }
354  $html[] = '</div>';
355  $html[] = '</div>';
356  $html[] = '<div class="form-wizards-items-aside">';
357  $html[] = '<div class="btn-group-vertical">';
358  $html[] = $fieldControlHtml;
359  $html[] = '</div>';
360  $html[] = '</div>';
361  if (!empty($fieldWizardHtml)) {
362  $html[] = '<div class="form-wizards-items-bottom">';
363  $html[] = $fieldWizardHtml;
364  $html[] = '</div>';
365  }
366  $html[] = '</div>';
367  $html[] = '<input type="hidden"';
368  $html[] = ' data-formengine-validation-rules="' . htmlspecialchars($this->‪getValidationDataAsJsonString($config)) . '"';
369  $html[] = ' name="' . htmlspecialchars($elementName) . '"';
370  $html[] = ' value="' . htmlspecialchars(implode(',', $listOfSelectedValues)) . '"';
371  $html[] = ' onchange="' . htmlspecialchars(implode('', $parameterArray['fieldChangeFunc'])) . '"';
372  $html[] = ' />';
373  $html[] = '</div>';
374 
375  $resultArray['requireJsModules'][] = ['TYPO3/CMS/Backend/FormEngine/Element/GroupElement' => '
376  function(GroupElement) {
377  new GroupElement(' . GeneralUtility::quoteJSvalue($fieldId) . ');
378  }'
379  ];
380 
381  $resultArray['html'] = implode(LF, $html);
382  return $resultArray;
383  }
384 
388  protected function ‪getBackendUserAuthentication()
389  {
390  return ‪$GLOBALS['BE_USER'];
391  }
392 
396  protected function ‪getLanguageService()
397  {
398  return ‪$GLOBALS['LANG'];
399  }
400 }
‪TYPO3\CMS\Core\Imaging\Icon\SIZE_SMALL
‪const SIZE_SMALL
Definition: Icon.php:30
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldInformation
‪array renderFieldInformation()
Definition: AbstractFormElement.php:72
‪TYPO3\CMS\Backend\Form\Element\GroupElement\$defaultFieldWizard
‪array $defaultFieldWizard
Definition: GroupElement.php:73
‪TYPO3\CMS\Backend\Form\AbstractNode\mergeChildReturnIntoExistingResult
‪array mergeChildReturnIntoExistingResult(array $existing, array $childReturn, bool $mergeHtml=true)
Definition: AbstractNode.php:116
‪TYPO3\CMS\Backend\Form\AbstractNode\initializeResultArray
‪array initializeResultArray()
Definition: AbstractNode.php:90
‪TYPO3\CMS\Core\Imaging\Icon
Definition: Icon.php:26
‪TYPO3\CMS\Core\Utility\MathUtility\forceIntegerInRange
‪static int forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:32
‪TYPO3\CMS\Backend\Form\Element\GroupElement\render
‪array render()
Definition: GroupElement.php:102
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement
Definition: AbstractFormElement.php:32
‪TYPO3\CMS\Backend\Form\Element\GroupElement\getBackendUserAuthentication
‪BackendUserAuthentication getBackendUserAuthentication()
Definition: GroupElement.php:385
‪TYPO3\CMS\Backend\Form\Element
Definition: AbstractFormElement.php:16
‪TYPO3\CMS\Backend\Form\Element\GroupElement
Definition: GroupElement.php:29
‪TYPO3\CMS\Backend\Form\AbstractNode\getValidationDataAsJsonString
‪string getValidationDataAsJsonString(array $config)
Definition: AbstractNode.php:151
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldControl
‪array renderFieldControl()
Definition: AbstractFormElement.php:88
‪TYPO3\CMS\Backend\Form\Element\GroupElement\getLanguageService
‪LanguageService getLanguageService()
Definition: GroupElement.php:393
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\appendValueToLabelInDebugMode
‪string appendValueToLabelInDebugMode($label, $value)
Definition: AbstractFormElement.php:378
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static string getUniqueId($prefix='')
Definition: StringUtility.php:92
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Backend\Form\Element\GroupElement\$defaultFieldInformation
‪array $defaultFieldInformation
Definition: GroupElement.php:34
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:22
‪TYPO3\CMS\Backend\Form\Element\GroupElement\$defaultFieldControl
‪array $defaultFieldControl
Definition: GroupElement.php:44
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldWizard
‪array renderFieldWizard()
Definition: AbstractFormElement.php:104