‪TYPO3CMS  10.4
PageTreeRepository.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 Doctrine\DBAL\Connection;
31 
41 {
47  protected ‪$fields = [
48  'uid',
49  'pid',
50  'sorting',
51  'starttime',
52  'endtime',
53  'hidden',
54  'fe_group',
55  'title',
56  'nav_title',
57  'nav_hide',
58  'php_tree_stop',
59  'doktype',
60  'is_siteroot',
61  'module',
62  'extendToSubpages',
63  'content_from_pid',
64  't3ver_oid',
65  't3ver_wsid',
66  't3ver_state',
67  't3ver_stage',
68  't3ver_tstamp',
69  't3ver_move_id',
70  'perms_userid',
71  'perms_user',
72  'perms_groupid',
73  'perms_group',
74  'perms_everybody',
75  'mount_pid',
76  'shortcut',
77  'shortcut_mode',
78  'mount_pid_ol',
79  'url',
80  'sys_language_uid',
81  'l10n_parent',
82  ];
83 
89  protected ‪$currentWorkspace = 0;
90 
96  protected ‪$fullPageTree = [];
97 
101  protected ‪$additionalQueryRestrictions = [];
102 
108  public function ‪__construct(int $workspaceId = 0, array $additionalFieldsToQuery = [], array ‪$additionalQueryRestrictions = [])
109  {
110  $this->currentWorkspace = $workspaceId;
111  if (!empty($additionalFieldsToQuery)) {
112  $this->fields = array_merge($this->fields, $additionalFieldsToQuery);
113  }
114 
115  if (!empty(‪$additionalQueryRestrictions)) {
116  $this->additionalQueryRestrictions = ‪$additionalQueryRestrictions;
117  }
118  }
119 
130  public function ‪getTree(
131  int $entryPoint,
132  callable $callback = null,
133  array $dbMounts = [],
134  $resolveUserPermissions = false
135  ): array {
136  $this->‪fetchAllPages($dbMounts, $resolveUserPermissions);
137  if ($entryPoint === 0) {
138  $tree = ‪$this->fullPageTree;
139  } else {
140  $tree = $this->‪findInPageTree($entryPoint, $this->fullPageTree);
141  }
142  if (!empty($tree) && $callback !== null) {
143  $this->‪applyCallbackToChildren($tree, $callback);
144  }
145  return $tree;
146  }
147 
154  protected function ‪applyCallbackToChildren(array &$tree, callable $callback)
155  {
156  if (!isset($tree['_children'])) {
157  return;
158  }
159  foreach ($tree['_children'] as $k => &$childPage) {
160  if (!call_user_func_array($callback, [$childPage])) {
161  unset($tree['_children'][$k]);
162  continue;
163  }
164  $this->‪applyCallbackToChildren($childPage, $callback);
165  }
166  }
167 
176  public function ‪getTreeLevels(array $pageTree, int $depth, array $entryPointIds = []): array
177  {
178  $groupedAndSortedPagesByPid = [];
179 
180  if (count($entryPointIds) > 0) {
181  $pageRecords = $this->‪getPageRecords($entryPointIds);
182  $groupedAndSortedPagesByPid[$pageTree['uid']] = $pageRecords;
183  $parentPageIds = $entryPointIds;
184  } else {
185  $parentPageIds = [$pageTree['uid']];
186  }
187 
188  for ($i = 0; $i < $depth; $i++) {
189  if (empty($parentPageIds)) {
190  break;
191  }
192  $pageRecords = $this->‪getChildPageRecords($parentPageIds);
193 
194  $groupedAndSortedPagesByPid = $this->‪groupAndSortPages($pageRecords, $groupedAndSortedPagesByPid);
195 
196  $parentPageIds = array_column($pageRecords, 'uid');
197  }
198  $this->‪addChildrenToPage($pageTree, $groupedAndSortedPagesByPid);
199  return $pageTree;
200  }
201 
202  protected function ‪getChildPageRecords(array $parentPageIds): array
203  {
204  return $this->‪getPageRecords([], $parentPageIds);
205  }
206 
214  protected function ‪getPageRecords(array $pageIds = [], array $parentPageIds = []): array
215  {
216  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
217  ->getQueryBuilderForTable('pages');
218  $queryBuilder->getRestrictions()
219  ->removeAll()
220  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
221  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, $this->currentWorkspace));
222 
223  if (!empty($this->additionalQueryRestrictions)) {
224  foreach ($this->additionalQueryRestrictions as $additionalQueryRestriction) {
225  $queryBuilder->getRestrictions()->add($additionalQueryRestriction);
226  }
227  }
228 
229  $queryBuilder
230  ->select(...$this->fields)
231  ->from('pages')
232  ->where(
233  $queryBuilder->expr()->eq('sys_language_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
234  )
235  ->andWhere(
237  )
238  // ensure deterministic sorting
239  ->orderBy('sorting', 'ASC')
240  ->addOrderBy('uid', 'ASC');
241 
242  if (count($pageIds) > 0) {
243  $queryBuilder->andWhere(
244  $queryBuilder->expr()->in('uid', $queryBuilder->createNamedParameter($pageIds, Connection::PARAM_INT_ARRAY))
245  );
246  }
247 
248  if (count($parentPageIds) > 0) {
249  $queryBuilder->andWhere(
250  $queryBuilder->expr()->in('pid', $queryBuilder->createNamedParameter($parentPageIds, Connection::PARAM_INT_ARRAY))
251  );
252  }
253 
254  $pageRecords = $queryBuilder
255  ->execute()
256  ->fetchAll();
257 
258  // This is necessary to resolve all IDs in a workspace
259  if ($this->currentWorkspace !== 0 && !empty($pageRecords)) {
260  $livePagePids = [];
261  $livePageIds = [];
262  $movePlaceholderData = [];
263  foreach ($pageRecords as $pageRecord) {
264  $livePageIds[] = (int)$pageRecord['uid'];
265  $livePagePids[(int)$pageRecord['uid']] = (int)$pageRecord['pid'];
266  if ((int)$pageRecord['t3ver_state'] === ‪VersionState::MOVE_PLACEHOLDER) {
267  $movePlaceholderData[$pageRecord['t3ver_move_id']] = [
268  'pid' => (int)$pageRecord['pid'],
269  'sorting' => (int)$pageRecord['sorting']
270  ];
271  }
272  }
273 
274  // Resolve placeholders of workspace versions
275  $resolver = GeneralUtility::makeInstance(
276  PlainDataResolver::class,
277  'pages',
278  $livePageIds
279  );
280  $resolver->setWorkspaceId($this->currentWorkspace);
281  $resolver->setKeepDeletePlaceholder(false);
282  $resolver->setKeepMovePlaceholder(false);
283  $resolver->setKeepLiveIds(false);
284  $recordIds = $resolver->get();
285 
286  if (!empty($recordIds)) {
287  $queryBuilder->getRestrictions()->removeAll();
288  $pageRecords = $queryBuilder
289  ->select(...$this->fields)
290  ->from('pages')
291  ->where(
292  $queryBuilder->expr()->in('uid', $queryBuilder->createNamedParameter($recordIds, Connection::PARAM_INT_ARRAY))
293  )
294  // ensure deterministic sorting
295  ->orderBy('sorting', 'ASC')
296  ->addOrderBy('uid', 'ASC')
297  ->execute()
298  ->fetchAll();
299 
300  foreach ($pageRecords as &$pageRecord) {
301  if ((int)$pageRecord['t3ver_state'] === ‪VersionState::MOVE_PLACEHOLDER) {
302  $liveRecord = ‪BackendUtility::getRecord('pages', $pageRecord['t3ver_move_id']);
303  $pageRecord['uid'] = (int)$liveRecord['uid'];
304  $pageRecord['t3ver_oid'] = (int)$pageRecord['t3ver_move_id'];
305  $pageRecord['title'] = $liveRecord['title'];
306  } elseif ((int)$pageRecord['t3ver_state'] === ‪VersionState::MOVE_POINTER && !empty($movePlaceholderData[$pageRecord['t3ver_oid']])) {
307  $pageRecord['uid'] = $pageRecord['t3ver_oid'];
308  $pageRecord['sorting'] = (int)$movePlaceholderData[$pageRecord['t3ver_oid']]['sorting'];
309  $pageRecord['t3ver_state'] = ‪VersionState::MOVE_PLACEHOLDER;
310  $pageRecord['pid'] = (int)$movePlaceholderData[$pageRecord['t3ver_oid']]['pid'];
311  } elseif ((int)$pageRecord['t3ver_oid'] > 0) {
312  $liveRecord = ‪BackendUtility::getRecord('pages', $pageRecord['t3ver_oid']);
313  $pageRecord['sorting'] = (int)$liveRecord['sorting'];
314  $pageRecord['uid'] = (int)$liveRecord['uid'];
315  $pageRecord['pid'] = (int)$liveRecord['pid'];
316  }
317  }
318  } else {
319  $pageRecords = [];
320  }
321  }
322  foreach ($pageRecords as &$pageRecord) {
323  $pageRecord['uid'] = (int)$pageRecord['uid'];
324  }
325 
326  return $pageRecords;
327  }
328 
329  public function ‪hasChildren(int $pid): bool
330  {
331  $pageRecords = $this->‪getChildPageRecords([$pid]);
332  return !empty($pageRecords);
333  }
334 
342  protected function ‪fetchAllPages(array $dbMounts, bool $resolveUserPermissions = false): array
343  {
344  if (!empty($this->fullPageTree)) {
345  return ‪$this->fullPageTree;
346  }
347  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
348  ->getQueryBuilderForTable('pages');
349  $queryBuilder->getRestrictions()
350  ->removeAll()
351  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
352  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, $this->currentWorkspace));
353 
354  if (!empty($this->additionalQueryRestrictions)) {
355  foreach ($this->additionalQueryRestrictions as $additionalQueryRestriction) {
356  $queryBuilder->getRestrictions()->add($additionalQueryRestriction);
357  }
358  }
359 
360  $query = $queryBuilder
361  ->select(...$this->fields)
362  ->from('pages')
363  ->where(
364  // Only show records in default language
365  $queryBuilder->expr()->eq('sys_language_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
366  );
367 
368  if ($resolveUserPermissions) {
369  $query->andWhere(
371  );
372  }
373 
374  $pageRecords = $query->execute()->fetchAll();
375 
376  $ids = array_column($pageRecords, 'uid');
377  foreach ($dbMounts as $mount) {
378  $entryPointRootLine = ‪BackendUtility::BEgetRootLine($mount, '', false, $this->fields);
379  foreach ($entryPointRootLine as $page) {
380  $pageId = (int)$page['uid'];
381  if (in_array($pageId, $ids) || $pageId === 0) {
382  continue;
383  }
384  $pageRecords[] = $page;
385  $ids[] = $pageId;
386  }
387  }
388 
389  $livePagePids = [];
390  $movePlaceholderData = [];
391  // This is necessary to resolve all IDs in a workspace
392  if ($this->currentWorkspace !== 0 && !empty($pageRecords)) {
393  $livePageIds = [];
394  foreach ($pageRecords as $pageRecord) {
395  $livePageIds[] = (int)$pageRecord['uid'];
396  $livePagePids[(int)$pageRecord['uid']] = (int)$pageRecord['pid'];
397  if ((int)$pageRecord['t3ver_state'] === ‪VersionState::MOVE_PLACEHOLDER) {
398  $movePlaceholderData[$pageRecord['t3ver_move_id']] = [
399  'pid' => (int)$pageRecord['pid'],
400  'sorting' => (int)$pageRecord['sorting']
401  ];
402  }
403  }
404  // Resolve placeholders of workspace versions
405  $resolver = GeneralUtility::makeInstance(
406  PlainDataResolver::class,
407  'pages',
408  $livePageIds
409  );
410  $resolver->setWorkspaceId($this->currentWorkspace);
411  $resolver->setKeepDeletePlaceholder(false);
412  $resolver->setKeepMovePlaceholder(false);
413  $resolver->setKeepLiveIds(false);
414  $recordIds = $resolver->get();
415 
416  $queryBuilder->getRestrictions()->removeAll();
417  $pageRecords = $queryBuilder
418  ->select(...$this->fields)
419  ->from('pages')
420  ->where(
421  $queryBuilder->expr()->in('uid', $recordIds)
422  )
423  ->execute()
424  ->fetchAll();
425  }
426 
427  // Now set up sorting, nesting (tree-structure) for all pages based on pid+sorting fields
428  $groupedAndSortedPagesByPid = [];
429  foreach ($pageRecords as $pageRecord) {
430  $parentPageId = (int)$pageRecord['pid'];
431  // In case this is a record from a workspace
432  // The uid+pid of the live-version record is fetched
433  // This is done in order to avoid fetching records again (e.g. via BackendUtility::workspaceOL()
434  if ((int)$pageRecord['t3ver_oid'] > 0) {
435  // When a move pointer is found, the pid+sorting of the MOVE_PLACEHOLDER should be used (this is the
436  // workspace record holding this information), also the t3ver_state is set to the MOVE_PLACEHOLDER
437  // because the record is then added
438  if ((int)$pageRecord['t3ver_state'] === ‪VersionState::MOVE_POINTER && !empty($movePlaceholderData[$pageRecord['t3ver_oid']])) {
439  $parentPageId = (int)$movePlaceholderData[$pageRecord['t3ver_oid']]['pid'];
440  $pageRecord['sorting'] = (int)$movePlaceholderData[$pageRecord['t3ver_oid']]['sorting'];
441  $pageRecord['t3ver_state'] = ‪VersionState::MOVE_PLACEHOLDER;
442  } else {
443  // Just a record in a workspace (not moved etc)
444  $parentPageId = (int)$livePagePids[$pageRecord['t3ver_oid']];
445  }
446  // this is necessary so the links to the modules are still pointing to the live IDs
447  $pageRecord['uid'] = (int)$pageRecord['t3ver_oid'];
448  $pageRecord['pid'] = $parentPageId;
449  }
450 
451  $sorting = (int)$pageRecord['sorting'];
452  while (isset($groupedAndSortedPagesByPid[$parentPageId][$sorting])) {
453  $sorting++;
454  }
455  $groupedAndSortedPagesByPid[$parentPageId][$sorting] = $pageRecord;
456  }
457 
458  $this->fullPageTree = [
459  'uid' => 0,
460  'title' => ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ?: 'TYPO3'
461  ];
462  $this->‪addChildrenToPage($this->fullPageTree, $groupedAndSortedPagesByPid);
463  return ‪$this->fullPageTree;
464  }
465 
472  protected function ‪addChildrenToPage(array &$page, array &$groupedAndSortedPagesByPid)
473  {
474  $page['_children'] = $groupedAndSortedPagesByPid[(int)$page['uid']] ?? [];
475  ksort($page['_children']);
476  foreach ($page['_children'] as &$child) {
477  $this->‪addChildrenToPage($child, $groupedAndSortedPagesByPid);
478  }
479  }
480 
488  protected function ‪findInPageTree(int $pageId, array $pages): array
489  {
490  foreach ($pages['_children'] as $childPage) {
491  if ((int)$childPage['uid'] === $pageId) {
492  return $childPage;
493  }
494  $result = $this->‪findInPageTree($pageId, $childPage);
495  if (!empty($result)) {
496  return $result;
497  }
498  }
499  return [];
500  }
501 
510  public function ‪fetchFilteredTree(string $searchFilter, array $allowedMountPointPageIds, string $additionalWhereClause): array
511  {
512  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
513  ->getQueryBuilderForTable('pages');
514  $queryBuilder->getRestrictions()
515  ->removeAll()
516  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
517 
518  if (!empty($this->additionalQueryRestrictions)) {
519  foreach ($this->additionalQueryRestrictions as $additionalQueryRestriction) {
520  $queryBuilder->getRestrictions()->add($additionalQueryRestriction);
521  }
522  }
523 
524  $expressionBuilder = $queryBuilder->expr();
525 
526  if ($this->currentWorkspace === 0) {
527  // Only include ws_id=0
528  $workspaceIdExpression = $expressionBuilder->eq('t3ver_wsid', 0);
529  } else {
530  // Include live records PLUS records from the given workspace
531  $workspaceIdExpression = $expressionBuilder->in(
532  't3ver_wsid',
533  [0, $this->currentWorkspace]
534  );
535  }
536 
537  $queryBuilder = $queryBuilder
538  ->select(...$this->fields)
539  ->from('pages')
540  ->where(
541  // Only show records in default language
542  $expressionBuilder->eq('sys_language_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)),
543  $workspaceIdExpression,
544  ‪QueryHelper::stripLogicalOperatorPrefix($additionalWhereClause)
545  );
546 
547  $searchParts = $expressionBuilder->orX();
548  if (is_numeric($searchFilter) && $searchFilter > 0) {
549  $searchParts->add(
550  $expressionBuilder->eq('uid', $queryBuilder->createNamedParameter($searchFilter, \PDO::PARAM_INT))
551  );
552  }
553  $searchFilter = '%' . $queryBuilder->escapeLikeWildcards($searchFilter) . '%';
554 
555  $searchWhereAlias = $expressionBuilder->orX(
556  $expressionBuilder->like(
557  'nav_title',
558  $queryBuilder->createNamedParameter($searchFilter, \PDO::PARAM_STR)
559  ),
560  $expressionBuilder->like(
561  'title',
562  $queryBuilder->createNamedParameter($searchFilter, \PDO::PARAM_STR)
563  )
564  );
565  $searchParts->add($searchWhereAlias);
566 
567  $queryBuilder->andWhere($searchParts);
568  $pageRecords = $queryBuilder
569  ->execute()
570  ->fetchAll();
571 
572  $livePagePids = [];
573  if ($this->currentWorkspace !== 0 && !empty($pageRecords)) {
574  $livePageIds = [];
575  foreach ($pageRecords as $pageRecord) {
576  $livePageIds[] = (int)$pageRecord['uid'];
577  $livePagePids[(int)$pageRecord['uid']] = (int)$pageRecord['pid'];
578  if ((int)$pageRecord['t3ver_oid'] > 0) {
579  $livePagePids[(int)$pageRecord['t3ver_oid']] = (int)$pageRecord['pid'];
580  }
581  if ((int)$pageRecord['t3ver_state'] === ‪VersionState::MOVE_PLACEHOLDER) {
582  $movePlaceholderData[$pageRecord['t3ver_move_id']] = [
583  'pid' => (int)$pageRecord['pid'],
584  'sorting' => (int)$pageRecord['sorting']
585  ];
586  }
587  }
588  // Resolve placeholders of workspace versions
589  $resolver = GeneralUtility::makeInstance(
590  PlainDataResolver::class,
591  'pages',
592  $livePageIds
593  );
594  $resolver->setWorkspaceId($this->currentWorkspace);
595  $resolver->setKeepDeletePlaceholder(false);
596  $resolver->setKeepMovePlaceholder(false);
597  $resolver->setKeepLiveIds(false);
598  $recordIds = $resolver->get();
599 
600  $pageRecords = [];
601  if (!empty($recordIds)) {
602  $queryBuilder->getRestrictions()->removeAll();
603  $queryBuilder
604  ->select(...$this->fields)
605  ->from('pages')
606  ->where(
607  $queryBuilder->expr()->in('uid', $queryBuilder->createNamedParameter($recordIds, Connection::PARAM_INT_ARRAY))
608  );
609  $queryBuilder->andWhere($searchParts);
610  $pageRecords = $queryBuilder
611  ->execute()
612  ->fetchAll();
613  }
614  }
615 
616  $pages = [];
617  foreach ($pageRecords as $pageRecord) {
618  // In case this is a record from a workspace
619  // The uid+pid of the live-version record is fetched
620  // This is done in order to avoid fetching records again (e.g. via BackendUtility::workspaceOL()
621  if ((int)$pageRecord['t3ver_oid'] > 0) {
622  // This probably should also remove the live version
623  if ((int)$pageRecord['t3ver_state'] === ‪VersionState::DELETE_PLACEHOLDER) {
624  continue;
625  }
626  // When a move pointer is found, the pid+sorting of the MOVE_PLACEHOLDER should be used (this is the
627  // workspace record holding this information), also the t3ver_state is set to the MOVE_PLACEHOLDER
628  // because the record is then added
629  if ((int)$pageRecord['t3ver_state'] === ‪VersionState::MOVE_POINTER && !empty($movePlaceholderData[$pageRecord['t3ver_oid']])) {
630  $parentPageId = (int)$movePlaceholderData[$pageRecord['t3ver_oid']]['pid'];
631  $pageRecord['sorting'] = (int)$movePlaceholderData[$pageRecord['t3ver_oid']]['sorting'];
632  $pageRecord['t3ver_state'] = ‪VersionState::MOVE_PLACEHOLDER;
633  } else {
634  // Just a record in a workspace (not moved etc)
635  $parentPageId = (int)$livePagePids[$pageRecord['t3ver_oid']];
636  }
637  // this is necessary so the links to the modules are still pointing to the live IDs
638  $pageRecord['uid'] = (int)$pageRecord['t3ver_oid'];
639  $pageRecord['pid'] = $parentPageId;
640  }
641  $pages[(int)$pageRecord['uid']] = $pageRecord;
642  }
643  unset($pageRecords);
644 
645  $pages = $this->‪filterPagesOnMountPoints($pages, $allowedMountPointPageIds);
646 
647  $groupedAndSortedPagesByPid = $this->‪groupAndSortPages($pages);
648 
649  $this->fullPageTree = [
650  'uid' => 0,
651  'title' => ‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ?: 'TYPO3'
652  ];
653  $this->‪addChildrenToPage($this->fullPageTree, $groupedAndSortedPagesByPid);
654 
655  return ‪$this->fullPageTree;
656  }
657 
665  protected function ‪filterPagesOnMountPoints(array $pages, array $mountPoints): array
666  {
667  foreach ($pages as $key => $pageRecord) {
669  $pageRecord['uid'],
670  '',
671  $this->currentWorkspace !== 0,
672  $this->fields
673  );
674  $rootline = array_reverse($rootline);
675  if (!in_array(0, $mountPoints, true)) {
676  $isInsideMountPoints = false;
677  foreach ($rootline as $rootlineElement) {
678  if (in_array((int)$rootlineElement['uid'], $mountPoints, true)) {
679  $isInsideMountPoints = true;
680  break;
681  }
682  }
683  if (!$isInsideMountPoints) {
684  unset($pages[$key]);
685  //skip records outside of the allowed mount points
686  continue;
687  }
688  }
689 
690  $inFilteredRootline = false;
691  $amountOfRootlineElements = count($rootline);
692  for ($i = 0; $i < $amountOfRootlineElements; ++$i) {
693  $rootlineElement = $rootline[$i];
694  $rootlineElement['uid'] = (int)$rootlineElement['uid'];
695  $isInWebMount = false;
696  if ($rootlineElement['uid'] > 0) {
697  $isInWebMount = (int)$this->‪getBackendUser()->‪isInWebMount($rootlineElement);
698  }
699 
700  if (!$isInWebMount
701  || ($rootlineElement['uid'] === (int)$mountPoints[0]
702  && $rootlineElement['uid'] !== $isInWebMount)
703  ) {
704  continue;
705  }
706  if ($this->‪getBackendUser()->‪isAdmin() || ($rootlineElement['uid'] === $isInWebMount && in_array($rootlineElement['uid'], $mountPoints, true))) {
707  $inFilteredRootline = true;
708  }
709  if (!$inFilteredRootline) {
710  continue;
711  }
712 
713  if (!isset($pages[$rootlineElement['uid']])) {
714  $pages[$rootlineElement['uid']] = $rootlineElement;
715  }
716  }
717  }
718  // Make sure the mountpoints show up in page tree even when parent pages are not accessible pages
719  foreach ($mountPoints as $mountPoint) {
720  if ($mountPoint !== 0) {
721  if (!array_key_exists($mountPoint, $pages)) {
722  $pages[$mountPoint] = ‪BackendUtility::getRecord('pages', $mountPoint);
723  $pages[$mountPoint]['uid'] = (int)$pages[$mountPoint]['uid'];
724  }
725  $pages[$mountPoint]['pid'] = 0;
726  }
727  }
728 
729  return $pages;
730  }
731 
739  protected function ‪groupAndSortPages(array $pages, $groupedAndSortedPagesByPid = []): array
740  {
741  foreach ($pages as $key => $pageRecord) {
742  $parentPageId = (int)$pageRecord['pid'];
743  $sorting = (int)$pageRecord['sorting'];
744  // If the page record was already added in another depth level, don't add it another time.
745  // This may happen, if entry points are intersecting each other (Entry point B is inside entry point A).
746  if (($groupedAndSortedPagesByPid[$parentPageId][$sorting]['uid'] ?? 0) === $pageRecord['uid']) {
747  continue;
748  }
749  while (isset($groupedAndSortedPagesByPid[$parentPageId][$sorting])) {
750  $sorting++;
751  }
752  $groupedAndSortedPagesByPid[$parentPageId][$sorting] = $pageRecord;
753  }
754 
755  return $groupedAndSortedPagesByPid;
756  }
757 
761  protected function ‪getBackendUser(): ‪BackendUserAuthentication
762  {
763  return ‪$GLOBALS['BE_USER'];
764  }
765 }
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\$fullPageTree
‪array $fullPageTree
Definition: PageTreeRepository.php:93
‪TYPO3\CMS\Core\DataHandling\PlainDataResolver
Definition: PlainDataResolver.php:34
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\filterPagesOnMountPoints
‪array filterPagesOnMountPoints(array $pages, array $mountPoints)
Definition: PageTreeRepository.php:661
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\hasChildren
‪hasChildren(int $pid)
Definition: PageTreeRepository.php:325
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\$fields
‪string[] $fields
Definition: PageTreeRepository.php:46
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\fetchAllPages
‪array fetchAllPages(array $dbMounts, bool $resolveUserPermissions=false)
Definition: PageTreeRepository.php:338
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\getTreeLevels
‪array getTreeLevels(array $pageTree, int $depth, array $entryPointIds=[])
Definition: PageTreeRepository.php:172
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\$additionalQueryRestrictions
‪array $additionalQueryRestrictions
Definition: PageTreeRepository.php:97
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\$currentWorkspace
‪int $currentWorkspace
Definition: PageTreeRepository.php:87
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\isAdmin
‪bool isAdmin()
Definition: BackendUserAuthentication.php:292
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\fetchFilteredTree
‪array fetchFilteredTree(string $searchFilter, array $allowedMountPointPageIds, string $additionalWhereClause)
Definition: PageTreeRepository.php:506
‪TYPO3\CMS\Core\Versioning\VersionState\DELETE_PLACEHOLDER
‪const DELETE_PLACEHOLDER
Definition: VersionState.php:55
‪TYPO3\CMS\Backend\Utility\BackendUtility\BEgetRootLine
‪static array BEgetRootLine($uid, $clause='', $workspaceOL=false, array $additionalFields=[])
Definition: BackendUtility.php:343
‪TYPO3\CMS\Core\Versioning\VersionState\MOVE_POINTER
‪const MOVE_POINTER
Definition: VersionState.php:73
‪TYPO3\CMS\Core\Type\Bitmask\Permission
Definition: Permission.php:24
‪TYPO3\CMS\Backend\Tree\Repository
Definition: PageTreeRepository.php:18
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\findInPageTree
‪array findInPageTree(int $pageId, array $pages)
Definition: PageTreeRepository.php:484
‪TYPO3\CMS\Core\Database\Query\QueryHelper
Definition: QueryHelper.php:32
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\groupAndSortPages
‪array groupAndSortPages(array $pages, $groupedAndSortedPagesByPid=[])
Definition: PageTreeRepository.php:735
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\addChildrenToPage
‪addChildrenToPage(array &$page, array &$groupedAndSortedPagesByPid)
Definition: PageTreeRepository.php:468
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\getPageRecords
‪array getPageRecords(array $pageIds=[], array $parentPageIds=[])
Definition: PageTreeRepository.php:210
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Core\Type\Bitmask\Permission\PAGE_SHOW
‪const PAGE_SHOW
Definition: Permission.php:33
‪TYPO3\CMS\Backend\Utility\BackendUtility
Definition: BackendUtility.php:75
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\getBackendUser
‪BackendUserAuthentication getBackendUser()
Definition: PageTreeRepository.php:757
‪TYPO3\CMS\Backend\Utility\BackendUtility\getRecord
‪static array null getRecord($table, $uid, $fields=' *', $where='', $useDeleteClause=true)
Definition: BackendUtility.php:95
‪TYPO3\CMS\Core\Versioning\VersionState
Definition: VersionState.php:24
‪TYPO3\CMS\Core\Database\Query\QueryHelper\stripLogicalOperatorPrefix
‪static string stripLogicalOperatorPrefix(string $constraint)
Definition: QueryHelper.php:165
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:28
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository
Definition: PageTreeRepository.php:41
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\getChildPageRecords
‪getChildPageRecords(array $parentPageIds)
Definition: PageTreeRepository.php:198
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\getTree
‪array getTree(int $entryPoint, callable $callback=null, array $dbMounts=[], $resolveUserPermissions=false)
Definition: PageTreeRepository.php:126
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\__construct
‪__construct(int $workspaceId=0, array $additionalFieldsToQuery=[], array $additionalQueryRestrictions=[])
Definition: PageTreeRepository.php:104
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Backend\Tree\Repository\PageTreeRepository\applyCallbackToChildren
‪applyCallbackToChildren(array &$tree, callable $callback)
Definition: PageTreeRepository.php:150
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\isInWebMount
‪int null isInWebMount($idOrRow, $readPerms='', $exitOnError=0)
Definition: BackendUserAuthentication.php:352
‪TYPO3\CMS\Core\Versioning\VersionState\MOVE_PLACEHOLDER
‪const MOVE_PLACEHOLDER
Definition: VersionState.php:72
‪TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction
Definition: WorkspaceRestriction.php:39