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