[BUGFIX] Prevent PHP warning when trying to loop over null
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / Element / SelectMultipleSideBySideElement.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form\Element;
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\Utility\GeneralUtility;
20 use TYPO3\CMS\Core\Utility\MathUtility;
21 use TYPO3\CMS\Core\Utility\StringUtility;
22
23 /**
24 * Render a widget with two boxes side by side.
25 *
26 * This is rendered for config type=select, maxitems > 1, no other renderMode set
27 */
28 class SelectMultipleSideBySideElement extends AbstractFormElement
29 {
30 /**
31 * Render side by side element.
32 *
33 * @return array As defined in initializeResultArray() of AbstractNode
34 */
35 public function render()
36 {
37 $table = $this->data['tableName'];
38 $field = $this->data['fieldName'];
39 $parameterArray = $this->data['parameterArray'];
40 // Field configuration from TCA:
41 $config = $parameterArray['fieldConf']['config'];
42
43 // Creating the label for the "No Matching Value" entry.
44 $noMatchingLabel = isset($parameterArray['fieldTSConfig']['noMatchingValue_label'])
45 ? $this->getLanguageService()->sL($parameterArray['fieldTSConfig']['noMatchingValue_label'])
46 : '[ ' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.noMatchingValue') . ' ]';
47
48 $selItems = $config['items'];
49 $html = '';
50 $disabled = '';
51 if ($config['readOnly']) {
52 $disabled = ' disabled="disabled"';
53 }
54 // Setting this hidden field (as a flag that JavaScript can read out)
55 if (!$disabled) {
56 $html .= '<input type="hidden" data-formengine-input-name="' . htmlspecialchars($parameterArray['itemFormElName']) . '" value="' . ($config['multiple'] ? 1 : 0) . '" />';
57 }
58 // Set max and min items:
59 $maxitems = MathUtility::forceIntegerInRange($config['maxitems'], 0);
60 if (!$maxitems) {
61 $maxitems = 100000;
62 }
63 // Get "removeItems":
64 $removeItems = GeneralUtility::trimExplode(',', $parameterArray['fieldTSConfig']['removeItems'], true);
65 // Get the array with selected items:
66 $itemsArray = $parameterArray['itemFormElValue'] ?: [];
67
68 // Perform modification of the selected items array:
69 // @todo: this part should probably be moved to TcaSelectItems provider?!
70 foreach ($itemsArray as $itemNumber => $itemValue) {
71 $itemArray = array(
72 0 => $itemValue,
73 1 => '',
74 );
75 $itemIcon = null;
76 $isRemoved = in_array($itemValue, $removeItems)
77 || $config['type'] == 'select' && $config['authMode']
78 && !$this->getBackendUserAuthentication()->checkAuthMode($table, $field, $itemValue, $config['authMode']);
79 if ($isRemoved && !$parameterArray['fieldTSConfig']['disableNoMatchingValueElement'] && !$config['disableNoMatchingValueElement']) {
80 $itemArray[1] = rawurlencode(@sprintf($noMatchingLabel, $itemValue));
81 } else {
82 if (isset($parameterArray['fieldTSConfig']['altLabels.'][$itemValue])) {
83 $itemArray[1] = rawurlencode($this->getLanguageService()->sL($parameterArray['fieldTSConfig']['altLabels.'][$itemValue]));
84 }
85 if (isset($parameterArray['fieldTSConfig']['altIcons.'][$itemValue])) {
86 $itemArray[2] = $parameterArray['fieldTSConfig']['altIcons.'][$itemValue];
87 }
88 }
89 if ($itemArray[1] === '') {
90 foreach ($selItems as $selItem) {
91 if ($selItem[1] == $itemValue) {
92 $itemArray[1] = $selItem[0];
93 break;
94 }
95 }
96 }
97 $itemsArray[$itemNumber] = implode('|', $itemArray);
98 }
99
100 // size must be at least two, as there are always maxitems > 1 (see parent function)
101 if (isset($config['size'])) {
102 $size = (int)$config['size'];
103 } else {
104 $size = 2;
105 }
106 $size = $config['autoSizeMax'] ? MathUtility::forceIntegerInRange(count($itemsArray) + 1, MathUtility::forceIntegerInRange($size, 1), $config['autoSizeMax']) : $size;
107
108 $itemsToSelect = [];
109 $filterTextfield = [];
110 $filterSelectbox = '';
111 if (!$disabled) {
112 // Create option tags:
113 $opt = array();
114 foreach ($selItems as $p) {
115 $opt[] = '<option value="' . htmlspecialchars($p[1]) . '" title="' . $p[0] . '">' . $p[0] . '</option>';
116 }
117 // Put together the selector box:
118 $selector_itemListStyle = isset($config['itemListStyle'])
119 ? ' style="' . htmlspecialchars($config['itemListStyle']) . '"'
120 : '';
121 $sOnChange = implode('', $parameterArray['fieldChangeFunc']);
122
123 $multiSelectId = StringUtility::getUniqueId('tceforms-multiselect-');
124 $itemsToSelect[] = '<select data-relatedfieldname="' . htmlspecialchars($parameterArray['itemFormElName']) . '" '
125 . 'data-exclusivevalues="' . htmlspecialchars($config['exclusiveKeys']) . '" '
126 . 'id="' . $multiSelectId . '" '
127 . 'data-formengine-input-name="' . htmlspecialchars($parameterArray['itemFormElName']) . '" '
128 . 'class="form-control t3js-formengine-select-itemstoselect" '
129 . ($size ? ' size="' . $size . '" ' : '')
130 . 'onchange="' . htmlspecialchars($sOnChange) . '" '
131 . $parameterArray['onFocus']
132 . $this->getValidationDataAsDataAttribute($config)
133 . $selector_itemListStyle
134 . '>';
135 $itemsToSelect[] = implode(LF, $opt);
136 $itemsToSelect[] = '</select>';
137
138 // enable filter functionality via a text field
139 if ($config['enableMultiSelectFilterTextfield']) {
140 $filterTextfield[] = '<span class="input-group input-group-sm">';
141 $filterTextfield[] = '<span class="input-group-addon">';
142 $filterTextfield[] = '<span class="fa fa-filter"></span>';
143 $filterTextfield[] = '</span>';
144 $filterTextfield[] = '<input class="t3js-formengine-multiselect-filter-textfield form-control" value="">';
145 $filterTextfield[] = '</span>';
146 }
147
148 // enable filter functionality via a select
149 if (isset($config['multiSelectFilterItems']) && is_array($config['multiSelectFilterItems']) && count($config['multiSelectFilterItems']) > 1) {
150 $filterDropDownOptions = array();
151 foreach ($config['multiSelectFilterItems'] as $optionElement) {
152 $optionValue = $this->getLanguageService()->sL(isset($optionElement[1]) && $optionElement[1] != '' ? $optionElement[1]
153 : $optionElement[0]);
154 $filterDropDownOptions[] = '<option value="' . htmlspecialchars($this->getLanguageService()->sL($optionElement[0])) . '">'
155 . htmlspecialchars($optionValue) . '</option>';
156 }
157 $filterSelectbox = '<select class="form-control input-sm t3js-formengine-multiselect-filter-dropdown">'
158 . implode(LF, $filterDropDownOptions) . '</select>';
159 }
160 }
161
162 if (!empty(trim($filterSelectbox)) && !empty($filterTextfield)) {
163 $filterSelectbox = '<div class="form-multigroup-item form-multigroup-element">' . $filterSelectbox . '</div>';
164 $filterTextfield = '<div class="form-multigroup-item form-multigroup-element">' . implode(LF, $filterTextfield) . '</div>';
165 $selectBoxFilterContents = '<div class="t3js-formengine-multiselect-filter-container form-multigroup-wrap">' . $filterSelectbox . $filterTextfield . '</div>';
166 } else {
167 $selectBoxFilterContents = trim($filterSelectbox . ' ' . implode(LF, $filterTextfield));
168 }
169
170 // Pass to "dbFileIcons" function:
171 $params = array(
172 'size' => $size,
173 'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
174 'style' => isset($config['selectedListStyle'])
175 ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
176 : '',
177 'dontShowMoveIcons' => $maxitems <= 1,
178 'maxitems' => $maxitems,
179 'info' => '',
180 'headers' => array(
181 'selector' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.selected'),
182 'items' => $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.items'),
183 'selectorbox' => $selectBoxFilterContents,
184 ),
185 'noBrowser' => 1,
186 'rightbox' => implode(LF, $itemsToSelect),
187 'readOnly' => $disabled
188 );
189 $html .= $this->dbFileIcons($parameterArray['itemFormElName'], '', '', $itemsArray, '', $params, $parameterArray['onFocus']);
190
191 // Wizards:
192 if (!$disabled) {
193 $html = $this->renderWizards(
194 array($html),
195 $config['wizards'],
196 $table,
197 $this->data['databaseRow'],
198 $field,
199 $parameterArray,
200 $parameterArray['itemFormElName'],
201 BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras'])
202 );
203 }
204
205 $resultArray = $this->initializeResultArray();
206 $resultArray['html'] = $html;
207 return $resultArray;
208 }
209
210 /**
211 * @return BackendUserAuthentication
212 */
213 protected function getBackendUserAuthentication()
214 {
215 return $GLOBALS['BE_USER'];
216 }
217 }