GroupElement.php 13.8 KB
Newer Older
1
2
3
<?php
namespace TYPO3\CMS\Backend\Form\Element;

4
/*
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 * This file is part of the TYPO3 CMS project.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */

use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Backend\Utility\IconUtility;
use TYPO3\CMS\Core\Messaging\FlashMessage;
Christian Kuhn's avatar
Christian Kuhn committed
20
use TYPO3\CMS\Core\Messaging\FlashMessageService;
21
22
23
24
use TYPO3\CMS\Core\Resource\ProcessedFile;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\MathUtility;
Christian Kuhn's avatar
Christian Kuhn committed
25
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
26
27
28
29

/**
 * Generation of TCEform elements of the type "group"
 */
30
class GroupElement extends AbstractFormElement {
31
32

	/**
Christian Kuhn's avatar
Christian Kuhn committed
33
	 * This will render a selector box into which elements from either
34
35
	 * the file system or database can be inserted. Relations.
	 *
Christian Kuhn's avatar
Christian Kuhn committed
36
	 * @return array As defined in initializeResultArray() of AbstractNode
37
	 */
Christian Kuhn's avatar
Christian Kuhn committed
38
39
40
41
42
43
	public function render() {
		$table = $this->globalOptions['table'];
		$fieldName = $this->globalOptions['fieldName'];
		$row = $this->globalOptions['databaseRow'];
		$parameterArray = $this->globalOptions['parameterArray'];
		$config = $parameterArray['fieldConf']['config'];
44
		$show_thumbs = $config['show_thumbs'];
Christian Kuhn's avatar
Christian Kuhn committed
45
46
		$resultArray = $this->initializeResultArray();

47
		$size = isset($config['size']) ? (int)$config['size'] : $this->minimumInputWidth;
48
49
50
51
52
		$maxitems = MathUtility::forceIntegerInRange($config['maxitems'], 0);
		if (!$maxitems) {
			$maxitems = 100000;
		}
		$minitems = MathUtility::forceIntegerInRange($config['minitems'], 0);
Benjamin Kott's avatar
Benjamin Kott committed
53
54
55
		$thumbnails = array();
		$allowed = GeneralUtility::trimExplode(',', $config['allowed'], TRUE);
		$disallowed = GeneralUtility::trimExplode(',', $config['disallowed'], TRUE);
56
		$disabled = ($this->isGlobalReadonly() || $config['readOnly']);
Benjamin Kott's avatar
Benjamin Kott committed
57
		$info = array();
Christian Kuhn's avatar
Christian Kuhn committed
58
		$parameterArray['itemFormElID_file'] = $parameterArray['itemFormElID'] . '_files';
Benjamin Kott's avatar
Benjamin Kott committed
59

60
61
62
		// whether the list and delete controls should be disabled
		$noList = isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'list');
		$noDelete = isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'delete');
Benjamin Kott's avatar
Benjamin Kott committed
63
64

		// "Extra" configuration; Returns configuration for the field based on settings found in the "types" fieldlist.
65
		$specConf = BackendUtility::getSpecConfParts($parameterArray['fieldConf']['defaultExtras']);
Benjamin Kott's avatar
Benjamin Kott committed
66

Christian Kuhn's avatar
Christian Kuhn committed
67
68
69
70
71
		// Register properties in requiredElements
		$resultArray['requiredElements'][$parameterArray['itemFormElName']] = array(
			$minitems,
			$maxitems,
			'imgName' => $table . '_' . $row['uid'] . '_' . $fieldName
Benjamin Kott's avatar
Benjamin Kott committed
72
		);
Christian Kuhn's avatar
Christian Kuhn committed
73
74
75
76
77
78
79
80
		$tabAndInlineStack = $this->globalOptions['tabAndInlineStack'];
		if (!empty($tabAndInlineStack) && preg_match('/^(.+\\])\\[(\\w+)\\]$/', $parameterArray['itemFormElName'], $match)) {
			array_shift($match);
			$resultArray['requiredNested'][$parameterArray['itemFormElName']] = array(
				'parts' => $match,
				'level' => $tabAndInlineStack,
			);
		}
