‪TYPO3CMS  ‪main
SelectSingleElement.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 
23 
31 {
37  protected ‪$defaultFieldInformation = [
38  'tcaDescription' => [
39  'renderType' => 'tcaDescription',
40  ],
41  ];
42 
48  protected ‪$defaultFieldWizard = [
49  'selectIcons' => [
50  'renderType' => 'selectIcons',
51  'disabled' => true,
52  ],
53  'localizationStateSelector' => [
54  'renderType' => 'localizationStateSelector',
55  'after' => [
56  'selectIcons',
57  ],
58  ],
59  'otherLanguageContent' => [
60  'renderType' => 'otherLanguageContent',
61  'after' => [ 'localizationStateSelector' ],
62  ],
63  'defaultLanguageDifferences' => [
64  'renderType' => 'defaultLanguageDifferences',
65  'after' => [ 'otherLanguageContent' ],
66  ],
67  ];
68 
69  public function ‪__construct(
70  private readonly ‪InlineStackProcessor $inlineStackProcessor,
71  ) {}
72 
78  public function ‪render(): array
79  {
80  $resultArray = $this->‪initializeResultArray();
81 
82  $table = $this->data['tableName'];
83  $field = $this->data['fieldName'];
84  $parameterArray = $this->data['parameterArray'];
85  $config = $parameterArray['fieldConf']['config'];
86 
87  $selectItems = $parameterArray['fieldConf']['config']['items'];
88  $classList = ['form-select', 'form-control-adapt'];
89 
90  // Check against inline uniqueness
91  $this->inlineStackProcessor->initializeByGivenStructure($this->data['inlineStructure']);
92  $uniqueIds = [];
93  if (($this->data['isInlineChild'] ?? false) && ($this->data['inlineParentUid'] ?? false)) {
94  // If config[foreign_unique] is set for the parent inline field, all
95  // already used unique ids must be excluded from the select items.
96  $inlineObjectName = $this->inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']);
97  if (($this->data['inlineParentConfig']['foreign_table'] ?? false) === $table
98  && ($this->data['inlineParentConfig']['foreign_unique'] ?? false) === $field
99  ) {
100  $classList[] = 't3js-inline-unique';
101  $uniqueIds = $this->data['inlineData']['unique'][$inlineObjectName . '-' . $table]['used'] ?? [];
102  }
103  // hide uid of parent record for symmetric relations
104  if (($this->data['inlineParentConfig']['foreign_table'] ?? false) === $table
105  && (
106  ($this->data['inlineParentConfig']['foreign_field'] ?? false) === $field
107  || ($this->data['inlineParentConfig']['symmetric_field'] ?? false) === $field
108  )
109  ) {
110  $uniqueIds[] = $this->data['inlineParentUid'];
111  }
112  $uniqueIds = array_map(intval(...), $uniqueIds);
113  }
114 
115  // Initialization:
116  $selectId = ‪StringUtility::getUniqueId('tceforms-select-');
117  $selectedIcon = '';
118  $size = (int)($config['size'] ?? 0);
119 
120  // Style set on <select/>
121  $options = '';
122  $disabled = false;
123  if (!empty($config['readOnly'])) {
124  $disabled = true;
125  }
126 
127  // Prepare groups
128  $selectItemCounter = 0;
129  $selectItemGroupCount = 0;
130  $selectItemGroups = [];
131  $selectedValue = '';
132  $hasIcons = false;
133 
134  // In case e.g. "l10n_display" is set to "defaultAsReadonly" only one value (as string) could be handed in
135  if (!empty($parameterArray['itemFormElValue'])) {
136  if (is_array($parameterArray['itemFormElValue'])) {
137  $selectedValue = (string)$parameterArray['itemFormElValue'][0];
138  } else {
139  $selectedValue = (string)$parameterArray['itemFormElValue'];
140  }
141  }
142 
143  foreach ($selectItems as $item) {
144  $selected = $selectedValue === (string)$item['value'];
145 
146  if ($item['value'] === '--div--') {
147  // IS OPTGROUP
148  if ($selectItemCounter !== 0) {
149  $selectItemGroupCount++;
150  }
151  $selectItemGroups[$selectItemGroupCount]['header'] = [
152  'title' => $item['label'],
153  ];
154  } elseif ($selected || !in_array((int)$item['value'], $uniqueIds, true)) {
155  $icon = !empty($item['icon']) ? ‪FormEngineUtility::getIconHtml($item['icon'], $item['label'], $item['label']) : '';
156 
157  if ($selected) {
158  $selectedIcon = $icon;
159  }
160 
161  $selectItemGroups[$selectItemGroupCount]['items'][] = [
162  'title' => $this->‪appendValueToLabelInDebugMode($item['label'], $item['value']),
163  'value' => $item['value'],
164  'icon' => $icon,
165  'selected' => $selected,
166  ];
167  $selectItemCounter++;
168  }
169  }
170 
171  // Fallback icon
172  // @todo: assign a special icon for non matching values?
173  if (!$selectedIcon && !empty($selectItemGroups[0]['items'][0]['icon'])) {
174  $selectedIcon = $selectItemGroups[0]['items'][0]['icon'];
175  }
176 
177  // Process groups
178  foreach ($selectItemGroups as $selectItemGroup) {
179  // suppress groups without items
180  if (empty($selectItemGroup['items'])) {
181  continue;
182  }
183 
184  $optionGroup = is_array($selectItemGroup['header'] ?? null);
185  $options .= ($optionGroup ? '<optgroup label="' . htmlspecialchars($selectItemGroup['header']['title'], ENT_COMPAT, 'UTF-8', false) . '">' : '');
186 
187  if (is_array($selectItemGroup['items'])) {
188  foreach ($selectItemGroup['items'] as $item) {
189  $options .= '<option value="' . htmlspecialchars($item['value']) . '" data-icon="' .
190  htmlspecialchars($item['icon']) . '"'
191  . ($item['selected'] ? ' selected="selected"' : '') . '>' . htmlspecialchars((string)($item['title'] ?? ''), ENT_COMPAT, 'UTF-8', false) . '</option>';
192  }
193  $hasIcons = !empty($item['icon']);
194  }
195 
196  $options .= ($optionGroup ? '</optgroup>' : '');
197  }
198 
199  $selectAttributes = [
200  'id' => $selectId,
201  'name' => (string)($parameterArray['itemFormElName'] ?? ''),
202  'data-formengine-validation-rules' => $this->‪getValidationDataAsJsonString($config),
203  'class' => implode(' ', $classList),
204  ];
205  if ($size) {
206  $selectAttributes['size'] = (string)$size;
207  }
208  if ($disabled) {
209  $selectAttributes['disabled'] = 'disabled';
210  }
211 
212  $fieldInformationResult = $this->‪renderFieldInformation();
213  $fieldInformationHtml = $fieldInformationResult['html'];
214  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldInformationResult, false);
215 
216  $fieldControlResult = $this->‪renderFieldControl();
217  $fieldControlHtml = $fieldControlResult['html'];
218  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldControlResult, false);
219 
220  $fieldWizardResult = $this->‪renderFieldWizard();
221  $fieldWizardHtml = $fieldWizardResult['html'];
222  $resultArray = $this->‪mergeChildReturnIntoExistingResult($resultArray, $fieldWizardResult, false);
223 
224  $html = [];
225  $html[] = $this->‪renderLabel($selectId);
226  $html[] = '<div class="formengine-field-item t3js-formengine-field-item">';
227  $html[] = $fieldInformationHtml;
228  $html[] = '<div class="form-control-wrap">';
229  $html[] = '<div class="form-wizards-wrap">';
230  $html[] = '<div class="form-wizards-element">';
231  if ($hasIcons) {
232  $html[] = '<div class="input-group">';
233  $html[] = '<span class="input-group-text input-group-icon">';
234  $html[] = $selectedIcon;
235  $html[] = '</span>';
236  }
237  $html[] = '<select ' . GeneralUtility::implodeAttributes($selectAttributes, true) . '>';
238  $html[] = $options;
239  $html[] = '</select>';
240  if ($hasIcons) {
241  $html[] = '</div>';
242  }
243  $html[] = '</div>';
244  if (!$disabled && !empty($fieldControlHtml)) {
245  $html[] = '<div class="form-wizards-items-aside form-wizards-items-aside--field-control">';
246  $html[] = '<div class="btn-group">';
247  $html[] = $fieldControlHtml;
248  $html[] = '</div>';
249  $html[] = '</div>';
250  }
251  if (!$disabled && !empty($fieldWizardHtml)) {
252  $html[] = '<div class="form-wizards-items-bottom">';
253  $html[] = $fieldWizardHtml;
254  $html[] = '</div>';
255  }
256  $html[] = '</div>';
257  $html[] = '</div>';
258  $html[] = '</div>';
259 
260  $onFieldChangeItems = $this->getOnFieldChangeItems($parameterArray['fieldChangeFunc'] ?? []);
261  $resultArray['javaScriptModules']['selectSingleElement'] = ‪JavaScriptModuleInstruction::create(
262  '@typo3/backend/form-engine/element/select-single-element.js'
263  )->invoke('initializeOnReady', '#' . $selectId, ['onChange' => $onFieldChangeItems]);
264 
265  $resultArray['html'] = implode(LF, $html);
266  return $resultArray;
267  }
268 }
‪TYPO3\CMS\Backend\Form\Element\SelectSingleElement\$defaultFieldWizard
‪array $defaultFieldWizard
Definition: SelectSingleElement.php:46
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldInformation
‪array renderFieldInformation()
Definition: AbstractFormElement.php:73
‪TYPO3\CMS\Backend\Form\AbstractNode\mergeChildReturnIntoExistingResult
‪array mergeChildReturnIntoExistingResult(array $existing, array $childReturn, bool $mergeHtml=true)
Definition: AbstractNode.php:104
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction\create
‪static create(string $name, string $exportName=null)
Definition: JavaScriptModuleInstruction.php:47
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement
Definition: AbstractFormElement.php:37
‪TYPO3\CMS\Core\Page\JavaScriptModuleInstruction
Definition: JavaScriptModuleInstruction.php:23
‪TYPO3\CMS\Backend\Form\Element
Definition: AbstractFormElement.php:16
‪TYPO3\CMS\Backend\Form\Utility\FormEngineUtility
Definition: FormEngineUtility.php:41
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldControl
‪array renderFieldControl()
Definition: AbstractFormElement.php:89
‪TYPO3\CMS\Backend\Form\Element\SelectSingleElement\$defaultFieldInformation
‪array $defaultFieldInformation
Definition: SelectSingleElement.php:36
‪TYPO3\CMS\Backend\Form\Utility\FormEngineUtility\getIconHtml
‪static string getIconHtml($icon, $alt='', $title='')
Definition: FormEngineUtility.php:134
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\appendValueToLabelInDebugMode
‪appendValueToLabelInDebugMode(string|int $label, string|int $value)
Definition: AbstractFormElement.php:447
‪TYPO3\CMS\Backend\Form\AbstractNode\getValidationDataAsJsonString
‪getValidationDataAsJsonString(array $config)
Definition: AbstractNode.php:133
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderLabel
‪renderLabel(string $for)
Definition: AbstractFormElement.php:119
‪TYPO3\CMS\Backend\Form\InlineStackProcessor
Definition: InlineStackProcessor.php:32
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Backend\Form\Element\SelectSingleElement
Definition: SelectSingleElement.php:31
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:24
‪TYPO3\CMS\Backend\Form\Element\SelectSingleElement\__construct
‪__construct(private readonly InlineStackProcessor $inlineStackProcessor,)
Definition: SelectSingleElement.php:67
‪TYPO3\CMS\Backend\Form\Element\AbstractFormElement\renderFieldWizard
‪array renderFieldWizard()
Definition: AbstractFormElement.php:105
‪TYPO3\CMS\Backend\Form\Element\SelectSingleElement\render
‪array render()
Definition: SelectSingleElement.php:76
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static getUniqueId(string $prefix='')
Definition: StringUtility.php:57
‪TYPO3\CMS\Backend\Form\AbstractNode\initializeResultArray
‪initializeResultArray()
Definition: AbstractNode.php:77