TYPO3 CMS  TYPO3_8-7
DatabaseTreeDataProvider.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 
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 
104  public function setLabelField($labelField)
105  {
106  $this->labelField = $labelField;
107  }
108 
114  public function getLabelField()
115  {
116  return $this->labelField;
117  }
118 
124  public function setTableName($tableName)
125  {
126  $this->tableName = $tableName;
127  }
128 
134  public function getTableName()
135  {
136  return $this->tableName;
137  }
138 
144  public function setLookupField($lookupField)
145  {
146  $this->lookupField = $lookupField;
147  }
148 
154  public function getLookupField()
155  {
156  return $this->lookupField;
157  }
158 
164  public function setLookupMode($lookupMode)
165  {
166  $this->lookupMode = $lookupMode;
167  }
168 
174  public function getLookupMode()
175  {
176  return $this->lookupMode;
177  }
178 
185  public function getNodes(\TYPO3\CMS\Backend\Tree\TreeNode $node)
186  {
187  }
188 
194  public function getRoot()
195  {
196  return $this->buildRepresentationForNode($this->treeData);
197  }
198 
204  public function setRootUid($rootUid)
205  {
206  $this->rootUid = $rootUid;
207  }
208 
214  public function getRootUid()
215  {
216  return $this->rootUid;
217  }
218 
224  public function setTableWhere($tableWhere)
225  {
226  $this->tableWhere = $tableWhere;
227  }
228 
234  public function getTableWhere()
235  {
236  return $this->tableWhere;
237  }
238 
247  protected function buildRepresentationForNode(\TYPO3\CMS\Backend\Tree\TreeNode $basicNode, DatabaseTreeNode $parent = null, $level = 0)
248  {
250  $node = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Tree\TableConfiguration\DatabaseTreeNode::class);
251  $row = [];
252  if ($basicNode->getId() == 0) {
253  $node->setSelected(false);
254  $node->setExpanded(true);
255  $node->setLabel($GLOBALS['LANG']->sL($GLOBALS['TCA'][$this->tableName]['ctrl']['title']));
256  } else {
257  $row = BackendUtility::getRecordWSOL($this->tableName, $basicNode->getId(), '*', '', false);
258  $node->setLabel(BackendUtility::getRecordTitle($this->tableName, $row) ?: $basicNode->getId());
259  $node->setSelected(GeneralUtility::inList($this->getSelectedList(), $basicNode->getId()));
260  $node->setExpanded($this->isExpanded($basicNode));
261  }
262  $node->setId($basicNode->getId());
263  $node->setSelectable(!GeneralUtility::inList($this->getNonSelectableLevelList(), $level) && !in_array($basicNode->getId(), $this->getItemUnselectableList()));
264  $node->setSortValue($this->nodeSortValues[$basicNode->getId()]);
265  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
266  $node->setIcon($iconFactory->getIconForRecord($this->tableName, $row, Icon::SIZE_SMALL));
267  $node->setParentNode($parent);
268  if ($basicNode->hasChildNodes()) {
269  $node->setHasChildren(true);
271  $childNodes = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\SortedTreeNodeCollection::class);
272  $tempNodes = [];
273  foreach ($basicNode->getChildNodes() as $child) {
274  $tempNodes[] = $this->buildRepresentationForNode($child, $node, $level + 1);
275  }
276  $childNodes->exchangeArray($tempNodes);
277  $childNodes->asort();
278  $node->setChildNodes($childNodes);
279  }
280  return $node;
281  }
282 
286  public function initializeTreeData()
287  {
288  parent::initializeTreeData();
289  $this->nodeSortValues = array_flip($this->itemWhiteList);
290  $this->columnConfiguration = $GLOBALS['TCA'][$this->getTableName()]['columns'][$this->getLookupField()]['config'];
291  if (isset($this->columnConfiguration['foreign_table']) && $this->columnConfiguration['foreign_table'] != $this->getTableName()) {
292  throw new \InvalidArgumentException('TCA Tree configuration is invalid: tree for different node-Tables is not implemented yet', 1290944650);
293  }
294  $this->treeData = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\TreeNode::class);
295  $this->loadTreeData();
297  }
298 
302  protected function loadTreeData()
303  {
304  $this->treeData->setId($this->getRootUid());
305  $this->treeData->setParentNode(null);
306  if ($this->levelMaximum >= 1) {
307  $childNodes = $this->getChildrenOf($this->treeData, 1);
308  if ($childNodes !== null) {
309  $this->treeData->setChildNodes($childNodes);
310  }
311  }
312  }
313 
321  protected function getChildrenOf(\TYPO3\CMS\Backend\Tree\TreeNode $node, $level)
322  {
323  $nodeData = null;
324  if ($node->getId() !== 0) {
325  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
326  ->getQueryBuilderForTable($this->getTableName());
327  $queryBuilder->getRestrictions()->removeAll();
328  $nodeData = $queryBuilder->select('*')
329  ->from($this->getTableName())
330  ->where(
331  $queryBuilder->expr()->eq(
332  'uid',
333  $queryBuilder->createNamedParameter($node->getId(), \PDO::PARAM_INT)
334  )
335  )
336  ->setMaxResults(1)
337  ->execute()
338  ->fetch();
339  }
340  if (empty($nodeData)) {
341  $nodeData = [
342  'uid' => 0,
343  $this->getLookupField() => ''
344  ];
345  }
346  $storage = null;
347  $children = $this->getRelatedRecords($nodeData);
348  if (!empty($children)) {
350  $storage = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\TreeNodeCollection::class);
351  foreach ($children as $child) {
352  $node = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\TreeNode::class);
353  $node->setId($child);
354  if ($level < $this->levelMaximum) {
355  $children = $this->getChildrenOf($node, $level + 1);
356  if ($children !== null) {
357  $node->setChildNodes($children);
358  }
359  }
360  $storage->append($node);
361  }
362  }
363  return $storage;
364  }
365 
372  protected function getRelatedRecords(array $row)
373  {
374  if ($this->getLookupMode() == self::MODE_PARENT) {
375  $children = $this->getChildrenUidsFromParentRelation($row);
376  } else {
377  $children = $this->getChildrenUidsFromChildrenRelation($row);
378  }
379  $allowedArray = [];
380  foreach ($children as $child) {
381  if (!in_array($child, $this->idCache) && in_array($child, $this->itemWhiteList)) {
382  $allowedArray[] = $child;
383  }
384  }
385  $this->idCache = array_merge($this->idCache, $allowedArray);
386  return $allowedArray;
387  }
388 
395  protected function getChildrenUidsFromParentRelation(array $row)
396  {
397  $uid = $row['uid'];
398  switch ((string)$this->columnConfiguration['type']) {
399  case 'inline':
400 
401  case 'select':
402  if ($this->columnConfiguration['MM']) {
404  $dbGroup = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\RelationHandler::class);
405  // Dummy field for setting "look from other site"
406  $this->columnConfiguration['MM_oppositeField'] = 'children';
407  $dbGroup->start($row[$this->getLookupField()], $this->getTableName(), $this->columnConfiguration['MM'], $uid, $this->getTableName(), $this->columnConfiguration);
408  $relatedUids = $dbGroup->tableArray[$this->getTableName()];
409  } elseif ($this->columnConfiguration['foreign_field']) {
410  $relatedUids = $this->listFieldQuery($this->columnConfiguration['foreign_field'], $uid);
411  } else {
412  $relatedUids = $this->listFieldQuery($this->getLookupField(), $uid);
413  }
414  break;
415  default:
416  $relatedUids = $this->listFieldQuery($this->getLookupField(), $uid);
417  }
418  return $relatedUids;
419  }
420 
427  protected function getChildrenUidsFromChildrenRelation(array $row)
428  {
429  $relatedUids = [];
430  $uid = $row['uid'];
431  $value = $row[$this->getLookupField()];
432  switch ((string)$this->columnConfiguration['type']) {
433  case 'inline':
434  // Intentional fall-through
435  case 'select':
436  if ($this->columnConfiguration['MM']) {
437  $dbGroup = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Database\RelationHandler::class);
438  $dbGroup->start(
439  $value,
440  $this->getTableName(),
441  $this->columnConfiguration['MM'],
442  $uid,
443  $this->getTableName(),
444  $this->columnConfiguration
445  );
446  $relatedUids = $dbGroup->tableArray[$this->getTableName()];
447  } elseif ($this->columnConfiguration['foreign_field']) {
448  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
449  ->getQueryBuilderForTable($this->getTableName());
450  $queryBuilder->getRestrictions()->removeAll();
451  $records = $queryBuilder->select('uid')
452  ->from($this->getTableName())
453  ->where(
454  $queryBuilder->expr()->eq(
455  $this->columnConfiguration['foreign_field'],
456  $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
457  )
458  )
459  ->execute()
460  ->fetchAll();
461 
462  if (!empty($records)) {
463  $relatedUids = array_column($records, 'uid');
464  }
465  } else {
466  $relatedUids = GeneralUtility::intExplode(',', $value, true);
467  }
468  break;
469  default:
470  $relatedUids = GeneralUtility::intExplode(',', $value, true);
471  }
472  return $relatedUids;
473  }
474 
482  protected function listFieldQuery($fieldName, $queryId)
483  {
484  $queryId = (int)$queryId;
485  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
486  ->getQueryBuilderForTable($this->getTableName());
487  $queryBuilder->getRestrictions()->removeAll();
488 
489  $queryBuilder->select('uid')
490  ->from($this->getTableName())
491  ->where($queryBuilder->expr()->inSet($fieldName, $queryBuilder->quote($queryId)));
492 
493  if ($queryId === 0) {
494  $queryBuilder->orWhere(
495  $queryBuilder->expr()->comparison(
496  'CAST(' . $queryBuilder->quoteIdentifier($fieldName) . ' AS CHAR)',
498  $queryBuilder->quote('')
499  )
500  );
501  }
502 
503  $records = $queryBuilder->execute()->fetchAll();
504  $uidArray = is_array($records) ? array_column($records, 'uid') : [];
505 
506  return $uidArray;
507  }
508 
512  protected function emitPostProcessTreeDataSignal()
513  {
514  $this->getSignalSlotDispatcher()->dispatch(
515  self::class,
516  self::SIGNAL_PostProcessTreeData,
517  [$this, $this->treeData]
518  );
519  }
520 
526  protected function getSignalSlotDispatcher()
527  {
528  if (!isset($this->signalSlotDispatcher)) {
529  $this->signalSlotDispatcher = $this->getObjectManager()->get(Dispatcher::class);
530  }
532  }
533 
539  protected function getObjectManager()
540  {
541  return GeneralUtility::makeInstance(ObjectManager::class);
542  }
543 }
static getRecordWSOL( $table, $uid, $fields=' *', $where='', $useDeleteClause=true, $unsetMovePointers=false)
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
static makeInstance($className,... $constructorArguments)
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']