Benjamin Kott's avatar
Benjamin Kott committed
81

Christian Kuhn's avatar
Christian Kuhn committed
82
		// If maxitems==1 then automatically replace the current item (in list and file selector)
83
		if ($maxitems === 1) {
Christian Kuhn's avatar
Christian Kuhn committed
84
			$resultArray['additionalJavaScriptPost'][] =
85
				'TBE_EDITOR.clearBeforeSettingFormValueFromBrowseWin[' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName']) . '] = {
Christian Kuhn's avatar
Christian Kuhn committed
86
					itemFormElID_file: ' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElID_file']) . '
87
				}';
88
89
			$parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'setFormValueManipulate(' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName'])
				. ', \'Remove\'); ' . $parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'];
90
91
		} elseif ($noList) {
			// If the list controls have been removed and the maximum number is reached, remove the first entry to avoid "write once" field
92
93
			$parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'] = 'setFormValueManipulate(' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName'])
				. ', \'RemoveFirstIfFull\', ' . GeneralUtility::quoteJSvalue($maxitems) . '); ' . $parameterArray['fieldChangeFunc']['TBE_EDITOR_fieldChanged'];
94
		}
Benjamin Kott's avatar
Benjamin Kott committed
95

Christian Kuhn's avatar
Christian Kuhn committed
96
		$html = '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '_mul" value="' . ($config['multiple'] ? 1 : 0) . '"' . $disabled . ' />';
Benjamin Kott's avatar
Benjamin Kott committed
97

98
		// Acting according to either "file" or "db" type:
