221c8a9dba2db1668464be8717da0056edb21854
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / FormDataProvider / AbstractItemProvider.php
1 <?php
2 namespace TYPO3\CMS\Backend\Form\FormDataProvider;
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\Module\ModuleLoader;
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
20 use TYPO3\CMS\Core\Database\DatabaseConnection;
21 use TYPO3\CMS\Core\Database\RelationHandler;
22 use TYPO3\CMS\Core\Imaging\IconFactory;
23 use TYPO3\CMS\Core\Messaging\FlashMessage;
24 use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
25 use TYPO3\CMS\Core\Messaging\FlashMessageService;
26 use TYPO3\CMS\Core\Utility\ArrayUtility;
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28 use TYPO3\CMS\Core\Utility\MathUtility;
29 use TYPO3\CMS\Core\Utility\PathUtility;
30 use TYPO3\CMS\Lang\LanguageService;
31
32 /**
33 * Contains methods used by Data providers that handle elements
34 * with single items like select, radio and some more.
35 */
36 abstract class AbstractItemProvider
37 {
38 /**
39 * Resolve "itemProcFunc" of elements.
40 *
41 * @param array $result Main result array
42 * @param string $fieldName Field name to handle item list for
43 * @param array $items Existing items array
44 * @return array New list of item elements
45 */
46 protected function resolveItemProcessorFunction(array $result, $fieldName, array $items)
47 {
48 $table = $result['tableName'];
49 $config = $result['processedTca']['columns'][$fieldName]['config'];
50
51 $pageTsProcessorParameters = null;
52 if (!empty($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['itemsProcFunc.'])) {
53 $pageTsProcessorParameters = $result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['itemsProcFunc.'];
54 }
55 $processorParameters = [
56 // Function manipulates $items directly and return nothing
57 'items' => &$items,
58 'config' => $config,
59 'TSconfig' => $pageTsProcessorParameters,
60 'table' => $table,
61 'row' => $result['databaseRow'],
62 'field' => $fieldName,
63 ];
64 if (!empty($result['flexParentDatabaseRow'])) {
65 $processorParameters['flexParentDatabaseRow'] = $result['flexParentDatabaseRow'];
66 }
67
68 try {
69 GeneralUtility::callUserFunction($config['itemsProcFunc'], $processorParameters, $this);
70 } catch (\Exception $exception) {
71 // The itemsProcFunc method may throw an exception, create a flash message if so
72 $languageService = $this->getLanguageService();
73 $fieldLabel = $fieldName;
74 if (!empty($result['processedTca']['columns'][$fieldName]['label'])) {
75 $fieldLabel = $languageService->sL($result['processedTca']['columns'][$fieldName]['label']);
76 }
77 $message = sprintf(
78 $languageService->sL('LLL:EXT:lang/locallang_core.xlf:error.items_proc_func_error'),
79 $fieldLabel,
80 $exception->getMessage()
81 );
82 /** @var FlashMessage $flashMessage */
83 $flashMessage = GeneralUtility::makeInstance(
84 FlashMessage::class,
85 $message,
86 '',
87 FlashMessage::ERROR,
88 true
89 );
90 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
91 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
92 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
93 $defaultFlashMessageQueue->enqueue($flashMessage);
94 }
95
96 return $items;
97 }
98
99 /**
100 * PageTsConfig addItems:
101 *
102 * TCEFORMS.aTable.aField[.types][.aType].addItems.aValue = aLabel,
103 * with type specific options merged by pageTsConfig already
104 *
105 * Used by TcaSelectItems and TcaSelectTreeItems data providers
106 *
107 * @param array $result result array
108 * @param string $fieldName Current handle field name
109 * @param array $items Incoming items
110 * @return array Modified item array
111 */
112 protected function addItemsFromPageTsConfig(array $result, $fieldName, array $items)
113 {
114 $table = $result['tableName'];
115 if (!empty($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['addItems.'])
116 && is_array($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['addItems.'])
117 ) {
118 $addItemsArray = $result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['addItems.'];
119 foreach ($addItemsArray as $value => $label) {
120 // If the value ends with a dot, it is a subelement like "34.icon = mylabel.png", skip it
121 if (substr($value, -1) === '.') {
122 continue;
123 }
124 // Check if value "34 = mylabel" also has a "34.icon = myImage.png"
125 $icon = null;
126 if (isset($addItemsArray[$value . '.'])
127 && is_array($addItemsArray[$value . '.'])
128 && !empty($addItemsArray[$value . '.']['icon'])
129 ) {
130 $icon = $addItemsArray[$value . '.']['icon'];
131 }
132 $items[] = array($label, $value, $icon);
133 }
134 }
135 return $items;
136 }
137
138 /**
139 * TCA config "special" evaluation. Add them to $items
140 *
141 * Used by TcaSelectItems and TcaSelectTreeItems data providers
142 *
143 * @param array $result Result array
144 * @param string $fieldName Current handle field name
145 * @param array $items Incoming items
146 * @return array Modified item array
147 * @throws \UnexpectedValueException
148 */
149 protected function addItemsFromSpecial(array $result, $fieldName, array $items)
150 {
151 // Guard
152 if (empty($result['processedTca']['columns'][$fieldName]['config']['special'])
153 || !is_string($result['processedTca']['columns'][$fieldName]['config']['special'])
154 ) {
155 return $items;
156 }
157
158 $languageService = $this->getLanguageService();
159 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
160
161 $special = $result['processedTca']['columns'][$fieldName]['config']['special'];
162 if ($special === 'tables') {
163 foreach ($GLOBALS['TCA'] as $currentTable => $_) {
164 if (!empty($GLOBALS['TCA'][$currentTable]['ctrl']['adminOnly'])) {
165 // Hide "admin only" tables
166 continue;
167 }
168 $label = !empty($GLOBALS['TCA'][$currentTable]['ctrl']['title']) ? $GLOBALS['TCA'][$currentTable]['ctrl']['title'] : '';
169 $icon = $iconFactory->mapRecordTypeToIconIdentifier($currentTable, []);
170 $helpText = [];
171 $languageService->loadSingleTableDescription($currentTable);
172 // @todo: check if this actually works, currently help texts are missing
173 $helpTextArray = $GLOBALS['TCA_DESCR'][$currentTable]['columns'][''];
174 if (!empty($helpTextArray['description'])) {
175 $helpText['description'] = $helpTextArray['description'];
176 }
177 $items[] = [$label, $currentTable, $icon, $helpText];
178 }
179 } elseif ($special === 'pagetypes') {
180 if (isset($GLOBALS['TCA']['pages']['columns']['doktype']['config']['items'])
181 && is_array($GLOBALS['TCA']['pages']['columns']['doktype']['config']['items'])
182 ) {
183 $specialItems = $GLOBALS['TCA']['pages']['columns']['doktype']['config']['items'];
184 foreach ($specialItems as $specialItem) {
185 if (!is_array($specialItem) || $specialItem[1] === '--div--') {
186 // Skip non arrays and divider items
187 continue;
188 }
189 $label = $specialItem[0];
190 $value = $specialItem[1];
191 $icon = $iconFactory->mapRecordTypeToIconIdentifier('pages', ['doktype' => $specialItem[1]]);
192 $items[] = [$label, $value, $icon];
193 }
194 }
195 } elseif ($special === 'exclude') {
196 $excludeArrays = $this->getExcludeFields();
197 foreach ($excludeArrays as $excludeArray) {
198 list($theTable, $theFullField) = explode(':', $excludeArray[1]);
199 // If the field comes from a FlexForm, the syntax is more complex
200 $theFieldParts = explode(';', $theFullField);
201 $theField = array_pop($theFieldParts);
202 // Add header if not yet set for table:
203 if (!array_key_exists($theTable, $items)) {
204 $icon = $iconFactory->mapRecordTypeToIconIdentifier($theTable, []);
205 $items[$theTable] = [
206 $GLOBALS['TCA'][$theTable]['ctrl']['title'],
207 '--div--',
208 $icon
209 ];
210 }
211 // Add help text
212 $helpText = [];
213 $languageService->loadSingleTableDescription($theTable);
214 $helpTextArray = $GLOBALS['TCA_DESCR'][$theTable]['columns'][$theFullField];
215 if (!empty($helpTextArray['description'])) {
216 $helpText['description'] = $helpTextArray['description'];
217 }
218 // Item configuration:
219 // @todo: the title calculation does not work well for flex form fields, see unit tests
220 $items[] = [
221 rtrim($languageService->sL($GLOBALS['TCA'][$theTable]['columns'][$theField]['label']), ':') . ' (' . $theField . ')',
222 $excludeArray[1],
223 'empty-empty',
224 $helpText
225 ];
226 }
227 } elseif ($special === 'explicitValues') {
228 $theTypes = $this->getExplicitAuthFieldValues();
229 $icons = [
230 'ALLOW' => 'status-status-permission-granted',
231 'DENY' => 'status-status-permission-denied'
232 ];
233 // Traverse types:
234 foreach ($theTypes as $tableFieldKey => $theTypeArrays) {
235 if (is_array($theTypeArrays['items'])) {
236 // Add header:
237 $items[] = [
238 $theTypeArrays['tableFieldLabel'],
239 '--div--',
240 ];
241 // Traverse options for this field:
242 foreach ($theTypeArrays['items'] as $itemValue => $itemContent) {
243 // Add item to be selected:
244 $items[] = [
245 '[' . $itemContent[2] . '] ' . $itemContent[1],
246 $tableFieldKey . ':' . preg_replace('/[:|,]/', '', $itemValue) . ':' . $itemContent[0],
247 $icons[$itemContent[0]]
248 ];
249 }
250 }
251 }
252 } elseif ($special === 'languages') {
253 foreach ($result['systemLanguageRows'] as $language) {
254 if ($language['uid'] !== -1) {
255 $items[] = [
256 0 => $language['title'] . ' [' . $language['uid'] . ']',
257 1 => $language['uid'],
258 2 => $language['flagIconIdentifier']
259 ];
260 }
261 }
262 } elseif ($special === 'custom') {
263 $customOptions = $GLOBALS['TYPO3_CONF_VARS']['BE']['customPermOptions'];
264 if (is_array($customOptions)) {
265 foreach ($customOptions as $coKey => $coValue) {
266 if (is_array($coValue['items'])) {
267 // Add header:
268 $items[] = [
269 $languageService->sL($coValue['header']),
270 '--div--'
271 ];
272 // Traverse items:
273 foreach ($coValue['items'] as $itemKey => $itemCfg) {
274 $icon = 'empty-empty';
275 $helpText = [];
276 if (!empty($itemCfg[2])) {
277 $helpText['description'] = $languageService->sL($itemCfg[2]);
278 }
279 $items[] = [
280 $languageService->sL($itemCfg[0]),
281 $coKey . ':' . preg_replace('/[:|,]/', '', $itemKey),
282 $icon,
283 $helpText
284 ];
285 }
286 }
287 }
288 }
289 } elseif ($special === 'modListGroup' || $special === 'modListUser') {
290 $loadModules = GeneralUtility::makeInstance(ModuleLoader::class);
291 $loadModules->load($GLOBALS['TBE_MODULES']);
292 $modList = $special === 'modListUser' ? $loadModules->modListUser : $loadModules->modListGroup;
293 if (is_array($modList)) {
294 foreach ($modList as $theMod) {
295 // Icon:
296 $icon = $languageService->moduleLabels['tabs_images'][$theMod . '_tab'];
297 if ($icon) {
298 $icon = '../' . PathUtility::stripPathSitePrefix($icon);
299 }
300 // Add help text
301 $helpText = [
302 'title' => $languageService->moduleLabels['labels'][$theMod . '_tablabel'],
303 'description' => $languageService->moduleLabels['labels'][$theMod . '_tabdescr']
304 ];
305
306 $label = '';
307 // Add label for main module:
308 $pp = explode('_', $theMod);
309 if (count($pp) > 1) {
310 $label .= $languageService->moduleLabels['tabs'][($pp[0] . '_tab')] . '>';
311 }
312 // Add modules own label now:
313 $label .= $languageService->moduleLabels['tabs'][$theMod . '_tab'];
314
315 // Item configuration:
316 $items[] = [$label, $theMod, $icon, $helpText];
317 }
318 }
319 } else {
320 throw new \UnexpectedValueException(
321 'Unknown special value ' . $special . ' for field ' . $fieldName . ' of table ' . $result['tableName'],
322 1439298496
323 );
324 }
325
326 return $items;
327 }
328
329 /**
330 * TCA config "fileFolder" evaluation. Add them to $items
331 *
332 * Used by TcaSelectItems and TcaSelectTreeItems data providers
333 *
334 * @param array $result Result array
335 * @param string $fieldName Current handle field name
336 * @param array $items Incoming items
337 * @return array Modified item array
338 */
339 protected function addItemsFromFolder(array $result, $fieldName, array $items)
340 {
341 if (empty($result['processedTca']['columns'][$fieldName]['config']['fileFolder'])
342 || !is_string($result['processedTca']['columns'][$fieldName]['config']['fileFolder'])
343 ) {
344 return $items;
345 }
346
347 $fileFolder = $result['processedTca']['columns'][$fieldName]['config']['fileFolder'];
348 $fileFolder = GeneralUtility::getFileAbsFileName($fileFolder);
349 $fileFolder = rtrim($fileFolder, '/') . '/';
350
351 if (@is_dir($fileFolder)) {
352 $fileExtensionList = '';
353 if (!empty($result['processedTca']['columns'][$fieldName]['config']['fileFolder_extList'])
354 && is_string($result['processedTca']['columns'][$fieldName]['config']['fileFolder_extList'])
355 ) {
356 $fileExtensionList = $result['processedTca']['columns'][$fieldName]['config']['fileFolder_extList'];
357 }
358 $recursionLevels = isset($fieldValue['config']['fileFolder_recursions'])
359 ? MathUtility::forceIntegerInRange($fieldValue['config']['fileFolder_recursions'], 0, 99)
360 : 99;
361 $fileArray = GeneralUtility::getAllFilesAndFoldersInPath([], $fileFolder, $fileExtensionList, 0, $recursionLevels);
362 $fileArray = GeneralUtility::removePrefixPathFromList($fileArray, $fileFolder);
363 foreach ($fileArray as $fileReference) {
364 $fileInformation = pathinfo($fileReference);
365 $icon = GeneralUtility::inList($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'], strtolower($fileInformation['extension']))
366 ? '../' . PathUtility::stripPathSitePrefix($fileFolder) . $fileReference
367 : '';
368 $items[] = [
369 $fileReference,
370 $fileReference,
371 $icon
372 ];
373 }
374 }
375
376 return $items;
377 }
378
379 /**
380 * TCA config "foreign_table" evaluation. Add them to $items
381 *
382 * Used by TcaSelectItems and TcaSelectTreeItems data providers
383 *
384 * @param array $result Result array
385 * @param string $fieldName Current handle field name
386 * @param array $items Incoming items
387 * @return array Modified item array
388 */
389 protected function addItemsFromForeignTable(array $result, $fieldName, array $items)
390 {
391 // Guard
392 if (empty($result['processedTca']['columns'][$fieldName]['config']['foreign_table'])
393 || !is_string($result['processedTca']['columns'][$fieldName]['config']['foreign_table'])
394 ) {
395 return $items;
396 }
397
398 $languageService = $this->getLanguageService();
399 $database = $this->getDatabaseConnection();
400
401 $foreignTable = $result['processedTca']['columns'][$fieldName]['config']['foreign_table'];
402 $foreignTableQueryArray = $this->buildForeignTableQuery($result, $fieldName);
403 $queryResource = $database->exec_SELECT_queryArray($foreignTableQueryArray);
404
405 // Early return on error with flash message
406 $databaseError = $database->sql_error();
407 if (!empty($databaseError)) {
408 $msg = htmlspecialchars($databaseError) . '<br />' . LF;
409 $msg .= $languageService->sL('LLL:EXT:lang/locallang_core.xlf:error.database_schema_mismatch');
410 $msgTitle = $languageService->sL('LLL:EXT:lang/locallang_core.xlf:error.database_schema_mismatch_title');
411 /** @var $flashMessage FlashMessage */
412 $flashMessage = GeneralUtility::makeInstance(FlashMessage::class, $msg, $msgTitle, FlashMessage::ERROR, true);
413 /** @var $flashMessageService FlashMessageService */
414 $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
415 /** @var $defaultFlashMessageQueue FlashMessageQueue */
416 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
417 $defaultFlashMessageQueue->enqueue($flashMessage);
418 $database->sql_free_result($queryResource);
419 return $items;
420 }
421
422 $labelPrefix = '';
423 if (!empty($result['processedTca']['columns'][$fieldName]['config']['foreign_table_prefix'])) {
424 $labelPrefix = $result['processedTca']['columns'][$fieldName]['config']['foreign_table_prefix'];
425 $labelPrefix = $languageService->sL($labelPrefix);
426 }
427 $iconFieldName = '';
428 if (!empty($result['processedTca']['ctrl']['selicon_field'])) {
429 $iconFieldName = $result['processedTca']['ctrl']['selicon_field'];
430 }
431 $iconPath = '';
432 if (!empty($result['processedTca']['ctrl']['selicon_field_path'])) {
433 $iconPath = $result['processedTca']['ctrl']['selicon_field_path'];
434 }
435
436 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
437
438 while ($foreignRow = $database->sql_fetch_assoc($queryResource)) {
439 BackendUtility::workspaceOL($foreignTable, $foreignRow);
440 if (is_array($foreignRow)) {
441 // Prepare the icon if available:
442 if ($iconFieldName && $iconPath && $foreignRow[$iconFieldName]) {
443 $iParts = GeneralUtility::trimExplode(',', $foreignRow[$iconFieldName], true);
444 $icon = '../' . $iconPath . '/' . trim($iParts[0]);
445 } else {
446 $icon = $iconFactory->mapRecordTypeToIconIdentifier($foreignTable, $foreignRow);
447 }
448 // Add the item
449 $items[] = [
450 $labelPrefix . htmlspecialchars(BackendUtility::getRecordTitle($foreignTable, $foreignRow)),
451 $foreignRow['uid'],
452 $icon
453 ];
454 }
455 }
456
457 $database->sql_free_result($queryResource);
458
459 return $items;
460 }
461
462 /**
463 * Remove items using "keepItems" pageTsConfig
464 *
465 * Used by TcaSelectItems and TcaSelectTreeItems data providers
466 *
467 * @param array $result Result array
468 * @param string $fieldName Current handle field name
469 * @param array $items Incoming items
470 * @return array Modified item array
471 */
472 protected function removeItemsByKeepItemsPageTsConfig(array $result, $fieldName, array $items)
473 {
474 $table = $result['tableName'];
475 if (!isset($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['keepItems'])
476 || !is_string($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['keepItems'])
477 ) {
478 return $items;
479 }
480
481 // If keepItems is set but is an empty list all current items get removed
482 if (empty($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['keepItems'])
483 && $result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['keepItems'] !== '0') {
484 return [];
485 }
486
487 return ArrayUtility::keepItemsInArray(
488 $items,
489 $result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['keepItems'],
490 function ($value) {
491 return $value[1];
492 }
493 );
494 }
495
496 /**
497 * Remove items using "removeItems" pageTsConfig
498 *
499 * Used by TcaSelectItems and TcaSelectTreeItems data providers
500 *
501 * @param array $result Result array
502 * @param string $fieldName Current handle field name
503 * @param array $items Incoming items
504 * @return array Modified item array
505 */
506 protected function removeItemsByRemoveItemsPageTsConfig(array $result, $fieldName, array $items)
507 {
508 $table = $result['tableName'];
509 if (empty($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['removeItems'])
510 || !is_string($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['removeItems'])
511 ) {
512 return $items;
513 }
514
515 $removeItems = GeneralUtility::trimExplode(
516 ',',
517 $result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['removeItems'],
518 true
519 );
520 foreach ($items as $key => $itemValues) {
521 if (in_array($itemValues[1], $removeItems)) {
522 unset($items[$key]);
523 }
524 }
525
526 return $items;
527 }
528
529 /**
530 * Remove items user restriction on language field
531 *
532 * Used by TcaSelectItems and TcaSelectTreeItems data providers
533 *
534 * @param array $result Result array
535 * @param string $fieldName Current handle field name
536 * @param array $items Incoming items
537 * @return array Modified item array
538 */
539 protected function removeItemsByUserLanguageFieldRestriction(array $result, $fieldName, array $items)
540 {
541 // Guard clause returns if not a language field is handled
542 if (empty($result['processedTca']['ctrl']['languageField'])
543 || $result['processedTca']['ctrl']['languageField'] !== $fieldName
544 ) {
545 return $items;
546 }
547
548 $backendUser = $this->getBackendUser();
549 foreach ($items as $key => $itemValues) {
550 if (!$backendUser->checkLanguageAccess($itemValues[1])) {
551 unset($items[$key]);
552 }
553 }
554
555 return $items;
556 }
557
558 /**
559 * Remove items by user restriction on authMode items
560 *
561 * Used by TcaSelectItems and TcaSelectTreeItems data providers
562 *
563 * @param array $result Result array
564 * @param string $fieldName Current handle field name
565 * @param array $items Incoming items
566 * @return array Modified item array
567 */
568 protected function removeItemsByUserAuthMode(array $result, $fieldName, array $items)
569 {
570 // Guard clause returns early if no authMode field is configured
571 if (!isset($result['processedTca']['columns'][$fieldName]['config']['authMode'])
572 || !is_string($result['processedTca']['columns'][$fieldName]['config']['authMode'])
573 ) {
574 return $items;
575 }
576
577 $backendUser = $this->getBackendUser();
578 $authMode = $result['processedTca']['columns'][$fieldName]['config']['authMode'];
579 foreach ($items as $key => $itemValues) {
580 // @todo: checkAuthMode() uses $GLOBAL access for "individual" authMode - get rid of this
581 if (!$backendUser->checkAuthMode($result['tableName'], $fieldName, $itemValues[1], $authMode)) {
582 unset($items[$key]);
583 }
584 }
585
586 return $items;
587 }
588
589 /**
590 * Remove items if doktype is handled for non admin users
591 *
592 * Used by TcaSelectItems and TcaSelectTreeItems data providers
593 *
594 * @param array $result Result array
595 * @param string $fieldName Current handle field name
596 * @param array $items Incoming items
597 * @return array Modified item array
598 */
599 protected function removeItemsByDoktypeUserRestriction(array $result, $fieldName, array $items)
600 {
601 $table = $result['tableName'];
602 $backendUser = $this->getBackendUser();
603 // Guard clause returns if not correct table and field or if user is admin
604 if ($table !== 'pages' && $table !== 'pages_language_overlay'
605 || $fieldName !== 'doktype' || $backendUser->isAdmin()
606 ) {
607 return $items;
608 }
609
610 $allowedPageTypes = $backendUser->groupData['pagetypes_select'];
611 foreach ($items as $key => $itemValues) {
612 if (!GeneralUtility::inList($allowedPageTypes, $itemValues[1])) {
613 unset($items[$key]);
614 }
615 }
616
617 return $items;
618 }
619
620 /**
621 * Returns an array with the exclude fields as defined in TCA and FlexForms
622 * Used for listing the exclude fields in be_groups forms.
623 *
624 * @return array Array of arrays with excludeFields (fieldName, table:fieldName) from TCA
625 * and FlexForms (fieldName, table:extKey;sheetName;fieldName)
626 */
627 protected function getExcludeFields()
628 {
629 $languageService = $this->getLanguageService();
630 $finalExcludeArray = [];
631
632 // Fetch translations for table names
633 $tableToTranslation = [];
634 // All TCA keys
635 foreach ($GLOBALS['TCA'] as $table => $conf) {
636 $tableToTranslation[$table] = $languageService->sl($conf['ctrl']['title']);
637 }
638 // Sort by translations
639 asort($tableToTranslation);
640 foreach ($tableToTranslation as $table => $translatedTable) {
641 $excludeArrayTable = [];
642
643 // All field names configured and not restricted to admins
644 if (is_array($GLOBALS['TCA'][$table]['columns'])
645 && empty($GLOBALS['TCA'][$table]['ctrl']['adminOnly'])
646 && (empty($GLOBALS['TCA'][$table]['ctrl']['rootLevel']) || !empty($GLOBALS['TCA'][$table]['ctrl']['security']['ignoreRootLevelRestriction']))
647 ) {
648 foreach ($GLOBALS['TCA'][$table]['columns'] as $field => $_) {
649 if ($GLOBALS['TCA'][$table]['columns'][$field]['exclude']) {
650 // Get human readable names of fields
651 $translatedField = $languageService->sl($GLOBALS['TCA'][$table]['columns'][$field]['label']);
652 // Add entry
653 $excludeArrayTable[] = [$translatedTable . ': ' . $translatedField, $table . ':' . $field];
654 }
655 }
656 }
657 // All FlexForm fields
658 $flexFormArray = $this->getRegisteredFlexForms($table);
659 foreach ($flexFormArray as $tableField => $flexForms) {
660 // Prefix for field label, e.g. "Plugin Options:"
661 $labelPrefix = '';
662 if (!empty($GLOBALS['TCA'][$table]['columns'][$tableField]['label'])) {
663 $labelPrefix = $languageService->sl($GLOBALS['TCA'][$table]['columns'][$tableField]['label']);
664 }
665 // Get all sheets and title
666 foreach ($flexForms as $extIdent => $extConf) {
667 $extTitle = $languageService->sl(trim($extConf['title']));
668 // Get all fields in sheet
669 foreach ($extConf['ds']['sheets'] as $sheetName => $sheet) {
670 if (empty($sheet['ROOT']['el']) || !is_array($sheet['ROOT']['el'])) {
671 continue;
672 }
673 foreach ($sheet['ROOT']['el'] as $fieldName => $field) {
674 // Use only fields that have exclude flag set
675 if (empty($field['TCEforms']['exclude'])) {
676 continue;
677 }
678 $fieldLabel = !empty(trim($field['TCEforms']['label'])) ? $languageService->sl(trim($field['TCEforms']['label'])) : $fieldName;
679 $fieldIdent = $table . ':' . $tableField . ';' . $extIdent . ';' . $sheetName . ';' . $fieldName;
680 $excludeArrayTable[] = [trim($labelPrefix . ' ' . $extTitle, ': ') . ': ' . $fieldLabel, $fieldIdent];
681 }
682 }
683 }
684 }
685 // Sort fields by the translated value
686 if (!empty($excludeArrayTable)) {
687 usort($excludeArrayTable, function (array $array1, array $array2) {
688 $array1 = reset($array1);
689 $array2 = reset($array2);
690 if (is_string($array1) && is_string($array2)) {
691 return strcasecmp($array1, $array2);
692 }
693 return 0;
694 });
695 $finalExcludeArray = array_merge($finalExcludeArray, $excludeArrayTable);
696 }
697 }
698
699 return $finalExcludeArray;
700 }
701
702 /**
703 * Returns all registered FlexForm definitions with title and fields
704 *
705 * @param string $table Table to handle
706 * @return array Data structures with speaking extension title
707 */
708 protected function getRegisteredFlexForms($table)
709 {
710 if (empty($table) || empty($GLOBALS['TCA'][$table]['columns'])) {
711 return [];
712 }
713 $flexForms = [];
714 foreach ($GLOBALS['TCA'][$table]['columns'] as $tableField => $fieldConf) {
715 if (!empty($fieldConf['config']['type']) && !empty($fieldConf['config']['ds']) && $fieldConf['config']['type'] == 'flex') {
716 $flexForms[$tableField] = [];
717 unset($fieldConf['config']['ds']['default']);
718 // Get pointer fields
719 $pointerFields = !empty($fieldConf['config']['ds_pointerField']) ? $fieldConf['config']['ds_pointerField'] : 'list_type,CType';
720 $pointerFields = GeneralUtility::trimExplode(',', $pointerFields);
721 // Get FlexForms
722 foreach ($fieldConf['config']['ds'] as $flexFormKey => $dataStructure) {
723 // Get extension identifier (uses second value if it's not empty, "list" or "*", else first one)
724 $identFields = GeneralUtility::trimExplode(',', $flexFormKey);
725 $extIdent = $identFields[0];
726 if (!empty($identFields[1]) && $identFields[1] !== 'list' && $identFields[1] !== '*') {
727 $extIdent = $identFields[1];
728 }
729 // Load external file references
730 if (!is_array($dataStructure)) {
731 $file = GeneralUtility::getFileAbsFileName(str_ireplace('FILE:', '', $dataStructure));
732 if ($file && @is_file($file)) {
733 $dataStructure = GeneralUtility::getUrl($file);
734 }
735 $dataStructure = GeneralUtility::xml2array($dataStructure);
736 if (!is_array($dataStructure)) {
737 continue;
738 }
739 }
740 // Get flexform content
741 $dataStructure = GeneralUtility::resolveAllSheetsInDS($dataStructure);
742 if (empty($dataStructure['sheets']) || !is_array($dataStructure['sheets'])) {
743 continue;
744 }
745 // Use DS pointer to get extension title from TCA
746 // @todo: I don't understand this code ... does it make sense at all?
747 $title = $extIdent;
748 $keyFields = GeneralUtility::trimExplode(',', $flexFormKey);
749 foreach ($pointerFields as $pointerKey => $pointerName) {
750 if (empty($keyFields[$pointerKey]) || $keyFields[$pointerKey] === '*' || $keyFields[$pointerKey] === 'list') {
751 continue;
752 }
753 if (!empty($GLOBALS['TCA'][$table]['columns'][$pointerName]['config']['items'])) {
754 $items = $GLOBALS['TCA'][$table]['columns'][$pointerName]['config']['items'];
755 if (!is_array($items)) {
756 continue;
757 }
758 foreach ($items as $itemConf) {
759 if (!empty($itemConf[0]) && !empty($itemConf[1]) && $itemConf[1] == $keyFields[$pointerKey]) {
760 $title = $itemConf[0];
761 break 2;
762 }
763 }
764 }
765 }
766 $flexForms[$tableField][$extIdent] = [
767 'title' => $title,
768 'ds' => $dataStructure
769 ];
770 }
771 }
772 }
773 return $flexForms;
774 }
775
776 /**
777 * Returns an array with explicit Allow/Deny fields.
778 * Used for listing these field/value pairs in be_groups forms
779 *
780 * @return array Array with information from all of $GLOBALS['TCA']
781 */
782 protected function getExplicitAuthFieldValues()
783 {
784 $languageService = static::getLanguageService();
785 $adLabel = [
786 'ALLOW' => $languageService->sl('LLL:EXT:lang/locallang_core.xlf:labels.allow'),
787 'DENY' => $languageService->sl('LLL:EXT:lang/locallang_core.xlf:labels.deny')
788 ];
789 $allowDenyOptions = [];
790 foreach ($GLOBALS['TCA'] as $table => $_) {
791 // All field names configured:
792 if (is_array($GLOBALS['TCA'][$table]['columns'])) {
793 foreach ($GLOBALS['TCA'][$table]['columns'] as $field => $_) {
794 $fieldConfig = $GLOBALS['TCA'][$table]['columns'][$field]['config'];
795 if ($fieldConfig['type'] === 'select' && $fieldConfig['authMode']) {
796 // Check for items
797 if (is_array($fieldConfig['items'])) {
798 // Get Human Readable names of fields and table:
799 $allowDenyOptions[$table . ':' . $field]['tableFieldLabel'] =
800 $languageService->sl($GLOBALS['TCA'][$table]['ctrl']['title']) . ': '
801 . $languageService->sl($GLOBALS['TCA'][$table]['columns'][$field]['label']);
802 foreach ($fieldConfig['items'] as $iVal) {
803 // Values '' is not controlled by this setting.
804 if ((string)$iVal[1] !== '') {
805 // Find iMode
806 $iMode = '';
807 switch ((string)$fieldConfig['authMode']) {
808 case 'explicitAllow':
809 $iMode = 'ALLOW';
810 break;
811 case 'explicitDeny':
812 $iMode = 'DENY';
813 break;
814 case 'individual':
815 if ($iVal[4] === 'EXPL_ALLOW') {
816 $iMode = 'ALLOW';
817 } elseif ($iVal[4] === 'EXPL_DENY') {
818 $iMode = 'DENY';
819 }
820 break;
821 }
822 // Set iMode
823 if ($iMode) {
824 $allowDenyOptions[$table . ':' . $field]['items'][$iVal[1]] = [
825 $iMode,
826 $languageService->sl($iVal[0]),
827 $adLabel[$iMode]
828 ];
829 }
830 }
831 }
832 }
833 }
834 }
835 }
836 }
837 return $allowDenyOptions;
838 }
839
840 /**
841 * Build query to fetch foreign records
842 *
843 * @param array $result Result array
844 * @param string $localFieldName Current handle field name
845 * @return array Query array ready to be executed via Database->exec_SELECT_queryArray()
846 * @throws \UnexpectedValueException
847 */
848 protected function buildForeignTableQuery(array $result, $localFieldName)
849 {
850 $backendUser = $this->getBackendUser();
851
852 $foreignTableName = $result['processedTca']['columns'][$localFieldName]['config']['foreign_table'];
853
854 if (!is_array($GLOBALS['TCA'][$foreignTableName])) {
855 throw new \UnexpectedValueException(
856 'Field ' . $localFieldName . ' of table ' . $result['tableName'] . ' reference to foreign table '
857 . $foreignTableName . ', but this table is not defined in TCA',
858 1439569743
859 );
860 }
861
862 $foreignTableClauseArray = $this->processForeignTableClause($result, $foreignTableName, $localFieldName);
863
864 $queryArray = [];
865 $queryArray['SELECT'] = BackendUtility::getCommonSelectFields($foreignTableName, $foreignTableName . '.');
866
867 // rootLevel = -1 means that elements can be on the rootlevel OR on any page (pid!=-1)
868 // rootLevel = 0 means that elements are not allowed on root level
869 // rootLevel = 1 means that elements are only on the root level (pid=0)
870 $rootLevel = 0;
871 if (isset($GLOBALS['TCA'][$foreignTableName]['ctrl']['rootLevel'])) {
872 $rootLevel = $GLOBALS['TCA'][$foreignTableName]['ctrl']['rootLevel'];
873 }
874 $deleteClause = BackendUtility::deleteClause($foreignTableName);
875 if ($rootLevel == 1 || $rootLevel == -1) {
876 $pidWhere = $foreignTableName . '.pid' . (($rootLevel == -1) ? '<>-1' : '=0');
877 $queryArray['FROM'] = $foreignTableName;
878 $queryArray['WHERE'] = $pidWhere . $deleteClause . $foreignTableClauseArray['WHERE'];
879 } else {
880 $pageClause = $backendUser->getPagePermsClause(1);
881 if ($foreignTableName === 'pages') {
882 $queryArray['FROM'] = 'pages';
883 $queryArray['WHERE'] = '1=1' . $deleteClause . ' AND' . $pageClause . $foreignTableClauseArray['WHERE'];
884 } else {
885 $queryArray['FROM'] = $foreignTableName . ', pages';
886 $queryArray['WHERE'] = 'pages.uid=' . $foreignTableName . '.pid AND pages.deleted=0'
887 . $deleteClause . ' AND' . $pageClause . $foreignTableClauseArray['WHERE'];
888 }
889 }
890
891 $queryArray['GROUPBY'] = $foreignTableClauseArray['GROUPBY'];
892 $queryArray['ORDERBY'] = $foreignTableClauseArray['ORDERBY'];
893 $queryArray['LIMIT'] = $foreignTableClauseArray['LIMIT'];
894
895 return $queryArray;
896 }
897
898 /**
899 * Replace markers in a where clause from TCA foreign_table_where
900 *
901 * ###REC_FIELD_[field name]###
902 * ###THIS_UID### - is current element uid (zero if new).
903 * ###CURRENT_PID### - is the current page id (pid of the record).
904 * ###SITEROOT###
905 * ###PAGE_TSCONFIG_ID### - a value you can set from Page TSconfig dynamically.
906 * ###PAGE_TSCONFIG_IDLIST### - a value you can set from Page TSconfig dynamically.
907 * ###PAGE_TSCONFIG_STR### - a value you can set from Page TSconfig dynamically.
908 *
909 * @param array $result Result array
910 * @param string $foreignTableName Name of foreign table
911 * @param string $localFieldName Current handle field name
912 * @return array Query parts with keys WHERE, ORDERBY, GROUPBY, LIMIT
913 */
914 protected function processForeignTableClause(array $result, $foreignTableName, $localFieldName)
915 {
916 $database = $this->getDatabaseConnection();
917 $localTable = $result['tableName'];
918
919 $foreignTableClause = '';
920 if (!empty($result['processedTca']['columns'][$localFieldName]['config']['foreign_table_where'])
921 && is_string($result['processedTca']['columns'][$localFieldName]['config']['foreign_table_where'])
922 ) {
923 $foreignTableClause = $result['processedTca']['columns'][$localFieldName]['config']['foreign_table_where'];
924 // Replace possible markers in query
925 if (strstr($foreignTableClause, '###REC_FIELD_')) {
926 // " AND table.field='###REC_FIELD_field1###' AND ..." -> array(" AND table.field='", "field1###' AND ...")
927 $whereClauseParts = explode('###REC_FIELD_', $foreignTableClause);
928 foreach ($whereClauseParts as $key => $value) {
929 if ($key !== 0) {
930 // "field1###' AND ..." -> array("field1", "' AND ...")
931 $whereClauseSubParts = explode('###', $value, 2);
932 // @todo: Throw exception if there is no value? What happens for NEW records?
933 $rowFieldValue = $result['databaseRow'][$whereClauseSubParts[0]];
934 if (is_array($rowFieldValue)) {
935 // If a select or group field is used here, it may have been processed already and
936 // is now an array. Use first selected value in this case.
937 $rowFieldValue = $rowFieldValue[0];
938 }
939 if (substr($whereClauseParts[0], -1) === '\'' && $whereClauseSubParts[1][0] === '\'') {
940 $whereClauseParts[$key] = $database->quoteStr($rowFieldValue, $foreignTableName) . $whereClauseSubParts[1];
941 } else {
942 $whereClauseParts[$key] = $database->fullQuoteStr($rowFieldValue, $foreignTableName) . $whereClauseSubParts[1];
943 }
944 }
945 }
946 $foreignTableClause = implode('', $whereClauseParts);
947 }
948
949 $siteRootUid = 0;
950 foreach ($result['rootline'] as $rootlinePage) {
951 if (!empty($rootlinePage['is_siteroot'])) {
952 $siteRootUid = (int)$rootlinePage['uid'];
953 break;
954 }
955 }
956 $pageTsConfigId = 0;
957 if ($result['pageTsConfig']['TCEFORM.'][$localTable . '.'][$localFieldName . '.']['PAGE_TSCONFIG_ID']) {
958 $pageTsConfigId = (int)$result['pageTsConfig']['TCEFORM.'][$localTable . '.'][$localFieldName . '.']['PAGE_TSCONFIG_ID'];
959 }
960 $pageTsConfigIdList = 0;
961 if ($result['pageTsConfig']['TCEFORM.'][$localTable . '.'][$localFieldName . '.']['PAGE_TSCONFIG_IDLIST']) {
962 $pageTsConfigIdList = $result['pageTsConfig']['TCEFORM.'][$localTable . '.'][$localFieldName . '.']['PAGE_TSCONFIG_IDLIST'];
963 $pageTsConfigIdListArray = GeneralUtility::trimExplode(',', $pageTsConfigIdList, true);
964 $pageTsConfigIdList = [];
965 foreach ($pageTsConfigIdListArray as $pageTsConfigIdListElement) {
966 if (MathUtility::canBeInterpretedAsInteger($pageTsConfigIdListElement)) {
967 $pageTsConfigIdList[] = (int)$pageTsConfigIdListElement;
968 }
969 }
970 $pageTsConfigIdList = implode(',', $pageTsConfigIdList);
971 }
972 $pageTsConfigString = '';
973 if ($result['pageTsConfig']['TCEFORM.'][$localTable . '.'][$localFieldName . '.']['PAGE_TSCONFIG_STR']) {
974 $pageTsConfigString = $result['pageTsConfig']['TCEFORM.'][$localTable . '.'][$localFieldName . '.']['PAGE_TSCONFIG_STR'];
975 $pageTsConfigString = $database->quoteStr($pageTsConfigString, $foreignTableName);
976 }
977
978 $foreignTableClause = str_replace(
979 [
980 '###CURRENT_PID###',
981 '###THIS_UID###',
982 '###SITEROOT###',
983 '###PAGE_TSCONFIG_ID###',
984 '###PAGE_TSCONFIG_IDLIST###',
985 '###PAGE_TSCONFIG_STR###'
986 ],
987 [
988 (int)$result['effectivePid'],
989 (int)$result['databaseRow']['uid'],
990 $siteRootUid,
991 $pageTsConfigId,
992 $pageTsConfigIdList,
993 $pageTsConfigString
994 ],
995 $foreignTableClause
996 );
997 }
998
999 // Split the clause into an array with keys WHERE, GROUPBY, ORDERBY, LIMIT
1000 // Prepend a space to make sure "[[:space:]]+" will find a space there for the first element.
1001 $foreignTableClause = ' ' . $foreignTableClause;
1002 $foreignTableClauseArray = [
1003 'WHERE' => '',
1004 'GROUPBY' => '',
1005 'ORDERBY' => '',
1006 'LIMIT' => '',
1007 ];
1008 // Find LIMIT
1009 $reg = [];
1010 if (preg_match('/^(.*)[[:space:]]+LIMIT[[:space:]]+([[:alnum:][:space:],._]+)$/i', $foreignTableClause, $reg)) {
1011 $foreignTableClauseArray['LIMIT'] = trim($reg[2]);
1012 $foreignTableClause = $reg[1];
1013 }
1014 // Find ORDER BY
1015 $reg = [];
1016 if (preg_match('/^(.*)[[:space:]]+ORDER[[:space:]]+BY[[:space:]]+([[:alnum:][:space:],._]+)$/i', $foreignTableClause, $reg)) {
1017 $foreignTableClauseArray['ORDERBY'] = trim($reg[2]);
1018 $foreignTableClause = $reg[1];
1019 }
1020 // Find GROUP BY
1021 $reg = [];
1022 if (preg_match('/^(.*)[[:space:]]+GROUP[[:space:]]+BY[[:space:]]+([[:alnum:][:space:],._]+)$/i', $foreignTableClause, $reg)) {
1023 $foreignTableClauseArray['GROUPBY'] = trim($reg[2]);
1024 $foreignTableClause = $reg[1];
1025 }
1026 // Rest is assumed to be "WHERE" clause
1027 $foreignTableClauseArray['WHERE'] = $foreignTableClause;
1028
1029 return $foreignTableClauseArray;
1030 }
1031
1032 /**
1033 * Convert the current database values into an array
1034 *
1035 * @param array $row database row
1036 * @param string $fieldName fieldname to process
1037 * @return array
1038 */
1039 protected function processDatabaseFieldValue(array $row, $fieldName)
1040 {
1041 $currentDatabaseValues = array_key_exists($fieldName, $row)
1042 ? $row[$fieldName]
1043 : '';
1044 return GeneralUtility::trimExplode(',', $currentDatabaseValues, true);
1045 }
1046
1047 /**
1048 * Validate and sanitize database row values of the select field with the given name.
1049 * Creates an array out of databaseRow[selectField] values.
1050 *
1051 * Used by TcaSelectItems and TcaSelectTreeItems data providers
1052 *
1053 * @param array $result The current result array.
1054 * @param string $fieldName Name of the current select field.
1055 * @param array $staticValues Array with statically defined items, item value is used as array key.
1056 * @return array
1057 */
1058 protected function processSelectFieldValue(array $result, $fieldName, array $staticValues)
1059 {
1060 $fieldConfig = $result['processedTca']['columns'][$fieldName];
1061
1062 $currentDatabaseValueArray = array_key_exists($fieldName, $result['databaseRow']) ? $result['databaseRow'][$fieldName] : [];
1063 $newDatabaseValueArray = [];
1064
1065 // Add all values that were defined by static methods and do not come from the relation
1066 // e.g. TCA, TSconfig, itemProcFunc etc.
1067 foreach ($currentDatabaseValueArray as $value) {
1068 if (isset($staticValues[$value])) {
1069 $newDatabaseValueArray[] = $value;
1070 }
1071 }
1072
1073 if (isset($fieldConfig['config']['foreign_table']) && !empty($fieldConfig['config']['foreign_table'])) {
1074 /** @var RelationHandler $relationHandler */
1075 $relationHandler = GeneralUtility::makeInstance(RelationHandler::class);
1076 $relationHandler->registerNonTableValues = !empty($fieldConfig['config']['allowNonIdValues']);
1077 if (!empty($fieldConfig['config']['MM']) && $result['command'] !== 'new') {
1078 // MM relation
1079 $relationHandler->start(
1080 implode(',', $currentDatabaseValueArray),
1081 $fieldConfig['config']['foreign_table'],
1082 $fieldConfig['config']['MM'],
1083 $result['databaseRow']['uid'],
1084 $result['tableName'],
1085 $fieldConfig['config']
1086 );
1087 } else {
1088 // Non MM relation
1089 // If not dealing with MM relations, use default live uid, not versioned uid for record relations
1090 $relationHandler->start(
1091 implode(',', $currentDatabaseValueArray),
1092 $fieldConfig['config']['foreign_table'],
1093 '',
1094 $this->getLiveUid($result),
1095 $result['tableName'],
1096 $fieldConfig['config']
1097 );
1098 }
1099 $newDatabaseValueArray = array_merge($newDatabaseValueArray, $relationHandler->getValueArray());
1100 }
1101
1102 return array_unique($newDatabaseValueArray);
1103 }
1104
1105 /**
1106 * Translate the item labels
1107 *
1108 * Used by TcaSelectItems and TcaSelectTreeItems data providers
1109 *
1110 * @param array $result Result array
1111 * @param array $itemArray Items
1112 * @param string $table
1113 * @param string $fieldName
1114 * @return array
1115 */
1116 public function translateLabels(array $result, array $itemArray, $table, $fieldName)
1117 {
1118 $languageService = $this->getLanguageService();
1119
1120 foreach ($itemArray as $key => $item) {
1121 if (!isset($dynamicItems[$key])) {
1122 $staticValues[$item[1]] = $item;
1123 }
1124 if (isset($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['altLabels.'][$item[1]])
1125 && !empty($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['altLabels.'][$item[1]])
1126 ) {
1127 $label = $languageService->sL($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['altLabels.'][$item[1]]);
1128 } else {
1129 $label = $languageService->sL(trim($item[0]));
1130 }
1131 $value = strlen((string)$item[1]) > 0 ? $item[1] : '';
1132 $icon = $item[2] ?: null;
1133 $helpText = $item[3] ?: null;
1134 $itemArray[$key] = [
1135 $label,
1136 $value,
1137 $icon,
1138 $helpText
1139 ];
1140 }
1141
1142 return $itemArray;
1143 }
1144
1145 /**
1146 * Sanitize incoming item array
1147 *
1148 * Used by TcaSelectItems and TcaSelectTreeItems data providers
1149 *
1150 * @param mixed $itemArray
1151 * @param string $tableName
1152 * @param string $fieldName
1153 * @return array
1154 */
1155 public function sanitizeItemArray($itemArray, $tableName, $fieldName)
1156 {
1157 if (!is_array($itemArray)) {
1158 $itemArray = [];
1159 }
1160 foreach ($itemArray as $item) {
1161 if (!is_array($item)) {
1162 throw new \UnexpectedValueException(
1163 'An item in field ' . $fieldName . ' of table ' . $tableName . ' is not an array as expected',
1164 1439288036
1165 );
1166 }
1167 }
1168
1169 return $itemArray;
1170 }
1171
1172 /**
1173 * Make sure maxitems is always filled with a valid integer value.
1174 *
1175 * Used by TcaSelectItems and TcaSelectTreeItems data providers
1176 *
1177 * @param mixed $maxItems
1178 * @return int
1179 */
1180 public function sanitizeMaxItems($maxItems)
1181 {
1182 if (
1183 !empty($maxItems)
1184 && (int)$maxItems > 1
1185 ) {
1186 $maxItems = (int)$maxItems;
1187 } else {
1188 $maxItems = 1;
1189 }
1190
1191 return $maxItems;
1192 }
1193
1194 /**
1195 * Gets the record uid of the live default record. If already
1196 * pointing to the live record, the submitted record uid is returned.
1197 *
1198 * @param array $result Result array
1199 * @return int
1200 * @throws \UnexpectedValueException
1201 */
1202 protected function getLiveUid(array $result)
1203 {
1204 $table = $result['tableName'];
1205 $row = $result['databaseRow'];
1206 $uid = $row['uid'];
1207 if (!empty($result['processedTca']['ctrl']['versioningWS'])
1208 && $result['pid'] === -1
1209 ) {
1210 if (empty($row['t3ver_oid'])) {
1211 throw new \UnexpectedValueException(
1212 'No t3ver_oid found for record ' . $row['uid'] . ' on table ' . $table,
1213 1440066481
1214 );
1215 }
1216 $uid = $row['t3ver_oid'];
1217 }
1218 return $uid;
1219 }
1220
1221 /**
1222 * Determine the static values in the item array
1223 *
1224 * Used by TcaSelectItems and TcaSelectTreeItems data providers
1225 *
1226 * @param array $itemArray All item records for the select field
1227 * @param array $dynamicItemArray Item records from dynamic sources
1228 * @return array
1229 */
1230 public function getStaticValues($itemArray, $dynamicItemArray)
1231 {
1232 $staticValues = [];
1233 foreach ($itemArray as $key => $item) {
1234 if (!isset($dynamicItemArray[$key])) {
1235 $staticValues[$item[1]] = $item;
1236 }
1237 }
1238 return $staticValues;
1239 }
1240
1241 /**
1242 * @return LanguageService
1243 */
1244 protected function getLanguageService()
1245 {
1246 return $GLOBALS['LANG'];
1247 }
1248
1249 /**
1250 * @return DatabaseConnection
1251 */
1252 protected function getDatabaseConnection()
1253 {
1254 return $GLOBALS['TYPO3_DB'];
1255 }
1256
1257 /**
1258 * @return BackendUserAuthentication
1259 */
1260 protected function getBackendUser()
1261 {
1262 return $GLOBALS['BE_USER'];
1263 }
1264 }