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