‪TYPO3CMS  11.5
AbstractTreeView.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
18 use Psr\Http\Message\ServerRequestInterface;
21 use TYPO3\CMS\Backend\Utility\BackendUtility;
32 
36 abstract class ‪AbstractTreeView
37 {
38  // EXTERNAL, static:
39 
40  // Holds the current script to reload to.
44  public ‪$thisScript = '';
45 
46  // Used if the tree is made of records (not folders for ex.)
50  public ‪$title = 'no title';
51 
58  public ‪$BE_USER = '';
59 
66  public ‪$table = 'pages';
67 
73  public ‪$parentField = 'pid';
74 
81  public ‪$clause = '';
82 
89  public ‪$orderByFields = '';
90 
98  public ‪$fieldArray = [
99  'uid',
100  'pid',
101  'title',
102  'is_siteroot',
103  'doktype',
104  'nav_title',
105  'mount_pid',
106  'php_tree_stop',
107  't3ver_state',
108  'hidden',
109  'starttime',
110  'endtime',
111  'fe_group',
112  'module',
113  'extendToSubpages',
114  'nav_hide',
115  't3ver_wsid',
116  ];
117 
124  public ‪$defaultList = 'uid,pid,tstamp,sorting,deleted,perms_userid,perms_groupid,perms_user,perms_group,perms_everybody,crdate,cruser_id';
125 
131  public ‪$makeHTML = 1;
132 
133  // *********
134  // Internal
135  // *********
136  // For record trees:
137  // one-dim array of the uid's selected.
141  public ‪$ids = [];
142 
143  // The hierarchy of element uids
147  public ‪$ids_hierarchy = [];
148 
149  // The hierarchy of versioned element uids
153  public ‪$orig_ids_hierarchy = [];
154 
155  // Temporary, internal array
159  public ‪$buffer_idH = [];
160 
161  // For both types
162  // Tree is accumulated in this variable
166  public ‪$tree = [];
167 
171  public function ‪__construct()
172  {
173  $this->title = ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'];
174  $this->‪determineScriptUrl();
175  }
176 
180  protected function ‪determineScriptUrl()
181  {
182  if ((‪$GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface
183  && ($route = ‪$GLOBALS['TYPO3_REQUEST']->getAttribute('route')) instanceof ‪Route
184  ) {
185  $this->thisScript = (string)GeneralUtility::makeInstance(UriBuilder::class)->buildUriFromRoutePath(
186  $route->getPath()
187  );
188  }
189  }
190 
194  protected function ‪getThisScript()
195  {
196  return !str_contains($this->thisScript, '?') ? $this->thisScript . '?' : $this->thisScript . '&';
197  }
198 
205  public function ‪init(‪$clause = '', ‪$orderByFields = '')
206  {
207  // Setting BE_USER by default
208  $this->BE_USER = ‪$GLOBALS['BE_USER'];
209  // Setting clause
210  if (‪$clause) {
211  $this->clause = ‪$clause;
212  }
213  if (‪$orderByFields) {
214  $this->orderByFields = ‪$orderByFields;
215  }
216  }
217 
224  public function ‪addField($field, $noCheck = false)
225  {
226  if ($noCheck || is_array(‪$GLOBALS['TCA'][$this->table]['columns'][$field] ?? null) || GeneralUtility::inList($this->defaultList, $field)) {
227  $this->fieldArray[] = $field;
228  }
229  }
230 
234  public function ‪reset()
235  {
236  $this->tree = [];
237  $this->ids = [];
238  $this->ids_hierarchy = [];
239  $this->orig_ids_hierarchy = [];
240  }
241 
242  /*******************************************
243  *
244  * rendering parts
245  *
246  *******************************************/
259  public function ‪PMicon($row, $a, $c, $nextCount, $isOpen)
260  {
261  if ($nextCount) {
262  return $this->‪PM_ATagWrap($row['uid'], $isOpen);
263  }
264  return '';
265  }
266 
275  public function ‪PM_ATagWrap($bMark = '', $isOpen = false)
276  {
277  $anchor = $bMark ? '#' . $bMark : '';
278  $name = $bMark ? ' name="' . $bMark . '"' : '';
279  $aUrl = $this->‪getThisScript() . $anchor;
280  return '<a class="list-tree-control ' . ($isOpen ? 'list-tree-control-open' : 'list-tree-control-closed') . '" href="' . htmlspecialchars($aUrl) . '"' . $name . '><i class="fa"></i></a>';
281  }
282 
290  public function ‪addTagAttributes($icon, $attr)
291  {
292  return preg_replace('/ ?\\/?>$/', '', $icon) . ' ' . $attr . ' />';
293  }
294 
295  /*******************************************
296  *
297  * tree handling
298  *
299  *******************************************/
310  public function ‪expandNext($id)
311  {
312  return false;
313  }
314 
315  /******************************
316  *
317  * Functions that might be overwritten by extended classes
318  *
319  ********************************/
326  public function ‪getRootIcon($rec)
327  {
328  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
329  return $iconFactory->getIcon('apps-pagetree-root', ‪Icon::SIZE_SMALL)->render();
330  }
331 
338  public function ‪getIcon($row): string
339  {
340  if (is_int($row)) {
341  trigger_error(
342  'Calling ' . __METHOD__ . ' with argument $row containing the records uid is deprecated and will be removed in v12. Use the full row instead.',
343  E_USER_DEPRECATED
344  );
345 
346  $row = BackendUtility::getRecord($this->table, $row);
347  if ($row === null) {
348  return '';
349  }
350  }
351  ‪$title = $this->‪getTitleAttrib($row);
352  $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
353  $icon = $row['is_siteroot'] ? $iconFactory->getIcon('apps-pagetree-folder-root', ‪Icon::SIZE_SMALL) : $iconFactory->getIconForRecord($this->table, $row, ‪Icon::SIZE_SMALL);
354  return '<span title="' . ‪$title . '">' . $icon->render() . '</span>';
355  }
356 
365  public function ‪getTitleStr($row, $titleLen = 30)
366  {
367  ‪$title = htmlspecialchars(GeneralUtility::fixed_lgd_cs($row['title'], $titleLen));
368  return trim(‪$title) === '' ? '<em>[' . htmlspecialchars($this->‪getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.no_title')) . ']</em>' : ‪$title;
369  }
370 
377  public function ‪getTitleAttrib($row)
378  {
379  return htmlspecialchars($row['title']);
380  }
381 
382  /********************************
383  *
384  * tree data building
385  *
386  ********************************/
395  public function ‪getTree($uid, $depth = 999, $depthData = '')
396  {
397  // Buffer for id hierarchy is reset:
398  $this->buffer_idH = [];
399  // Init vars
400  $depth = (int)$depth;
401  $HTML = '';
402  $a = 0;
403  $res = $this->‪getDataInit($uid);
404  $c = $this->‪getDataCount($res);
405  $crazyRecursionLimiter = 9999;
406  $idH = [];
407  // Traverse the records:
408  while ($crazyRecursionLimiter > 0 && ($row = $this->‪getDataNext($res))) {
410  if (!$this->‪getBackendUser()->isInWebMount($this->table === 'pages' ? $row : $row['pid'])) {
411  // Current record is not within web mount => skip it
412  continue;
413  }
414 
415  $a++;
416  $crazyRecursionLimiter--;
417  $newID = $row['uid'];
418  if ($newID == 0) {
419  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);
420  }
421  // Reserve space.
422  $this->tree[] = [];
423  end($this->tree);
424  // Get the key for this space
425  $treeKey = key($this->tree);
426  // Accumulate the id of the element in the internal arrays
427  $this->ids[] = ($idH[$row['uid']]['uid'] = $row['uid']);
428  $this->ids_hierarchy[$depth][] = $row['uid'];
429  $this->orig_ids_hierarchy[$depth][] = (isset($row['_ORIG_uid']) && !empty($row['_ORIG_uid'])) ? $row['_ORIG_uid'] : $row['uid'];
430 
431  // Make a recursive call to the next level
432  $nextLevelDepthData = $depthData . '<span class="treeline-icon treeline-icon-' . ($a === $c ? 'clear' : 'line') . '"></span>';
433  $hasSub = $this->‪expandNext($newID) && !($row['php_tree_stop'] ?? false);
434  if ($depth > 1 && $hasSub) {
435  $nextCount = $this->‪getTree($newID, $depth - 1, $nextLevelDepthData);
436  if (!empty($this->buffer_idH)) {
437  $idH[$row['uid']]['subrow'] = ‪$this->buffer_idH;
438  }
439  // Set "did expand" flag
440  $isOpen = true;
441  } else {
442  $nextCount = $this->‪getCount($newID);
443  // Clear "did expand" flag
444  $isOpen = false;
445  }
446  // Set HTML-icons, if any:
447  if ($this->makeHTML) {
448  $HTML = $this->‪PMicon($row, $a, $c, $nextCount, $isOpen);
449  }
450  // Finally, add the row/HTML content to the ->tree array in the reserved key.
451  $this->tree[$treeKey] = [
452  'row' => $row,
453  'HTML' => $HTML,
454  'invertedDepth' => $depth,
455  'depthData' => $depthData,
456  'hasSub' => $nextCount && $hasSub,
457  'isFirst' => $a === 1,
458  'isLast' => $a === $c,
459  ];
460  }
461 
462  $this->‪getDataFree($res);
463  $this->buffer_idH = $idH;
464  return $c;
465  }
466 
467  /********************************
468  *
469  * Data handling
470  * Works with records and arrays
471  *
472  ********************************/
480  public function ‪getCount($uid)
481  {
482  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->table);
483  $queryBuilder->getRestrictions()
484  ->removeAll()
485  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
486  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->‪getBackendUser()->workspace));
487  $count = $queryBuilder
488  ->count('uid')
489  ->from($this->table)
490  ->where(
491  $queryBuilder->expr()->eq(
492  $this->parentField,
493  $queryBuilder->createNamedParameter($uid, ‪Connection::PARAM_INT)
494  ),
496  )
497  ->executeQuery()
498  ->fetchOne();
499 
500  return (int)$count;
501  }
502 
508  public function ‪getRootRecord()
509  {
510  return ['title' => ‪$this->title, 'uid' => 0];
511  }
512 
523  public function ‪getDataInit($parentId)
524  {
525  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->table);
526  $queryBuilder->getRestrictions()
527  ->removeAll()
528  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
529  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->‪getBackendUser()->workspace));
530  $queryBuilder
531  ->select(...$this->fieldArray)
532  ->from($this->table)
533  ->where(
534  $queryBuilder->expr()->eq(
535  $this->parentField,
536  $queryBuilder->createNamedParameter($parentId, ‪Connection::PARAM_INT)
537  ),
539  );
540 
541  foreach (‪QueryHelper::parseOrderBy($this->orderByFields) as $orderPair) {
542  [$fieldName, $order] = $orderPair;
543  $queryBuilder->addOrderBy($fieldName, $order);
544  }
545 
546  return $queryBuilder->executeQuery();
547  }
548 
557  public function ‪getDataCount(&$res)
558  {
559  return $res->rowCount();
560  }
561 
571  public function ‪getDataNext(&$res)
572  {
573  while ($row = $res->fetchAssociative()) {
574  BackendUtility::workspaceOL($this->table, $row, $this->‪getBackendUser()->workspace, true);
575  if (is_array($row)) {
576  break;
577  }
578  }
579  return $row;
580  }
581 
588  public function ‪getDataFree(&$res)
589  {
590  $res->free();
591  }
592 
596  protected function ‪getLanguageService()
597  {
598  return ‪$GLOBALS['LANG'];
599  }
600 
604  protected function ‪getBackendUser()
605  {
606  return ‪$GLOBALS['BE_USER'];
607  }
608 }
‪TYPO3\CMS\Core\Imaging\Icon\SIZE_SMALL
‪const SIZE_SMALL
Definition: Icon.php:30
‪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:68
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:49
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$fieldArray
‪array $fieldArray
Definition: AbstractTreeView.php:90
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$clause
‪string $clause
Definition: AbstractTreeView.php:75
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getDataInit
‪mixed getDataInit($parentId)
Definition: AbstractTreeView.php:508
‪TYPO3\CMS\Core\Imaging\Icon
Definition: Icon.php:26
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$title
‪string $title
Definition: AbstractTreeView.php:48
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\init
‪init($clause='', $orderByFields='')
Definition: AbstractTreeView.php:190
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$makeHTML
‪int $makeHTML
Definition: AbstractTreeView.php:121
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$ids
‪array $ids
Definition: AbstractTreeView.php:130
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$defaultList
‪string $defaultList
Definition: AbstractTreeView.php:115
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$BE_USER
‪TYPO3 CMS Core Authentication BackendUserAuthentication string $BE_USER
Definition: AbstractTreeView.php:55
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$buffer_idH
‪array $buffer_idH
Definition: AbstractTreeView.php:145
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$orig_ids_hierarchy
‪array $orig_ids_hierarchy
Definition: AbstractTreeView.php:140
‪TYPO3\CMS\Core\Imaging\IconFactory
Definition: IconFactory.php:34
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$table
‪string $table
Definition: AbstractTreeView.php:62
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getDataFree
‪getDataFree(&$res)
Definition: AbstractTreeView.php:573
‪TYPO3\CMS\Backend\Routing\Route
Definition: Route.php:24
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\expandNext
‪bool expandNext($id)
Definition: AbstractTreeView.php:295
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getRootRecord
‪array getRootRecord()
Definition: AbstractTreeView.php:493
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getDataCount
‪int getDataCount(&$res)
Definition: AbstractTreeView.php:542
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\reset
‪reset()
Definition: AbstractTreeView.php:219
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$tree
‪array $tree
Definition: AbstractTreeView.php:151
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\__construct
‪__construct()
Definition: AbstractTreeView.php:156
‪TYPO3\CMS\Core\Database\Query\QueryHelper
Definition: QueryHelper.php:32
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getTitleAttrib
‪string getTitleAttrib($row)
Definition: AbstractTreeView.php:362
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getRootIcon
‪string getRootIcon($rec)
Definition: AbstractTreeView.php:311
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:40
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$orderByFields
‪string $orderByFields
Definition: AbstractTreeView.php:82
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\PM_ATagWrap
‪string PM_ATagWrap($bMark='', $isOpen=false)
Definition: AbstractTreeView.php:260
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\addTagAttributes
‪string addTagAttributes($icon, $attr)
Definition: AbstractTreeView.php:275
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getBackendUser
‪BackendUserAuthentication getBackendUser()
Definition: AbstractTreeView.php:589
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\addField
‪addField($field, $noCheck=false)
Definition: AbstractTreeView.php:209
‪TYPO3\CMS\Backend\Tree\View
Definition: AbstractContentPagePositionMap.php:18
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getLanguageService
‪LanguageService getLanguageService()
Definition: AbstractTreeView.php:581
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:38
‪TYPO3\CMS\Core\Database\Query\QueryHelper\stripLogicalOperatorPrefix
‪static string stripLogicalOperatorPrefix(string $constraint)
Definition: QueryHelper.php:171
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getIcon
‪string getIcon($row)
Definition: AbstractTreeView.php:323
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\determineScriptUrl
‪determineScriptUrl()
Definition: AbstractTreeView.php:165
‪$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:380
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:28
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getThisScript
‪string getThisScript()
Definition: AbstractTreeView.php:179
‪TYPO3\CMS\Core\Localization\LanguageService
Definition: LanguageService.php:42
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\PMicon
‪string PMicon($row, $a, $c, $nextCount, $isOpen)
Definition: AbstractTreeView.php:244
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getTitleStr
‪string getTitleStr($row, $titleLen=30)
Definition: AbstractTreeView.php:350
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$ids_hierarchy
‪array $ids_hierarchy
Definition: AbstractTreeView.php:135
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView
Definition: AbstractTreeView.php:37
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getCount
‪int getCount($uid)
Definition: AbstractTreeView.php:465
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\getDataNext
‪array bool getDataNext(&$res)
Definition: AbstractTreeView.php:556
‪TYPO3\CMS\Backend\Tree\View\AbstractTreeView\$thisScript
‪string $thisScript
Definition: AbstractTreeView.php:43
‪TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction
Definition: WorkspaceRestriction.php:40