[!!!][TASK] TCA: Remove wizard _HIDDENFIELD and hideParent
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / Element / GroupElement.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\Backend\Utility\IconUtility;
19 use TYPO3\CMS\Core\Messaging\FlashMessage;
20 use TYPO3\CMS\Core\Messaging\FlashMessageService;
21 use TYPO3\CMS\Core\Resource\ProcessedFile;
22 use TYPO3\CMS\Core\Resource\ResourceFactory;
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24 use TYPO3\CMS\Core\Utility\MathUtility;
25 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
26
27 /**
28 * Generation of TCEform elements of the type "group"
29 */
30 class GroupElement extends AbstractFormElement {
31
32 /**
33 * This will render a selector box into which elements from either
34 * the file system or database can be inserted. Relations.
35 *
36 * @return array As defined in initializeResultArray() of AbstractNode
37 */
38 public function render() {
39 $table = $this->globalOptions['table'];
40 $fieldName = $this->globalOptions['fieldName'];
41 $row = $this->globalOptions['databaseRow'];
42 $parameterArray = $this->globalOptions['parameterArray'];
43 $config = $parameterArray['fieldConf']['config'];
44 $show_thumbs = $config['show_thumbs'];
45 $resultArray = $this->initializeResultArray();
46
47 $size = isset($config['size']) ? (int)$config['size'] : $this->minimumInputWidth;
48 $maxitems = MathUtility::forceIntegerInRange($config['maxitems'], 0);
49 if (!$maxitems) {
50 $maxitems = 100000;
51 }
52 $minitems = MathUtility::forceIntegerInRange($config['minitems'], 0);
53 $thumbnails = array();
54 $allowed = GeneralUtility::trimExplode(',', $config['allowed'], TRUE);
55 $disallowed = GeneralUtility::trimExplode(',', $config['disallowed'], TRUE);
56 $disabled = ($this->isGlobalReadonly() || $config['readOnly']);
57 $info = array();
58 $parameterArray['itemFormElID_file'] = $parameterArray['itemFormElID'] . '_files';
59
60 // whether the list and delete controls should be disabled
61 $noList = isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'list');
62 $noDelete = isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'delete');
63
64 // "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist.
65 $specConf = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
66
67 // Register properties in required elements / validation
68 $attributes['data-formengine-validation-rules'] = htmlspecialchars(
69 $this->getValidationDataAsJsonString(
70 array(
71 'minitems' => $minitems,
72 'maxitems' => $maxitems
73 )
74 )
75 );
76
77 // If maxitems==1 then automatically replace the current item (in list and file selector)
78 if ($maxitems === 1) {
79 $resultArray['additionalJavaScriptPost'][] =
80 'TBE_EDITOR.clearBeforeSettingFormValueFromBrowseWin[' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . '] = {
81 itemFormElID_file: ' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElID_file']) . '
82 }';
83 $parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'setFormValueManipulate(' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName'])
84 . ', \'Remove\'); ' . $parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'];
85 } elseif ($noList) {
86 // If the list controls have been removed and the maximum number is reached, remove the first entry to avoid "write once" field
87 $parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'setFormValueManipulate(' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName'])
88 . ', \'RemoveFirstIfFull\', ' . GeneralUtility::quoteJSvalue($maxitems) . '); ' . $parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'];
89 }
90
91 $html = '<input type="hidden" class="t3js-group-hidden-field" name="' . $parameterArray['itemFormElName'] . '_mul" value="' . ($config['multiple'] ? 1 : 0) . '"' . $disabled . ' />';
92
93 // Acting according to either "file" or "db" type:
94 switch ((string)$config['internal_type']) {
95 case 'file_reference':
96 $config['uploadfolder'] = '';
97 // Fall through
98 case 'file':
99 // Creating string showing allowed types:
100 if (empty($allowed)) {
101 $allowed = array('*');
102 }
103 // Making the array of file items:
104 $itemArray = GeneralUtility::trimExplode(',', $parameterArray['itemFormElValue'], TRUE);
105 $fileFactory = ResourceFactory::getInstance();
106 // Correct the filename for the FAL items
107 foreach ($itemArray as &$fileItem) {
108 list($fileUid, $fileLabel) = explode('|', $fileItem);
109 if (MathUtility::canBeInterpretedAsInteger($fileUid)) {
110 $fileObject = $fileFactory->getFileObject($fileUid);
111 $fileLabel = $fileObject->getName();
112 }
113 $fileItem = $fileUid . '|' . $fileLabel;
114 }
115 // Showing thumbnails:
116 if ($show_thumbs) {
117 foreach ($itemArray as $imgRead) {
118 $imgP = explode('|', $imgRead);
119 $imgPath = rawurldecode($imgP[0]);
120 // FAL icon production
121 if (MathUtility::canBeInterpretedAsInteger($imgP[0])) {
122 $fileObject = $fileFactory->getFileObject($imgP[0]);
123 if ($fileObject->isMissing()) {
124 $thumbnails[] = array(
125 'message' => \TYPO3\CMS\Core\Resource\Utility\BackendUtility::getFlashMessageForMissingFile($fileObject)->render()
126 );
127 } elseif (GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileObject->getExtension())) {
128 $thumbnails[] = array(
129 'name' => htmlspecialchars($fileObject->getName()),
130 'image' => $fileObject->process(ProcessedFile::CONTEXT_IMAGEPREVIEW, array())->getPublicUrl(TRUE)
131 );
132 } else {
133 // Icon
134 $thumbnails[] = array(
135 'name' => htmlspecialchars($fileObject->getName()),
136 'image' => IconUtility::getSpriteIconForResource($fileObject, array('title' => $fileObject->getName()))
137 );
138 }
139 } else {
140 $rowCopy = array();
141 $rowCopy[$fieldName] = $imgPath;
142 try {
143 $thumbnails[] = array(
144 'name' => $imgPath,
145 'image' => BackendUtility::thumbCode(
146 $rowCopy,
147 $table,
148 $fieldName,
149 '',
150 '',
151 $config['uploadfolder'],
152 0,
153 ' align="middle"'
154 )
155 );
156 } catch (\Exception $exception) {
157 /** @var $flashMessage FlashMessage */
158 $message = $exception->getMessage();
159 $flashMessage = GeneralUtility::makeInstance(
160 FlashMessage::class,
161 htmlspecialchars($message), '', FlashMessage::ERROR, TRUE
162 );
163 /** @var $flashMessageService FlashMessageService */
164 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
165 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
166 $defaultFlashMessageQueue->enqueue($flashMessage);
167 $logMessage = $message . ' (' . $table . ':' . $row['uid'] . ')';
168 GeneralUtility::sysLog($logMessage, 'core', GeneralUtility::SYSLOG_SEVERITY_WARNING);
169 }
170 }
171 }
172 }
173 // Creating the element:
174 $params = array(
175 'size' => $size,
176 'allowed' => $allowed,
177 'disallowed' => $disallowed,
178 'dontShowMoveIcons' => $maxitems <= 1,
179 'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
180 'maxitems' => $maxitems,
181 'style' => isset($config['selectedListStyle'])
182 ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
183 : '',
184 'thumbnails' => $thumbnails,
185 'readOnly' => $disabled,
186 'noBrowser' => $noList || isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'browser'),
187 'noList' => $noList,
188 'noDelete' => $noDelete
189 );
190 $html .= $this->dbFileIcons(
191 $parameterArray['itemFormElName'],
192 'file',
193 implode(',', $allowed),
194 $itemArray,
195 '',
196 $params,
197 $parameterArray['onFocus'],
198 '',
199 '',
200 '',
201 $config);
202 if (!$disabled && !(isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'upload'))) {
203 // Adding the upload field:
204 $isDirectFileUploadEnabled = (bool)$this->getBackendUserAuthentication()->uc['edit_docModuleUpload'];
205 if ($isDirectFileUploadEnabled && $config['uploadfolder']) {
206 // Insert the multiple attribute to enable HTML5 multiple file upload
207 $multipleAttribute = '';
208 $multipleFilenameSuffix = '';
209 if (isset($config['maxitems']) && $config['maxitems'] > 1) {
210 $multipleAttribute = ' multiple="multiple"';
211 $multipleFilenameSuffix = '[]';
212 }
213 $html .= '
214 <div id="' . $parameterArray['itemFormElID_file'] . '">
215 <input type="file"' . $multipleAttribute . '
216 name="data_files' . $this->globalOptions['elementBaseName'] . $multipleFilenameSuffix . '"
217 size="35" onchange="' . implode('', $parameterArray['fieldChangeFunc']) . '"
218 />
219 </div>';
220 }
221 }
222 break;
223 case 'folder':
224 // If the element is of the internal type "folder":
225 // Array of folder items:
226 $itemArray = GeneralUtility::trimExplode(',', $parameterArray['itemFormElValue'], TRUE);
227 // Creating the element:
228 $params = array(
229 'size' => $size,
230 'dontShowMoveIcons' => $maxitems <= 1,
231 'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
232 'maxitems' => $maxitems,
233 'style' => isset($config['selectedListStyle'])
234 ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
235 : '',
236 'readOnly' => $disabled,
237 'noBrowser' => $noList || isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'browser'),
238 'noList' => $noList
239 );
240 $html .= $this->dbFileIcons(
241 $parameterArray['itemFormElName'],
242 'folder',
243 '',
244 $itemArray,
245 '',
246 $params,
247 $parameterArray['onFocus']
248 );
249 break;
250 case 'db':
251 // If the element is of the internal type "db":
252 // Creating string showing allowed types:
253 $onlySingleTableAllowed = FALSE;
254 $languageService = $this->getLanguageService();
255
256 $allowedTables = array();
257 if ($allowed[0] === '*') {
258 $allowedTables = array(
259 'name' => htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.allTables'))
260 );
261 } elseif ($allowed) {
262 $onlySingleTableAllowed = count($allowed) === 1;
263 foreach ($allowed as $allowedTable) {
264 $allowedTables[] = array(
265 'name' => htmlspecialchars($languageService->sL($GLOBALS['TCA'][$allowedTable]['ctrl']['title'])),
266 'icon' => IconUtility::getSpriteIconForRecord($allowedTable, array()),
267 'onClick' => 'setFormValueOpenBrowser(\'db\', ' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName'] . '|||' . $allowedTable) . '); return false;'
268 );
269 }
270 }
271 $perms_clause = $this->getBackendUserAuthentication()->getPagePermsClause(1);
272 $itemArray = array();
273
274 // Thumbnails:
275 $temp_itemArray = GeneralUtility::trimExplode(',', $parameterArray['itemFormElValue'], TRUE);
276 foreach ($temp_itemArray as $dbRead) {
277 $recordParts = explode('|', $dbRead);
278 list($this_table, $this_uid) = BackendUtility::splitTable_Uid($recordParts[0]);
279 // For the case that no table was found and only a single table is defined to be allowed, use that one:
280 if (!$this_table && $onlySingleTableAllowed) {
281 $this_table = $allowed;
282 }
283 $itemArray[] = array('table' => $this_table, 'id' => $this_uid);
284 if (!$disabled && $show_thumbs) {
285 $rr = BackendUtility::getRecordWSOL($this_table, $this_uid);
286 $thumbnails[] = array(
287 'name' => BackendUtility::getRecordTitle($this_table, $rr, TRUE),
288 'image' => IconUtility::getSpriteIconForRecord($this_table, $rr),
289 'path' => BackendUtility::getRecordPath($rr['pid'], $perms_clause, 15),
290 'uid' => $rr['uid'],
291 'table' => $this_table
292 );
293 }
294 }
295 // Creating the element:
296 $params = array(
297 'size' => $size,
298 'dontShowMoveIcons' => $maxitems <= 1,
299 'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
300 'maxitems' => $maxitems,
301 'style' => isset($config['selectedListStyle'])
302 ? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
303 : '',
304 'info' => $info,
305 'allowedTables' => $allowedTables,
306 'thumbnails' => $thumbnails,
307 'readOnly' => $disabled,
308 'noBrowser' => $noList || isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'browser'),
309 'noList' => $noList
310 );
311 $html .= $this->dbFileIcons(
312 $parameterArray['itemFormElName'],
313 'db',
314 implode(',', $allowed),
315 $itemArray,
316 '',
317 $params,
318 $parameterArray['onFocus'],
319 $table,
320 $fieldName,
321 $row['uid'],
322 $config
323 );
324 break;
325 }
326 // Wizards:
327 if (!$disabled) {
328 $html = $this->renderWizards(
329 array($html),
330 $config['wizards'],
331 $table,
332 $row,
333 $fieldName,
334 $parameterArray,
335 $parameterArray['itemFormElName'],
336 $specConf
337 );
338 }
339 $resultArray['html'] = $html;
340 return $resultArray;
341 }
342
343 /**
344 * @return BackendUserAuthentication
345 */
346 protected function getBackendUserAuthentication() {
347 return $GLOBALS['BE_USER'];
348 }
349
350 }