99
		switch ((string)$config['internal_type']) {
100
101
			case 'file_reference':
				$config['uploadfolder'] = '';
102
				// Fall through
103
104
			case 'file':
				// Creating string showing allowed types:
Benjamin Kott's avatar
Benjamin Kott committed
105
106
				if (!count($allowed)) {
					$allowed = array('*');
107
108
				}
				// Making the array of file items:
Christian Kuhn's avatar
Christian Kuhn committed
109
				$itemArray = GeneralUtility::trimExplode(',', $parameterArray['itemFormElValue'], TRUE);
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
				$fileFactory = ResourceFactory::getInstance();
				// Correct the filename for the FAL items
				foreach ($itemArray as &$fileItem) {
					list($fileUid, $fileLabel) = explode('|', $fileItem);
					if (MathUtility::canBeInterpretedAsInteger($fileUid)) {
						$fileObject = $fileFactory->getFileObject($fileUid);
						$fileLabel = $fileObject->getName();
					}
					$fileItem = $fileUid . '|' . $fileLabel;
				}
				// Showing thumbnails:
				if ($show_thumbs) {
					foreach ($itemArray as $imgRead) {
						$imgP = explode('|', $imgRead);
						$imgPath = rawurldecode($imgP[0]);
						// FAL icon production
						if (MathUtility::canBeInterpretedAsInteger($imgP[0])) {
							$fileObject = $fileFactory->getFileObject($imgP[0]);
							if ($fileObject->isMissing()) {
Benjamin Kott's avatar
Benjamin Kott committed
129
130
131
								$thumbnails[] = array(
									'message' => \TYPO3\CMS\Core\Resource\Utility\BackendUtility::getFlashMessageForMissingFile($fileObject)->render()
								);
132
							} elseif (GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], $fileObject->getExtension())) {
Benjamin Kott's avatar
Benjamin Kott committed
133
134
135
136
								$thumbnails[] = array(
									'name' => htmlspecialchars($fileObject->getName()),
									'image' => $fileObject->process(ProcessedFile::CONTEXT_IMAGEPREVIEW, array())->getPublicUrl(TRUE)
								);
137
138
							} else {
								// Icon
Benjamin Kott's avatar
Benjamin Kott committed
139
140
141
142
								$thumbnails[] = array(
									'name' => htmlspecialchars($fileObject->getName()),
									'image' => IconUtility::getSpriteIconForResource($fileObject, array('title' => $fileObject->getName()))
								);
143
144
145
							}
						} else {
							$rowCopy = array();
Christian Kuhn's avatar
Christian Kuhn committed
146
							$rowCopy[$fieldName] = $imgPath;
147
							try {
Benjamin Kott's avatar
Benjamin Kott committed
148
149
150
151
152
								$thumbnails[] = array(
									'name' => $imgPath,
									'image' => BackendUtility::thumbCode(
										$rowCopy,
										$table,
Christian Kuhn's avatar
Christian Kuhn committed
153
										$fieldName,
154
										'',
155
										'',
Benjamin Kott's avatar
Benjamin Kott committed
156
157
158
159
										$config['uploadfolder'],
										0,
										' align="middle"'
									)
160
161
162
163
164
								);
							} catch (\Exception $exception) {
								/** @var $flashMessage FlashMessage */
								$message = $exception->getMessage();
								$flashMessage = GeneralUtility::makeInstance(
165
									FlashMessage::class,
166
167
									htmlspecialchars($message), '', FlashMessage::ERROR, TRUE
								);
Christian Kuhn's avatar
Christian Kuhn committed
168
169
								/** @var $flashMessageService FlashMessageService */
								$flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
170
171
172
173
174
175
176
177
178
179
180
								$defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
								$defaultFlashMessageQueue->enqueue($flashMessage);
								$logMessage = $message . ' (' . $table . ':' . $row['uid'] . ')';
								GeneralUtility::sysLog($logMessage, 'core', GeneralUtility::SYSLOG_SEVERITY_WARNING);
							}
						}
					}
				}
				// Creating the element:
				$params = array(
					'size' => $size,
Benjamin Kott's avatar
Benjamin Kott committed
181
182
					'allowed' => $allowed,
					'disallowed' => $disallowed,
183
184
185
186
187
					'dontShowMoveIcons' => $maxitems <= 1,
					'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
					'maxitems' => $maxitems,
					'style' => isset($config['selectedListStyle'])
						? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
188
						: '',
Benjamin Kott's avatar
Benjamin Kott committed
189
					'thumbnails' => $thumbnails,
190
191
192
193
194
					'readOnly' => $disabled,
					'noBrowser' => $noList || isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'browser'),
					'noList' => $noList,
					'noDelete' => $noDelete
				);
Christian Kuhn's avatar
Christian Kuhn committed
195
196
				$html .= $this->dbFileIcons(
					$parameterArray['itemFormElName'],
Benjamin Kott's avatar
Benjamin Kott committed
197
198
199
200
201
					'file',
					implode(',', $allowed),
					$itemArray,
					'',
					$params,
Christian Kuhn's avatar
Christian Kuhn committed
202
					$parameterArray['onFocus'],
Benjamin Kott's avatar
Benjamin Kott committed
203
204
205
206
					'',
					'',
					'',
					$config);
