[CLEANUP] Remove usage of self::class
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Tree / TableConfiguration / DatabaseTreeDataProvider.php
1 <?php
2 namespace TYPO3\CMS\Core\Tree\TableConfiguration;
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\Core\Utility\GeneralUtility;
19
20 /**
21 * TCA tree data provider
22 *
23 * @author Steffen Ritter <info@steffen-ritter.net>
24 */
25 class DatabaseTreeDataProvider extends AbstractTableConfigurationTreeDataProvider {
26
27 const SIGNAL_PostProcessTreeData = 'PostProcessTreeData';
28 const MODE_CHILDREN = 1;
29 const MODE_PARENT = 2;
30
31 /**
32 * @var string
33 */
34 protected $tableName = '';
35
36 /**
37 * @var string
38 */
39 protected $treeId = '';
40
41 /**
42 * @var string
43 */
44 protected $labelField = '';
45
46 /**
47 * @var string
48 */
49 protected $tableWhere = '';
50
51 /**
52 * @var int
53 */
54 protected $lookupMode = self::MODE_CHILDREN;
55
56 /**
57 * @var string
58 */
59 protected $lookupField = '';
60
61 /**
62 * @var int
63 */
64 protected $rootUid = 0;
65
66 /**
67 * @var array
68 */
69 protected $idCache = array();
70
71 /**
72 * Stores TCA-Configuration of the LookUpField in tableName
73 *
74 * @var array
75 */
76 protected $columnConfiguration;
77
78 /**
79 * node sort values (the orderings from foreign_Table_where evaluation)
80 *
81 * @var array
82 */
83 protected $nodeSortValues = array();
84
85 /**
86 * @var array TCEforms compiled TSConfig array
87 */
88 protected $generatedTSConfig = array();
89
90 /**
91 * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
92 */
93 protected $signalSlotDispatcher;
94
95 /**
96 * Sets the label field
97 *
98 * @param string $labelField
99 * @return void
100 */
101 public function setLabelField($labelField) {
102 $this->labelField = $labelField;
103 }
104
105 /**
106 * Gets the label field
107 *
108 * @return string
109 */
110 public function getLabelField() {
111 return $this->labelField;
112 }
113
114 /**
115 * Sets the table name
116 *
117 * @param string $tableName
118 * @return void
119 */
120 public function setTableName($tableName) {
121 $this->tableName = $tableName;
122 }
123
124 /**
125 * Gets the table name
126 *
127 * @return string
128 */
129 public function getTableName() {
130 return $this->tableName;
131 }
132
133 /**
134 * Sets the lookup field
135 *
136 * @param string $lookupField
137 * @return void
138 */
139 public function setLookupField($lookupField) {
140 $this->lookupField = $lookupField;
141 }
142
143 /**
144 * Gets the lookup field
145 *
146 * @return string
147 */
148 public function getLookupField() {
149 return $this->lookupField;
150 }
151
152 /**
153 * Sets the lookup mode
154 *
155 * @param int $lookupMode
156 * @return void
157 */
158 public function setLookupMode($lookupMode) {
159 $this->lookupMode = $lookupMode;
160 }
161
162 /**
163 * Gets the lookup mode
164 *
165 * @return int
166 */
167 public function getLookupMode() {
168 return $this->lookupMode;
169 }
170
171 /**
172 * Gets the nodes
173 *
174 * @param \TYPO3\CMS\Backend\Tree\TreeNode $node
175 * @return \TYPO3\CMS\Backend\Tree\TreeNodeCollection
176 */
177 public function getNodes(\TYPO3\CMS\Backend\Tree\TreeNode $node) {
178
179 }
180
181 /**
182 * Gets the root node
183 *
184 * @return \TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeNode
185 */
186 public function getRoot() {
187 return $this->buildRepresentationForNode($this->treeData);
188 }
189
190 /**
191 * Sets the root uid
192 *
193 * @param int $rootUid
194 * @return void
195 */
196 public function setRootUid($rootUid) {
197 $this->rootUid = $rootUid;
198 }
199
200 /**
201 * Gets the root uid
202 *
203 * @return int
204 */
205 public function getRootUid() {
206 return $this->rootUid;
207 }
208
209 /**
210 * Sets the tableWhere clause
211 *
212 * @param string $tableWhere
213 * @return void
214 */
215 public function setTableWhere($tableWhere) {
216 $this->tableWhere = $tableWhere;
217 }
218
219 /**
220 * Gets the tableWhere clause
221 *
222 * @return string
223 */
224 public function getTableWhere() {
225 return $this->tableWhere;
226 }
227
228 /**
229 * Builds a complete node including childs
230 *
231 * @param \TYPO3\CMS\Backend\Tree\TreeNode $basicNode
232 * @param NULL|\TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeNode $parent
233 * @param int $level
234 * @return \TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeNode Node object
235 */
236 protected function buildRepresentationForNode(\TYPO3\CMS\Backend\Tree\TreeNode $basicNode, DatabaseTreeNode $parent = NULL, $level = 0) {
237 /** @var $node \TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeNode */
238 $node = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeNode::class);
239 $row = array();
240 if ($basicNode->getId() == 0) {
241 $node->setSelected(FALSE);
242 $node->setExpanded(TRUE);
243 $node->setLabel($GLOBALS['LANG']->sL($GLOBALS['TCA'][$this->tableName]['ctrl']['title']));
244 } else {
245 $row = BackendUtility::getRecordWSOL($this->tableName, $basicNode->getId(), '*', '', FALSE);
246 $node->setLabel(BackendUtility::getRecordTitle($this->tableName, $row) ?: $basicNode->getId());
247 $node->setSelected(GeneralUtility::inList($this->getSelectedList(), $basicNode->getId()));
248 $node->setExpanded($this->isExpanded($basicNode));
249 }
250 $node->setId($basicNode->getId());
251 $node->setSelectable(!GeneralUtility::inList($this->getNonSelectableLevelList(), $level) && !in_array($basicNode->getId(), $this->getItemUnselectableList()));
252 $node->setSortValue($this->nodeSortValues[$basicNode->getId()]);
253 $node->setIcon(\TYPO3\CMS\Backend\Utility\IconUtility::mapRecordTypeToSpriteIconClass($this->tableName, $row));
254 $node->setParentNode($parent);
255 if ($basicNode->hasChildNodes()) {
256 $node->setHasChildren(TRUE);
257 /** @var $childNodes \TYPO3\CMS\Backend\Tree\SortedTreeNodeCollection */
258 $childNodes = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\SortedTreeNodeCollection::class);
259 foreach ($basicNode->getChildNodes() as $child) {
260 $childNodes->append($this->buildRepresentationForNode($child, $node, $level + 1));
261 }
262 $node->setChildNodes($childNodes);
263 }
264 return $node;
265 }
266
267 /**
268 * Init the tree data
269 *
270 * @return void
271 */
272 public function initializeTreeData() {
273 parent::initializeTreeData();
274 $this->nodeSortValues = array_flip($this->itemWhiteList);
275 $this->columnConfiguration = $GLOBALS['TCA'][$this->getTableName()]['columns'][$this->getLookupField()]['config'];
276 if (isset($this->columnConfiguration['foreign_table']) && $this->columnConfiguration['foreign_table'] != $this->getTableName()) {
277 throw new \InvalidArgumentException('TCA Tree configuration is invalid: tree for different node-Tables is not implemented yet', 1290944650);
278 }
279 $this->treeData = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\TreeNode::class);
280 $this->loadTreeData();
281 $this->emitPostProcessTreeDataSignal();
282 }
283
284 /**
285 * Loads the tree data (all possible children)
286 *
287 * @return void
288 */
289 protected function loadTreeData() {
290 $this->treeData->setId($this->getRootUid());
291 $this->treeData->setParentNode(NULL);
292 if ($this->levelMaximum >= 1) {
293 $childNodes = $this->getChildrenOf($this->treeData, 1);
294 if ($childNodes !== NULL) {
295 $this->treeData->setChildNodes($childNodes);
296 }
297 }
298 }
299
300 /**
301 * Gets node children
302 *
303 * @param \TYPO3\CMS\Backend\Tree\TreeNode $node
304 * @param int $level
305 * @return NULL|\TYPO3\CMS\Backend\Tree\TreeNodeCollection
306 */
307 protected function getChildrenOf(\TYPO3\CMS\Backend\Tree\TreeNode $node, $level) {
308 $nodeData = NULL;
309 if ($node->getId() !== 0) {
310 $nodeData = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('*', $this->tableName, 'uid=' . $node->getId());
311 }
312 if ($nodeData == NULL) {
313 $nodeData = array(
314 'uid' => 0,
315 $this->getLookupField() => ''
316 );
317 }
318 $storage = NULL;
319 $children = $this->getRelatedRecords($nodeData);
320 if (count($children)) {
321 /** @var $storage \TYPO3\CMS\Backend\Tree\TreeNodeCollection */
322 $storage = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\TreeNodeCollection::class);
323 foreach ($children as $child) {
324 $node = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\TreeNode::class);
325 $node->setId($child);
326 if ($level < $this->levelMaximum) {
327 $children = $this->getChildrenOf($node, $level + 1);
328 if ($children !== NULL) {
329 $node->setChildNodes($children);
330 }
331 }
332 $storage->append($node);
333 }
334 }
335 return $storage;
336 }
337
338 /**
339 * Gets related records depending on TCA configuration
340 *
341 * @param array $row
342 * @return array
343 */
344 protected function getRelatedRecords(array $row) {
345 if ($this->getLookupMode() == DatabaseTreeDataProvider::MODE_PARENT) {
346 $children = $this->getChildrenUidsFromParentRelation($row);
347 } else {
348 $children = $this->getChildrenUidsFromChildrenRelation($row);
349 }
350 $allowedArray = array();
351 foreach ($children as $child) {
352 if (!in_array($child, $this->idCache) && in_array($child, $this->itemWhiteList)) {
353 $allowedArray[] = $child;
354 }
355 }
356 $this->idCache = array_merge($this->idCache, $allowedArray);
357 return $allowedArray;
358 }
359
360 /**
361 * Gets related records depending on TCA configuration
362 *
363 * @param array $row
364 * @return array
365 */
366 protected function getChildrenUidsFromParentRelation(array $row) {
367 $uid = $row['uid'];
368 switch ((string)$this->columnConfiguration['type']) {
369 case 'inline':
370
371 case 'select':
372 if ($this->columnConfiguration['MM']) {
373 /** @var $dbGroup \TYPO3\CMS\Core\Database\RelationHandler */
374 $dbGroup = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\RelationHandler::class);
375 // Dummy field for setting "look from other site"
376 $this->columnConfiguration['MM_oppositeField'] = 'children';
377 $dbGroup->start($row[$this->getLookupField()], $this->getTableName(), $this->columnConfiguration['MM'], $uid, $this->getTableName(), $this->columnConfiguration);
378 $relatedUids = $dbGroup->tableArray[$this->getTableName()];
379 } elseif ($this->columnConfiguration['foreign_field']) {
380 $relatedUids = $this->listFieldQuery($this->columnConfiguration['foreign_field'], $uid);
381 } else {
382 $relatedUids = $this->listFieldQuery($this->getLookupField(), $uid);
383 }
384 break;
385 default:
386 $relatedUids = $this->listFieldQuery($this->getLookupField(), $uid);
387 }
388 return $relatedUids;
389 }
390
391 /**
392 * Gets related children records depending on TCA configuration
393 *
394 * @param array $row
395 * @return array
396 */
397 protected function getChildrenUidsFromChildrenRelation(array $row) {
398 $relatedUids = array();
399 $uid = $row['uid'];
400 $value = $row[$this->getLookupField()];
401 switch ((string)$this->columnConfiguration['type']) {
402 case 'inline':
403
404 case 'select':
405 if ($this->columnConfiguration['MM']) {
406 /** @var $dbGroup \TYPO3\CMS\Core\Database\RelationHandler */
407 $dbGroup = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\RelationHandler::class);
408 $dbGroup->start($value, $this->getTableName(), $this->columnConfiguration['MM'], $uid, $this->getTableName(), $this->columnConfiguration);
409 $relatedUids = $dbGroup->tableArray[$this->getTableName()];
410 } elseif ($this->columnConfiguration['foreign_field']) {
411 $records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid', $this->getTableName(), $this->columnConfiguration['foreign_field'] . '=' . (int)$uid);
412 foreach ($records as $record) {
413 $relatedUids[] = $record['uid'];
414 }
415 } else {
416 $relatedUids = GeneralUtility::intExplode(',', $value, TRUE);
417 }
418 break;
419 default:
420 $relatedUids = GeneralUtility::intExplode(',', $value, TRUE);
421 }
422 return $relatedUids;
423 }
424
425 /**
426 * Queries the table for an field which might contain a list.
427 *
428 * @param string $fieldName the name of the field to be queried
429 * @param int $queryId the uid to search for
430 * @return int[] all uids found
431 */
432 protected function listFieldQuery($fieldName, $queryId) {
433 $records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows('uid', $this->getTableName(), $GLOBALS['TYPO3_DB']->listQuery($fieldName, (int)$queryId, $this->getTableName()) . ((int)$queryId == 0 ? ' OR ' . $fieldName . ' = \'\'' : ''));
434 $uidArray = array();
435 foreach ($records as $record) {
436 $uidArray[] = $record['uid'];
437 }
438 return $uidArray;
439 }
440
441 /**
442 * Emits the post processing tree data signal.
443 *
444 * @return void
445 */
446 protected function emitPostProcessTreeDataSignal() {
447 $this->getSignalSlotDispatcher()->dispatch(\TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeDataProvider::class,
448 self::SIGNAL_PostProcessTreeData,
449 array($this, $this->treeData)
450 );
451 $this->emitDeprecatedPostProcessTreeDataSignal();
452 }
453
454 /**
455 * A wrong signal name was introduced with https://review.typo3.org/#/c/34855/
456 * This function handles the old signal name and logs a deprecation warning.
457 *
458 * @return void
459 * @deprecated since TYPO3 CMS 7, will be removed in TYPO3 CMS 8
460 */
461 protected function emitDeprecatedPostProcessTreeDataSignal() {
462 $deprecatedSlots = $this->getSignalSlotDispatcher()->getSlots(
463 'TYPO3\\CMS\\Core\\Tree\\TableConfiguration\\TableConfiguration\\DatabaseTreeDataProvider',
464 self::SIGNAL_PostProcessTreeData
465 );
466 if (!empty($deprecatedSlots)) {
467 foreach ($deprecatedSlots as $slotInformation) {
468 $slotClassNameOrObject = $slotInformation['object'] ? get_class($slotInformation['object']) : $slotInformation['class'];
469 GeneralUtility::deprecationLog(
470 'Signal "TYPO3\\CMS\\Core\\Tree\\TableConfiguration\\TableConfiguration\\DatabaseTreeDataProvider" ' .
471 'is deprecated but used by "' . $slotClassNameOrObject . '". ' .
472 'Please update signal name to "' . __CLASS__ . '".'
473 );
474 }
475 $this->getSignalSlotDispatcher()->dispatch(
476 'TYPO3\\CMS\\Core\\Tree\\TableConfiguration\\TableConfiguration\\DatabaseTreeDataProvider',
477 self::SIGNAL_PostProcessTreeData,
478 array($this, $this->treeData)
479 );
480 }
481 }
482
483 /**
484 * Get the SignalSlot dispatcher
485 *
486 * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
487 */
488 protected function getSignalSlotDispatcher() {
489 if (!isset($this->signalSlotDispatcher)) {
490 $this->signalSlotDispatcher = $this->getObjectManager()->get(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
491 }
492 return $this->signalSlotDispatcher;
493 }
494
495 /**
496 * Get the ObjectManager
497 *
498 * @return \TYPO3\CMS\Extbase\Object\ObjectManager
499 */
500 protected function getObjectManager() {
501 return GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class);
502 }
503
504 }