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