207
208
				if (!$disabled && !(isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'upload'))) {
					// Adding the upload field:
209
210
					$isDirectFileUploadEnabled = (bool)$this->getBackendUserAuthentication()->uc['edit_docModuleUpload'];
					if ($isDirectFileUploadEnabled && $config['uploadfolder']) {
211
212
213
214
215
216
217
						// Insert the multiple attribute to enable HTML5 multiple file upload
						$multipleAttribute = '';
						$multipleFilenameSuffix = '';
						if (isset($config['maxitems']) && $config['maxitems'] > 1) {
							$multipleAttribute = ' multiple="multiple"';
							$multipleFilenameSuffix = '[]';
						}
Christian Kuhn's avatar
Christian Kuhn committed
218
219
						$html .= '
							<div id="' . $parameterArray['itemFormElID_file'] . '">
Benjamin Kott's avatar
Benjamin Kott committed
220
								<input type="file"' . $multipleAttribute . '
221
									name="data_files' . $this->globalOptions['elementBaseName'] . $multipleFilenameSuffix . '"
Christian Kuhn's avatar
Christian Kuhn committed
222
									size="35" onchange="' . implode('', $parameterArray['fieldChangeFunc']) . '"
Benjamin Kott's avatar
Benjamin Kott committed
223
224
								/>
							</div>';
225
226
227
228
229
230
					}
				}
				break;
			case 'folder':
				// If the element is of the internal type "folder":
				// Array of folder items:
Christian Kuhn's avatar
Christian Kuhn committed
231
				$itemArray = GeneralUtility::trimExplode(',', $parameterArray['itemFormElValue'], TRUE);
232
233
234
235
236
237
238
239
				// Creating the element:
				$params = array(
					'size' => $size,
					'dontShowMoveIcons' => $maxitems <= 1,
					'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
					'maxitems' => $maxitems,
					'style' => isset($config['selectedListStyle'])
						? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
240
						: '',
241
242
243
244
					'readOnly' => $disabled,
					'noBrowser' => $noList || isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'browser'),
					'noList' => $noList
				);
Christian Kuhn's avatar
Christian Kuhn committed
245
246
				$html .= $this->dbFileIcons(
					$parameterArray['itemFormElName'],
Benjamin Kott's avatar
Benjamin Kott committed
247
248
249
250
251
					'folder',
					'',
					$itemArray,
					'',
					$params,
Christian Kuhn's avatar
Christian Kuhn committed
252
					$parameterArray['onFocus']
Benjamin Kott's avatar
Benjamin Kott committed
253
				);
254
255
256
257
258
				break;
			case 'db':
				// If the element is of the internal type "db":
				// Creating string showing allowed types:
				$onlySingleTableAllowed = FALSE;
259
				$languageService = $this->getLanguageService();
Benjamin Kott's avatar
Benjamin Kott committed
260

Christian Kuhn's avatar
Christian Kuhn committed
261
				$allowedTables = array();
Benjamin Kott's avatar
Benjamin Kott committed
262
263
264
265
266
267
268
269
270
271
				if ($allowed[0] === '*') {
					$allowedTables = array(
						'name' => htmlspecialchars($languageService->sL('LLL:EXT:lang/locallang_core.xlf:labels.allTables'))
					);
				} elseif ($allowed) {
					$onlySingleTableAllowed = count($allowed) == 1;
					foreach ($allowed as $allowedTable) {
						$allowedTables[] = array(
							'name' => htmlspecialchars($languageService->sL($GLOBALS['TCA'][$allowedTable]['ctrl']['title'])),
							'icon' => IconUtility::getSpriteIconForRecord($allowedTable, array()),
272
							'onClick' => 'setFormValueOpenBrowser(\'db\', ' . GeneralUtility::quoteJSvalue($parameterArray['itemFormElName'] . '|||' . $allowedTable) . '); return false;'
Benjamin Kott's avatar
Benjamin Kott committed
273
						);
274
275
276
277
					}
				}
				$perms_clause = $this->getBackendUserAuthentication()->getPagePermsClause(1);
				$itemArray = array();
Benjamin Kott's avatar
Benjamin Kott committed
278

279
				// Thumbnails:
Christian Kuhn's avatar
Christian Kuhn committed
280
				$temp_itemArray = GeneralUtility::trimExplode(',', $parameterArray['itemFormElValue'], TRUE);
