TYPO3 CMS  TYPO3_8-7
TcaSelectTreeItems.php
Go to the documentation of this file.
1 <?php
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 
25 
38 {
46  public function addData(array $result)
47  {
48  $table = $result['tableName'];
49 
50  foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfig) {
51  if (empty($fieldConfig['config']['type']) || $fieldConfig['config']['type'] !== 'select') {
52  continue;
53  }
54 
55  // Make sure we are only processing supported renderTypes
56  if (!$this->isTargetRenderType($fieldConfig)) {
57  continue;
58  }
59 
60  $fieldConfig['config']['maxitems'] = MathUtility::forceIntegerInRange($fieldConfig['config']['maxitems'], 0, 99999);
61  if ($fieldConfig['config']['maxitems'] === 0) {
62  $fieldConfig['config']['maxitems'] = 99999;
63  }
64 
65  // A couple of tree specific config parameters can be overwritten via page TS.
66  // Pick those that influence the data fetching and write them into the config
67  // given to the tree data provider. This is additionally used in SelectTreeElement, so always do that.
68  if (isset($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['config.']['treeConfig.'])) {
69  $pageTsConfig = $result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['config.']['treeConfig.'];
70  // If rootUid is set in pageTsConfig, use it
71  if (isset($pageTsConfig['rootUid'])) {
72  $fieldConfig['config']['treeConfig']['rootUid'] = (int)$pageTsConfig['rootUid'];
73  }
74  if (isset($pageTsConfig['appearance.']['expandAll'])) {
75  $fieldConfig['config']['treeConfig']['appearance']['expandAll'] = (bool)$pageTsConfig['appearance.']['expandAll'];
76  }
77  if (isset($pageTsConfig['appearance.']['maxLevels'])) {
78  $fieldConfig['config']['treeConfig']['appearance']['maxLevels'] = (int)$pageTsConfig['appearance.']['maxLevels'];
79  }
80  if (isset($pageTsConfig['appearance.']['nonSelectableLevels'])) {
81  $fieldConfig['config']['treeConfig']['appearance']['nonSelectableLevels'] = $pageTsConfig['appearance.']['nonSelectableLevels'];
82  }
83  }
84 
85  // Prepare the list of currently selected nodes using RelationHandler
86  // This is needed to ensure a correct value initialization before the actual tree is loaded
87  $result['databaseRow'][$fieldName] = $this->processDatabaseFieldValue($result['databaseRow'], $fieldName);
88  $result['databaseRow'][$fieldName] = $this->processSelectFieldValue($result, $fieldName, []);
89 
90  if ($result['selectTreeCompileItems']) {
91  $finalItems = [];
92 
93  // Prepare the list of "static" items if there are any.
94  // "static" and "dynamic" is separated since the tree code only copes with "real" existing foreign nodes,
95  // so this "static" stuff allows defining tree items that don't really exist in the tree.
96  $itemsFromTca = $this->sanitizeItemArray($fieldConfig['config']['items'], $table, $fieldName);
97 
98  // List of additional items defined by page ts config "addItems"
99  $itemsFromPageTsConfig = $this->addItemsFromPageTsConfig($result, $fieldName, []);
100  // Resolve pageTsConfig item icons to markup
101  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
102  $finalPageTsConfigItems = [];
103  foreach ($itemsFromPageTsConfig as $item) {
104  if ($item[2] !== null) {
105  $item[2] = $iconFactory->getIcon($item[2], Icon::SIZE_SMALL)->getMarkup('inline');
106  }
107  $finalPageTsConfigItems[] = $item;
108  }
109 
110  if (!empty($itemsFromTca) || !empty($finalPageTsConfigItems)) {
111  // First apply "keepItems" to $itemsFromTca, this will restrict the tca item list to only
112  // those items that are defined in page ts "keepItems" if given
113  $itemsFromTca = $this->removeItemsByKeepItemsPageTsConfig($result, $fieldName, $itemsFromTca);
114  // Then, merge the items from page ts "addItems" into item list, since "addItems" should
115  // add additional items even if they are not in the "keepItems" list
116  $staticItems = array_merge($itemsFromTca, $finalPageTsConfigItems);
117  // Now apply page ts config "removeItems", so this is *after* addItems, so "removeItems" could
118  // possibly remove items again that were added via "addItems"
119  $staticItems = $this->removeItemsByRemoveItemsPageTsConfig($result, $fieldName, $staticItems);
120  // Now, apply user and access right restrictions to this item list
121  $staticItems = $this->removeItemsByUserLanguageFieldRestriction($result, $fieldName, $staticItems);
122  $staticItems = $this->removeItemsByUserAuthMode($result, $fieldName, $staticItems);
123  $staticItems = $this->removeItemsByDoktypeUserRestriction($result, $fieldName, $staticItems);
124  // Call itemsProcFunc if given. Note this function does *not* see the "dynamic" list of items
125  if (!empty($fieldConfig['config']['itemsProcFunc'])) {
126  $staticItems = $this->resolveItemProcessorFunction($result, $fieldName, $staticItems);
127  // itemsProcFunc must not be used anymore
128  unset($fieldConfig['config']['itemsProcFunc']);
129  }
130  // And translate any labels from the static list
131  $staticItems = $this->translateLabels($result, $staticItems, $table, $fieldName);
132  // Now compile the target items using the same array structure as the "dynamic" list below
133  foreach ($staticItems as $item) {
134  if ($item[1] === '--div--') {
135  // Skip divs that may occur here for whatever reason
136  continue;
137  }
138  $finalItems[] = [
139  'identifier' => $item[1],
140  'name' => $item[0],
141  'icon' => $item[2] ?? '',
142  'iconOverlay' => '',
143  'depth' => 0,
144  'hasChildren' => false,
145  'selectable' => true,
146  'checked' => in_array($item[1], $result['databaseRow'][$fieldName]),
147  ];
148  }
149  }
150 
151  // Fetch the list of all possible "related" items (yuk!) and apply a similar processing as with the "static" list
152  $dynamicItems = $this->addItemsFromForeignTable($result, $fieldName, []);
153  $dynamicItems = $this->removeItemsByKeepItemsPageTsConfig($result, $fieldName, $dynamicItems);
154  $dynamicItems = $this->removeItemsByRemoveItemsPageTsConfig($result, $fieldName, $dynamicItems);
155  $dynamicItems = $this->removeItemsByUserLanguageFieldRestriction($result, $fieldName, $dynamicItems);
156  $dynamicItems = $this->removeItemsByUserAuthMode($result, $fieldName, $dynamicItems);
157  $dynamicItems = $this->removeItemsByDoktypeUserRestriction($result, $fieldName, $dynamicItems);
158  // Funnily, the only data needed for the tree code are the uids of the possible records (yuk!) - get them
159  $uidListOfAllDynamicItems = [];
160  foreach ($dynamicItems as $item) {
161  if ((int)$item[1] > 0) {
162  $uidListOfAllDynamicItems[] = (int)$item[1];
163  }
164  }
165  // Now kick in this tree stuff
166  $treeDataProvider = TreeDataProviderFactory::getDataProvider(
167  $fieldConfig['config'],
168  $table,
169  $fieldName,
170  $result['databaseRow']
171  );
172  $treeDataProvider->setSelectedList(implode(',', $result['databaseRow'][$fieldName]));
173  // Basically the tree foo fetches all tree nodes again (aaargs), then verifies if
174  // a given rows uid is within this "list of allowed uids". It then creates an object
175  // tree representing the nested tree, just to collapse all that to a flat array again. Yay ...
176  $treeDataProvider->setItemWhiteList($uidListOfAllDynamicItems);
177  $treeDataProvider->initializeTreeData();
178  $treeRenderer = GeneralUtility::makeInstance(ExtJsArrayTreeRenderer::class);
179  $tree = GeneralUtility::makeInstance(TableConfigurationTree::class);
180  $tree->setDataProvider($treeDataProvider);
181  $tree->setNodeRenderer($treeRenderer);
182 
183  // Merge tree nodes after calculated nodes from static items
184  $fieldConfig['config']['items'] = array_merge($finalItems, $tree->render());
185  }
186 
187  $result['processedTca']['columns'][$fieldName] = $fieldConfig;
188  }
189 
190  return $result;
191  }
192 
199  protected function isTargetRenderType(array $fieldConfig)
200  {
201  return $fieldConfig['config']['renderType'] === 'selectTree';
202  }
203 }
removeItemsByUserLanguageFieldRestriction(array $result, $fieldName, array $items)
removeItemsByUserAuthMode(array $result, $fieldName, array $items)
static forceIntegerInRange($theInt, $min, $max=2000000000, $defaultValue=0)
Definition: MathUtility.php:31
translateLabels(array $result, array $itemArray, $table, $fieldName)
addItemsFromPageTsConfig(array $result, $fieldName, array $items)
static makeInstance($className,... $constructorArguments)
removeItemsByKeepItemsPageTsConfig(array $result, $fieldName, array $items)
removeItemsByRemoveItemsPageTsConfig(array $result, $fieldName, array $items)
removeItemsByDoktypeUserRestriction(array $result, $fieldName, array $items)