‪TYPO3CMS  ‪main
AbstractTreeView.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use TYPO3\CMS\Backend\Utility\BackendUtility;
29 use TYPO3\CMS\Core\Imaging\IconSize;
32 
38 abstract class ‪AbstractTreeView
39 {
44  protected string ‪$table = 'pages';
45 
49  protected string ‪$parentField = 'pid';
50 
56  protected string ‪$clause = '';
57 
63  public string ‪$orderByFields = '';
64 
71  protected array ‪$fieldArray = [
72  'uid',
73  'pid',
74  'title',
75  'is_siteroot',
76  'doktype',
77  'nav_title',
78  'mount_pid',
79  'php_tree_stop',
80  't3ver_state',
81  'hidden',
82  'starttime',
83  'endtime',
84  'fe_group',
85  'module',
86  'extendToSubpages',
87  'nav_hide',
88  't3ver_wsid',
89  ];
90 
96  protected string ‪$defaultList = 'uid,pid,tstamp,sorting,deleted,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,crdate';
97 
103  public ‪$makeHTML = 1;
104 
105  // *********
106  // Internal
107  // *********
108  // For record trees:
109  // one-dim array of the uid's selected.
113  public ‪$ids = [];
114 
115  // The hierarchy of element uids
119  public ‪$ids_hierarchy = [];
120 
121  // The hierarchy of versioned element uids
125  public ‪$orig_ids_hierarchy = [];
126 
127  // Temporary, internal array
131  public ‪$buffer_idH = [];
132 
133  // For both types
134  // Tree is accumulated in this variable
138  public ‪$tree = [];
139 
143  public function ‪__construct()
144  {
145  $this->‪init();
146  }
147 
154  public function ‪init($clause = '', ‪$orderByFields = '')
155  {
156  // Setting clause
157  if (‪$clause) {
158  $this->clause = ‪$clause;
159  }
160  if (‪$orderByFields) {
161  $this->orderByFields = ‪$orderByFields;
162  }
163  }
164 
171  public function ‪addField($field, $noCheck = false)
172  {
173  if ($noCheck || is_array(‪$GLOBALS['TCA'][$this->table]['columns'][$field] ?? null) || ‪GeneralUtility::inList($this->defaultList, $field)) {
174  $this->‪fieldArray[] = $field;
175  }
176  }
177 
181  public function ‪reset()
182  {
183  $this->tree = [];
184  $this->ids = [];
185  $this->ids_hierarchy = [];
186  $this->orig_ids_hierarchy = [];
187  }
188 
189  /*******************************************
190  *
191  * rendering parts
192  *
193  *******************************************/
205  protected function ‪PMicon($row, $a, $c, $nextCount, $isOpen)
206  {
207  if ($nextCount) {
208  return $this->‪PM_ATagWrap($row['uid'], $isOpen);
209  }
210  return '';
211  }
212 
220  protected function ‪PM_ATagWrap($bMark = '', $isOpen = false)
221  {
222  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
223 
224  $anchor = $bMark ? '#' . $bMark : '';
225  $name = $bMark ? ' name="' . $bMark . '"' : '';
226  $aUrl = $anchor;
227  if ($isOpen) {
228  $class = 'treelist-control-open';
229  $icon = $iconFactory->getIcon('actions-chevron-down', IconSize::SMALL);
230  } else {
231  $class = 'treelist-control-collapsed';
232  $icon = $iconFactory->getIcon('actions-chevron-right', IconSize::SMALL);
233  }
234  return '<a class="treelist-control ' . $class . '" href="' . htmlspecialchars($aUrl) . '"' . $name . '>' . $icon->render(‪AbstractSvgIconProvider::MARKUP_IDENTIFIER_INLINE) . '</a>';
235  }
236 
237  /*******************************************
238  *
239  * tree handling
240  *
241  *******************************************/
252  public function ‪expandNext($id)
253  {
254  return false;
255  }
256 
257  /******************************
258  *
259  * Functions that might be overwritten by extended classes
260  *
261  ********************************/
262 
269  protected function ‪getIcon(array $row): string
270  {
271  $title = $this->‪getTitleAttrib($row);
272  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
273  $icon = $row['is_siteroot'] ? $iconFactory->getIcon('apps-pagetree-folder-root', IconSize::SMALL) : $iconFactory->getIconForRecord($this->table, $row, IconSize::SMALL);
274  return $icon->setTitle($title)->render();
275  }
276 
285  protected function ‪getTitleStr($row, $titleLen = 30)
286  {
287  $title = htmlspecialchars(‪GeneralUtility::fixed_lgd_cs($row['title'], (int)$titleLen));
288  return trim($title) === '' ? '<em>[' . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title')) . ']</em>' : $title;
289  }
290 
297  protected function ‪getTitleAttrib($row)
298  {
299  return htmlspecialchars($row['title']);
300  }
301 
302  /********************************
303  *
304  * tree data building
305  *
306  ********************************/
315  public function ‪getTree(‪$uid, $depth = 999, $depthData = '')
316  {
317  // Buffer for id hierarchy is reset:
318  $this->buffer_idH = [];
319  // Init vars
320  $depth = (int)$depth;
321  $HTML = '';
322  $a = 0;
323  $res = $this->‪getDataInit(‪$uid);
324  $c = $res->rowCount();
325  $crazyRecursionLimiter = 9999;
326  $idH = [];
327  // Traverse the records:
328  while ($crazyRecursionLimiter > 0 && ($row = $this->‪getDataNext($res))) {
330  if (!$this->‪getBackendUser()->isInWebMount($this->table === 'pages' ? $row : $row['pid'])) {
331  // Current record is not within web mount => skip it
332  continue;
333  }
334 
335  $a++;
336  $crazyRecursionLimiter--;
337  $newID = $row['uid'];
338  if ($newID == 0) {
339  throw new \RuntimeException('Endless recursion detected: TYPO3 has detected an error in the database. Please fix it manually (e.g. using phpMyAdmin) and change the UID of ' . $this->table . ':0 to a new value. See https://forge.typo3.org/issues/16150 to get more information about a possible cause.', 1294586383);
340  }
341  // Reserve space.
342  $this->tree[] = [];
343  end($this->tree);
344  // Get the key for this space
345  $treeKey = key($this->tree);
346  // Accumulate the id of the element in the internal arrays
347  $this->ids[] = ($idH[$row['uid']]['uid'] = $row['uid']);
348  $this->ids_hierarchy[$depth][] = $row['uid'];
349  $this->orig_ids_hierarchy[$depth][] = (isset($row['_ORIG_uid']) && !empty($row['_ORIG_uid'])) ? $row['_ORIG_uid'] : $row['uid'];
350 
351  // Make a recursive call to the next level
352  $nextLevelDepthData = $depthData . '<span class="treeline-icon treeline-icon-' . ($a === $c ? 'clear' : 'line') . '"></span>';
353  $hasSub = $this->‪expandNext($newID) && !($row['php_tree_stop'] ?? false);
354  if ($depth > 1 && $hasSub) {
355  $nextCount = $this->‪getTree($newID, $depth - 1, $nextLevelDepthData);
356  if (!empty($this->buffer_idH)) {
357  $idH[$row['uid']]['subrow'] = ‪$this->buffer_idH;
358  }
359  // Set "did expand" flag
360  $isOpen = true;
361  } else {
362  $nextCount = $this->‪getCount($newID);
363  // Clear "did expand" flag
364  $isOpen = false;
365  }
366  // Set HTML-icons, if any:
367  if ($this->makeHTML) {
368  $HTML = $this->‪PMicon($row, $a, $c, $nextCount, $isOpen);
369  }
370  // Finally, add the row/HTML content to the ->tree array in the reserved key.
371  $this->tree[$treeKey] = [
372  'row' => $row,
373  'HTML' => $HTML,
374  'icon' => $this->‪getIcon($row),
375  'invertedDepth' => $depth,
376  'depthData' => $depthData,
377  'hasSub' => $nextCount && $hasSub,
378  'isFirst' => $a === 1,
379  'isLast' => $a === $c,
380  ];
381  }
382 
383  $res->free();
384  $this->buffer_idH = $idH;
385  return $c;
386  }
387 
388  /********************************
389  *
390  * Data handling
391  * Works with records and arrays
392  *
393  ********************************/
400  protected function ‪getCount(‪$uid)
401  {
402  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->table);
403  $queryBuilder->getRestrictions()
404  ->removeAll()
405  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
406  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, $this->‪getBackendUser()->workspace));
407  $count = $queryBuilder
408  ->count('uid')
409  ->from($this->table)
410  ->where(
411  $queryBuilder->expr()->eq(
412  $this->parentField,
413  $queryBuilder->createNamedParameter(‪$uid, ‪Connection::PARAM_INT)
414  ),
416  )
417  ->executeQuery()
418  ->fetchOne();
419 
420  return (int)$count;
421  }
422 
432  protected function ‪getDataInit($parentId)
433  {
434  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->table);
435  $queryBuilder->getRestrictions()
436  ->removeAll()
437  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
438  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, $this->‪getBackendUser()->workspace));
439  $queryBuilder
440  ->select(...$this->‪fieldArray)
441  ->from($this->table)
442  ->where(
443  $queryBuilder->expr()->eq(
444  $this->parentField,
445  $queryBuilder->createNamedParameter($parentId, ‪Connection::PARAM_INT)
446  ),
448  );
449 
450  foreach (‪QueryHelper::parseOrderBy($this->orderByFields) as $orderPair) {
451  [$fieldName, $order] = $orderPair;
452  $queryBuilder->addOrderBy($fieldName, $order);
453  }
454 
455  return $queryBuilder->executeQuery();
456  }
457 
466  protected function ‪getDataNext(&$res)
467  {
468  while ($row = $res->fetchAssociative()) {
469  BackendUtility::workspaceOL($this->table, $row, $this->‪getBackendUser()->workspace, true);
470  if (is_array($row)) {
471  break;
472  }
473  }
474  return $row;
475  }
476 
477  protected function ‪getLanguageService(): ‪LanguageService
478  {
479  return ‪$GLOBALS['LANG'];
480  }
481 
482  protected function ‪getBackendUser(): ‪BackendUserAuthentication
483  {
484  return ‪$GLOBALS['BE_USER'];
485  }
486 }
‪TYPO3\CMS\Core\Database\Query\QueryHelper\parseOrderBy
‪static array array[] parseOrderBy(string $input)
Definition: QueryHelper.php:44
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$parentField
‪string $parentField
Definition: AbstractTreeView.php:49
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:52
‪TYPO3\CMS\Core\Utility\GeneralUtility\fixed_lgd_cs
‪static string fixed_lgd_cs(string $string, int $chars, string $appendString='...')
Definition: GeneralUtility.php:92
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$fieldArray
‪array $fieldArray
Definition: AbstractTreeView.php:71
‪TYPO3\CMS\Core\Imaging\IconProvider\AbstractSvgIconProvider\MARKUP_IDENTIFIER_INLINE
‪const MARKUP_IDENTIFIER_INLINE
Definition: AbstractSvgIconProvider.php:32
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$clause
‪string $clause
Definition: AbstractTreeView.php:56
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getDataInit
‪mixed getDataInit($parentId)
Definition: AbstractTreeView.php:426
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\init
‪init($clause='', $orderByFields='')
Definition: AbstractTreeView.php:148
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$makeHTML
‪int $makeHTML
Definition: AbstractTreeView.php:102
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$ids
‪array $ids
Definition: AbstractTreeView.php:111
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$defaultList
‪string $defaultList
Definition: AbstractTreeView.php:96
‪TYPO3\CMS\Core\Imaging\IconProvider\AbstractSvgIconProvider
Definition: AbstractSvgIconProvider.php:31
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$buffer_idH
‪array $buffer_idH
Definition: AbstractTreeView.php:126
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$orig_ids_hierarchy
‪array $orig_ids_hierarchy
Definition: AbstractTreeView.php:121
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:34
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$table
‪string $table
Definition: AbstractTreeView.php:44
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\expandNext
‪bool expandNext($id)
Definition: AbstractTreeView.php:246
‪TYPO3\CMS\Filelist\Type\fieldArray
‪@ fieldArray
Definition: Mode.php:28
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\reset
‪reset()
Definition: AbstractTreeView.php:175
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$tree
‪array $tree
Definition: AbstractTreeView.php:132
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\__construct
‪__construct()
Definition: AbstractTreeView.php:137
‪TYPO3\CMS\Core\Database\Query\QueryHelper
Definition: QueryHelper.php:32
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getTitleAttrib
‪string getTitleAttrib($row)
Definition: AbstractTreeView.php:291
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$orderByFields
‪string $orderByFields
Definition: AbstractTreeView.php:63
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\PM_ATagWrap
‪string PM_ATagWrap($bMark='', $isOpen=false)
Definition: AbstractTreeView.php:214
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\addField
‪addField($field, $noCheck=false)
Definition: AbstractTreeView.php:165
‪TYPO3\CMS\Backend\Tree\View
Definition: AbstractContentPagePositionMap.php:18
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:41
‪TYPO3\CMS\Webhooks\Message\$uid
‪identifier readonly int $uid
Definition: PageModificationMessage.php:35
‪TYPO3\CMS\Core\Database\Query\QueryHelper\stripLogicalOperatorPrefix
‪static string stripLogicalOperatorPrefix(string $constraint)
Definition: QueryHelper.php:171
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getTree
‪int getTree($uid, $depth=999, $depthData='')
Definition: AbstractTreeView.php:309
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:28
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getIcon
‪string getIcon(array $row)
Definition: AbstractTreeView.php:263
‪TYPO3\CMS\Core\Utility\GeneralUtility\inList
‪static bool inList($list, $item)
Definition: GeneralUtility.php:422
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getBackendUser
‪getBackendUser()
Definition: AbstractTreeView.php:476
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:46
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getLanguageService
‪getLanguageService()
Definition: AbstractTreeView.php:471
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\PMicon
‪string PMicon($row, $a, $c, $nextCount, $isOpen)
Definition: AbstractTreeView.php:199
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getTitleStr
‪string getTitleStr($row, $titleLen=30)
Definition: AbstractTreeView.php:279
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$ids_hierarchy
‪array $ids_hierarchy
Definition: AbstractTreeView.php:116
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView
Definition: AbstractTreeView.php:39
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getCount
‪int getCount($uid)
Definition: AbstractTreeView.php:394
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getDataNext
‪array bool getDataNext(&$res)
Definition: AbstractTreeView.php:460
‪TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction
Definition: WorkspaceRestriction.php:39