281
282
283
284
285
286
287
288
289
290
				foreach ($temp_itemArray as $dbRead) {
					$recordParts = explode('|', $dbRead);
					list($this_table, $this_uid) = BackendUtility::splitTable_Uid($recordParts[0]);
					// For the case that no table was found and only a single table is defined to be allowed, use that one:
					if (!$this_table && $onlySingleTableAllowed) {
						$this_table = $allowed;
					}
					$itemArray[] = array('table' => $this_table, 'id' => $this_uid);
					if (!$disabled && $show_thumbs) {
						$rr = BackendUtility::getRecordWSOL($this_table, $this_uid);
Benjamin Kott's avatar
Benjamin Kott committed
291
292
293
294
295
296
297
						$thumbnails[] = array(
							'name' => BackendUtility::getRecordTitle($this_table, $rr, TRUE),
							'image' => IconUtility::getSpriteIconForRecord($this_table, $rr),
							'path' => BackendUtility::getRecordPath($rr['pid'], $perms_clause, 15),
							'uid' => $rr['uid'],
							'table' => $this_table
						);
298
299
300
301
302
303
304
305
306
307
					}
				}
				// Creating the element:
				$params = array(
					'size' => $size,
					'dontShowMoveIcons' => $maxitems <= 1,
					'autoSizeMax' => MathUtility::forceIntegerInRange($config['autoSizeMax'], 0),
					'maxitems' => $maxitems,
					'style' => isset($config['selectedListStyle'])
						? ' style="' . htmlspecialchars($config['selectedListStyle']) . '"'
308
						: '',
309
					'info' => $info,
Benjamin Kott's avatar
Benjamin Kott committed
310
311
					'allowedTables' => $allowedTables,
					'thumbnails' => $thumbnails,
312
313
314
315
					'readOnly' => $disabled,
					'noBrowser' => $noList || isset($config['disable_controls']) && GeneralUtility::inList($config['disable_controls'], 'browser'),
					'noList' => $noList
				);
Christian Kuhn's avatar
Christian Kuhn committed
316
317
				$html .= $this->dbFileIcons(
					$parameterArray['itemFormElName'],
Benjamin Kott's avatar
Benjamin Kott committed
318
319
320
321
322
					'db',
					implode(',', $allowed),
					$itemArray,
					'',
					$params,
Christian Kuhn's avatar
Christian Kuhn committed
323
					$parameterArray['onFocus'],
Benjamin Kott's avatar
Benjamin Kott committed
324
					$table,
Christian Kuhn's avatar
Christian Kuhn committed
325
					$fieldName,
Benjamin Kott's avatar
Benjamin Kott committed
326
327
328
					$row['uid'],
					$config
				);
329
330
331
				break;
		}
		// Wizards:
Christian Kuhn's avatar
Christian Kuhn committed
332
		$altItem = '<input type="hidden" name="' . $parameterArray['itemFormElName'] . '" value="' . htmlspecialchars($parameterArray['itemFormElValue']) . '" />';
333
		if (!$disabled) {
Christian Kuhn's avatar
Christian Kuhn committed
334
			$html = $this->renderWizards(
Benjamin Kott's avatar
Benjamin Kott committed
335
				array(
Christian Kuhn's avatar
Christian Kuhn committed
336
					$html,
Benjamin Kott's avatar
Benjamin Kott committed
337
338
339
340
341
					$altItem
				),
				$config['wizards'],
				$table,
				$row,
Christian Kuhn's avatar
Christian Kuhn committed
342
343
344
				$fieldName,
				$parameterArray,
				$parameterArray['itemFormElName'],
Benjamin Kott's avatar
Benjamin Kott committed
345
346
				$specConf
			);
347
		}
Christian Kuhn's avatar
Christian Kuhn committed
348
349
350
351
352
353
354
355
356
		$resultArray['html'] = $html;
		return $resultArray;
	}

	/**
	 * @return BackendUserAuthentication
	 */
	protected function getBackendUserAuthentication() {
		return $GLOBALS['BE_USER'];
357
	}
358

359
}