TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
DatabaseTreeDataProvider.php
Go to the documentation of this file.
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 
25 
30 {
31  const SIGNAL_PostProcessTreeData = 'PostProcessTreeData';
32  const MODE_CHILDREN = 1;
33  const MODE_PARENT = 2;
34 
38  protected $tableName = '';
39 
43  protected $treeId = '';
44 
48  protected $labelField = '';
49 
53  protected $tableWhere = '';
54 
58  protected $lookupMode = self::MODE_CHILDREN;
59 
63  protected $lookupField = '';
64 
68  protected $rootUid = 0;
69 
73  protected $idCache = [];
74 
81 
87  protected $nodeSortValues = [];
88 
92  protected $generatedTSConfig = [];
93 
98 
105  public function setLabelField($labelField)
106  {
107  $this->labelField = $labelField;
108  }
109 
115  public function getLabelField()
116  {
117  return $this->labelField;
118  }
119 
126  public function setTableName($tableName)
127  {
128  $this->tableName = $tableName;
129  }
130 
136  public function getTableName()
137  {
138  return $this->tableName;
139  }
140 
147  public function setLookupField($lookupField)
148  {
149  $this->lookupField = $lookupField;
150  }
151 
157  public function getLookupField()
158  {
159  return $this->lookupField;
160  }
161 
168  public function setLookupMode($lookupMode)
169  {
170  $this->lookupMode = $lookupMode;
171  }
172 
178  public function getLookupMode()
179  {
180  return $this->lookupMode;
181  }
182 
189  public function getNodes(\TYPO3\CMS\Backend\Tree\TreeNode $node)
190  {
191  }
192 
198  public function getRoot()
199  {
200  return $this->buildRepresentationForNode($this->treeData);
201  }
202 
209  public function setRootUid($rootUid)
210  {
211  $this->rootUid = $rootUid;
212  }
213 
219  public function getRootUid()
220  {
221  return $this->rootUid;
222  }
223 
230  public function setTableWhere($tableWhere)
231  {
232  $this->tableWhere = $tableWhere;
233  }
234 
240  public function getTableWhere()
241  {
242  return $this->tableWhere;
243  }
244 
253  protected function buildRepresentationForNode(\TYPO3\CMS\Backend\Tree\TreeNode $basicNode, DatabaseTreeNode $parent = null, $level = 0)
254  {
256  $node = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeNode::class);
257  $row = [];
258  if ($basicNode->getId() == 0) {
259  $node->setSelected(false);
260  $node->setExpanded(true);
261  $node->setLabel($GLOBALS['LANG']->sL($GLOBALS['TCA'][$this->tableName]['ctrl']['title']));
262  } else {
263  $row = BackendUtility::getRecordWSOL($this->tableName, $basicNode->getId(), '*', '', false);
264  $node->setLabel(BackendUtility::getRecordTitle($this->tableName, $row) ?: $basicNode->getId());
265  $node->setSelected(GeneralUtility::inList($this->getSelectedList(), $basicNode->getId()));
266  $node->setExpanded($this->isExpanded($basicNode));
267  }
268  $node->setId($basicNode->getId());
269  $node->setSelectable(!GeneralUtility::inList($this->getNonSelectableLevelList(), $level) && !in_array($basicNode->getId(), $this->getItemUnselectableList()));
270  $node->setSortValue($this->nodeSortValues[$basicNode->getId()]);
271  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
272  $node->setIcon($iconFactory->getIconForRecord($this->tableName, $row, Icon::SIZE_SMALL));
273  $node->setParentNode($parent);
274  if ($basicNode->hasChildNodes()) {
275  $node->setHasChildren(true);
277  $childNodes = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\SortedTreeNodeCollection::class);
278  foreach ($basicNode->getChildNodes() as $child) {
279  $childNodes->append($this->buildRepresentationForNode($child, $node, $level + 1));
280  }
281  $node->setChildNodes($childNodes);
282  }
283  return $node;
284  }
285 
291  public function initializeTreeData()
292  {
293  parent::initializeTreeData();
294  $this->nodeSortValues = array_flip($this->itemWhiteList);
295  $this->columnConfiguration = $GLOBALS['TCA'][$this->getTableName()]['columns'][$this->getLookupField()]['config'];
296  if (isset($this->columnConfiguration['foreign_table']) && $this->columnConfiguration['foreign_table'] != $this->getTableName()) {
297  throw new \InvalidArgumentException('TCA Tree configuration is invalid: tree for different node-Tables is not implemented yet', 1290944650);
298  }
299  $this->treeData = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\TreeNode::class);
300  $this->loadTreeData();
302  }
303 
309  protected function loadTreeData()
310  {
311  $this->treeData->setId($this->getRootUid());
312  $this->treeData->setParentNode(null);
313  if ($this->levelMaximum >= 1) {
314  $childNodes = $this->getChildrenOf($this->treeData, 1);
315  if ($childNodes !== null) {
316  $this->treeData->setChildNodes($childNodes);
317  }
318  }
319  }
320 
328  protected function getChildrenOf(\TYPO3\CMS\Backend\Tree\TreeNode $node, $level)
329  {
330  $nodeData = null;
331  if ($node->getId() !== 0) {
332  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
333  ->getQueryBuilderForTable($this->getTableName());
334  $queryBuilder->getRestrictions()->removeAll();
335  $nodeData = $queryBuilder->select('*')
336  ->from($this->getTableName())
337  ->where(
338  $queryBuilder->expr()->eq(
339  'uid',
340  $queryBuilder->createNamedParameter($node->getId(), \PDO::PARAM_INT)
341  )
342  )
343  ->setMaxResults(1)
344  ->execute()
345  ->fetch();
346  }
347  if (empty($nodeData)) {
348  $nodeData = [
349  'uid' => 0,
350  $this->getLookupField() => ''
351  ];
352  }
353  $storage = null;
354  $children = $this->getRelatedRecords($nodeData);
355  if (!empty($children)) {
357  $storage = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\TreeNodeCollection::class);
358  foreach ($children as $child) {
359  $node = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\TreeNode::class);
360  $node->setId($child);
361  if ($level < $this->levelMaximum) {
362  $children = $this->getChildrenOf($node, $level + 1);
363  if ($children !== null) {
364  $node->setChildNodes($children);
365  }
366  }
367  $storage->append($node);
368  }
369  }
370  return $storage;
371  }
372 
379  protected function getRelatedRecords(array $row)
380  {
381  if ($this->getLookupMode() == self::MODE_PARENT) {
382  $children = $this->getChildrenUidsFromParentRelation($row);
383  } else {
384  $children = $this->getChildrenUidsFromChildrenRelation($row);
385  }
386  $allowedArray = [];
387  foreach ($children as $child) {
388  if (!in_array($child, $this->idCache) && in_array($child, $this->itemWhiteList)) {
389  $allowedArray[] = $child;
390  }
391  }
392  $this->idCache = array_merge($this->idCache, $allowedArray);
393  return $allowedArray;
394  }
395 
402  protected function getChildrenUidsFromParentRelation(array $row)
403  {
404  $uid = $row['uid'];
405  switch ((string)$this->columnConfiguration['type']) {
406  case 'inline':
407 
408  case 'select':
409  if ($this->columnConfiguration['MM']) {
411  $dbGroup = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\RelationHandler::class);
412  // Dummy field for setting "look from other site"
413  $this->columnConfiguration['MM_oppositeField'] = 'children';
414  $dbGroup->start($row[$this->getLookupField()], $this->getTableName(), $this->columnConfiguration['MM'], $uid, $this->getTableName(), $this->columnConfiguration);
415  $relatedUids = $dbGroup->tableArray[$this->getTableName()];
416  } elseif ($this->columnConfiguration['foreign_field']) {
417  $relatedUids = $this->listFieldQuery($this->columnConfiguration['foreign_field'], $uid);
418  } else {
419  $relatedUids = $this->listFieldQuery($this->getLookupField(), $uid);
420  }
421  break;
422  default:
423  $relatedUids = $this->listFieldQuery($this->getLookupField(), $uid);
424  }
425  return $relatedUids;
426  }
427 
434  protected function getChildrenUidsFromChildrenRelation(array $row)
435  {
436  $relatedUids = [];
437  $uid = $row['uid'];
438  $value = $row[$this->getLookupField()];
439  switch ((string)$this->columnConfiguration['type']) {
440  case 'inline':
441  // Intentional fall-through
442  case 'select':
443  if ($this->columnConfiguration['MM']) {
444  $dbGroup = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\RelationHandler::class);
445  $dbGroup->start(
446  $value,
447  $this->getTableName(),
448  $this->columnConfiguration['MM'],
449  $uid,
450  $this->getTableName(),
451  $this->columnConfiguration
452  );
453  $relatedUids = $dbGroup->tableArray[$this->getTableName()];
454  } elseif ($this->columnConfiguration['foreign_field']) {
455  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
456  ->getQueryBuilderForTable($this->getTableName());
457  $queryBuilder->getRestrictions()->removeAll();
458  $records = $queryBuilder->select('uid')
459  ->from($this->getTableName())
460  ->where(
461  $queryBuilder->expr()->eq(
462  $this->columnConfiguration['foreign_field'],
463  $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
464  )
465  )
466  ->execute()
467  ->fetchAll();
468 
469  if (!empty($records)) {
470  $relatedUids = array_column($records, 'uid');
471  }
472  } else {
473  $relatedUids = GeneralUtility::intExplode(',', $value, true);
474  }
475  break;
476  default:
477  $relatedUids = GeneralUtility::intExplode(',', $value, true);
478  }
479  return $relatedUids;
480  }
481 
489  protected function listFieldQuery($fieldName, $queryId)
490  {
491  $queryId = (int)$queryId;
492  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
493  ->getQueryBuilderForTable($this->getTableName());
494  $queryBuilder->getRestrictions()->removeAll();
495 
496  $queryBuilder->select('uid')
497  ->from($this->getTableName())
498  ->where($queryBuilder->expr()->inSet($fieldName, $queryId));
499 
500  if ($queryId === 0) {
501  $queryBuilder->orWhere(
502  $queryBuilder->expr()->comparison(
503  'CAST(' . $queryBuilder->quoteIdentifier($fieldName) . ' AS CHAR)',
505  $queryBuilder->quote('')
506  )
507  );
508  }
509 
510  $records = $queryBuilder->execute()->fetchAll();
511  $uidArray = is_array($records) ? array_column($records, 'uid') : [];
512 
513  return $uidArray;
514  }
515 
521  protected function emitPostProcessTreeDataSignal()
522  {
523  $this->getSignalSlotDispatcher()->dispatch(
524  self::class,
525  self::SIGNAL_PostProcessTreeData,
526  [$this, $this->treeData]
527  );
528  }
529 
535  protected function getSignalSlotDispatcher()
536  {
537  if (!isset($this->signalSlotDispatcher)) {
538  $this->signalSlotDispatcher = $this->getObjectManager()->get(Dispatcher::class);
539  }
541  }
542 
548  protected function getObjectManager()
549  {
550  return GeneralUtility::makeInstance(ObjectManager::class);
551  }
552 }
static getRecordWSOL($table, $uid, $fields= '*', $where= '', $useDeleteClause=true, $unsetMovePointers=false)
static getRecordTitle($table, $row, $prep=false, $forceResult=true)
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static makeInstance($className,...$constructorArguments)
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)