92fed04939be7fd3cee7e68f5a82ba10e153250a
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Form / FormDataProvider / TcaSelectTreeItems.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\Form\FormDataProviderInterface;
18 use TYPO3\CMS\Core\Tree\TableConfiguration\ExtJsArrayTreeRenderer;
19 use TYPO3\CMS\Core\Tree\TableConfiguration\TableConfigurationTree;
20 use TYPO3\CMS\Core\Tree\TableConfiguration\TreeDataProviderFactory;
21 use TYPO3\CMS\Core\Utility\GeneralUtility;
22
23 /**
24 * Resolve select items, set processed item list in processedTca, sanitize and resolve database field
25 */
26 class TcaSelectTreeItems extends AbstractItemProvider implements FormDataProviderInterface
27 {
28 /**
29 * Resolve select items
30 *
31 * @param array $result
32 * @return array
33 * @throws \UnexpectedValueException
34 */
35 public function addData(array $result)
36 {
37 $table = $result['tableName'];
38
39 foreach ($result['processedTca']['columns'] as $fieldName => $fieldConfig) {
40 if (empty($fieldConfig['config']['type']) || $fieldConfig['config']['type'] !== 'select') {
41 continue;
42 }
43
44 // Make sure we are only processing supported renderTypes
45 if (!$this->isTargetRenderType($fieldConfig)) {
46 continue;
47 }
48
49 $fieldConfig['config']['maxitems'] = $this->sanitizeMaxItems($fieldConfig['config']['maxitems']);
50
51 // A couple of tree specific config parameters can be overwritten via page TS.
52 // Pick those that influence the data fetching and write them into the config
53 // given to the tree data provider
54 if (isset($result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['config.']['treeConfig.'])) {
55 $pageTsConfig = $result['pageTsConfig']['TCEFORM.'][$table . '.'][$fieldName . '.']['config.']['treeConfig.'];
56 // If rootUid is set in pageTsConfig, use it
57 if (isset($pageTsConfig['rootUid'])) {
58 $fieldConfig['config']['treeConfig']['rootUid'] = (int)$pageTsConfig['rootUid'];
59 }
60 if (isset($pageTsConfig['appearance.']['expandAll'])) {
61 $fieldConfig['config']['treeConfig']['appearance']['expandAll'] = (bool)$pageTsConfig['appearance.']['expandAll'];
62 }
63 if (isset($pageTsConfig['appearance.']['maxLevels'])) {
64 $fieldConfig['config']['treeConfig']['appearance']['maxLevels'] = (int)$pageTsConfig['appearance.']['maxLevels'];
65 }
66 if (isset($pageTsConfig['appearance.']['nonSelectableLevels'])) {
67 $fieldConfig['config']['treeConfig']['appearance']['nonSelectableLevels'] = $pageTsConfig['appearance.']['nonSelectableLevels'];
68 }
69 }
70
71 if ($result['selectTreeCompileItems']) {
72 $fieldConfig['config']['items'] = $this->sanitizeItemArray($fieldConfig['config']['items'], $table, $fieldName);
73
74 $pageTsConfigAddItems = $this->addItemsFromPageTsConfig($result, $fieldName, []);
75 $fieldConfig['config']['items'] = $this->addItemsFromSpecial($result, $fieldName, $fieldConfig['config']['items']);
76 $fieldConfig['config']['items'] = $this->addItemsFromFolder($result, $fieldName, $fieldConfig['config']['items']);
77 $staticItems = $fieldConfig['config']['items'] + $pageTsConfigAddItems;
78
79 $fieldConfig['config']['items'] = $this->addItemsFromForeignTable($result, $fieldName, $fieldConfig['config']['items']);
80 $dynamicItems = array_diff_key($fieldConfig['config']['items'], $staticItems);
81
82 $fieldConfig['config']['items'] = $this->removeItemsByKeepItemsPageTsConfig($result, $fieldName, $fieldConfig['config']['items']);
83 $fieldConfig['config']['items'] = $pageTsConfigAddItems + $fieldConfig['config']['items'];
84 $fieldConfig['config']['items'] = $this->removeItemsByRemoveItemsPageTsConfig($result, $fieldName, $fieldConfig['config']['items']);
85
86 $fieldConfig['config']['items'] = $this->removeItemsByUserLanguageFieldRestriction($result, $fieldName, $fieldConfig['config']['items']);
87 $fieldConfig['config']['items'] = $this->removeItemsByUserAuthMode($result, $fieldName, $fieldConfig['config']['items']);
88 $fieldConfig['config']['items'] = $this->removeItemsByDoktypeUserRestriction($result, $fieldName, $fieldConfig['config']['items']);
89
90 // Resolve "itemsProcFunc"
91 if (!empty($fieldConfig['config']['itemsProcFunc'])) {
92 $fieldConfig['config']['items'] = $this->resolveItemProcessorFunction($result, $fieldName, $fieldConfig['config']['items']);
93 // itemsProcFunc must not be used anymore
94 unset($fieldConfig['config']['itemsProcFunc']);
95 }
96
97 // Translate labels
98 $fieldConfig['config']['items'] = $this->translateLabels($result, $fieldConfig['config']['items'], $table, $fieldName);
99
100 $staticValues = $this->getStaticValues($fieldConfig['config']['items'], $dynamicItems);
101 $result['databaseRow'][$fieldName] = $this->processDatabaseFieldValue($result['databaseRow'], $fieldName);
102 $result['databaseRow'][$fieldName] = $this->processSelectFieldValue($result, $fieldName, $staticValues);
103
104 // Keys may contain table names, so a numeric array is created
105 $fieldConfig['config']['items'] = array_values($fieldConfig['config']['items']);
106
107 $fieldConfig['config']['treeData'] = $this->renderTree($result, $fieldConfig, $fieldName, $staticItems);
108 }
109
110 $result['processedTca']['columns'][$fieldName] = $fieldConfig;
111 }
112
113 return $result;
114 }
115
116 /**
117 * Renders the Ext JS tree.
118 *
119 * @param array $result The current result array.
120 * @param array $fieldConfig The configuration of the current field.
121 * @param string $fieldName The name of the current field.
122 * @param array $staticItems The static items from the field config.
123 * @return array The tree data configuration
124 */
125 protected function renderTree(array $result, array $fieldConfig, $fieldName, array $staticItems)
126 {
127 $allowedUids = [];
128 foreach ($fieldConfig['config']['items'] as $item) {
129 if ((int)$item[1] > 0) {
130 $allowedUids[] = $item[1];
131 }
132 }
133
134 $treeDataProvider = TreeDataProviderFactory::getDataProvider(
135 $fieldConfig['config'],
136 $result['tableName'],
137 $fieldName,
138 $result['databaseRow']
139 );
140 $treeDataProvider->setSelectedList(is_array($result['databaseRow'][$fieldName]) ? implode(',', $result['databaseRow'][$fieldName]) : $result['databaseRow'][$fieldName]);
141 $treeDataProvider->setItemWhiteList($allowedUids);
142 $treeDataProvider->initializeTreeData();
143
144 /** @var ExtJsArrayTreeRenderer $treeRenderer */
145 $treeRenderer = GeneralUtility::makeInstance(ExtJsArrayTreeRenderer::class);
146
147 /** @var TableConfigurationTree $tree */
148 $tree = GeneralUtility::makeInstance(TableConfigurationTree::class);
149 $tree->setDataProvider($treeDataProvider);
150 $tree->setNodeRenderer($treeRenderer);
151
152 $treeItems = $this->prepareAdditionalItems($staticItems, $result['databaseRow'][$fieldName]);
153 $treeItems[] = $tree->render();
154
155 $treeConfig = [
156 'items' => $treeItems,
157 ];
158
159 return $treeConfig;
160 }
161
162 /**
163 * Prepare the additional items that get prepended to the tree as leaves
164 *
165 * @param array $itemArray
166 * @param array $selectedNodes
167 * @return array
168 */
169 protected function prepareAdditionalItems(array $itemArray, array $selectedNodes)
170 {
171 $additionalItems = [];
172
173 foreach ($itemArray as $item) {
174 if ($item[1] === '--div--') {
175 continue;
176 }
177
178 $additionalItems[] = [
179 'uid' => $item[1],
180 'text' => $item[0],
181 'selectable' => true,
182 'leaf' => true,
183 'checked' => in_array($item[1], $selectedNodes),
184 'icon' => $item[2]
185 ];
186 }
187
188 return $additionalItems;
189 }
190
191 /**
192 * Determines whether the current field is a valid target for this DataProvider
193 *
194 * @param array $fieldConfig
195 * @return bool
196 */
197 protected function isTargetRenderType(array $fieldConfig)
198 {
199 return $fieldConfig['config']['renderType'] === 'selectTree';
200 }
201 }