‪TYPO3CMS  10.4
PageRepository.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\Log\LoggerAwareInterface;
19 use Psr\Log\LoggerAwareTrait;
42 
51 class ‪PageRepository implements LoggerAwareInterface
52 {
53  use LoggerAwareTrait;
54 
62  public ‪$where_hid_del = ' AND pages.deleted=0';
63 
69  public ‪$where_groupAccess = '';
70 
76  protected ‪$sys_language_uid = 0;
77 
87  protected ‪$versioningWorkspaceId = 0;
88 
94  protected ‪$computedPropertyNames = [
95  '_LOCALIZED_UID',
96  '_MP_PARAM',
97  '_ORIG_uid',
98  '_ORIG_pid',
99  '_PAGES_OVERLAY',
100  '_PAGES_OVERLAY_UID',
101  '_PAGES_OVERLAY_LANGUAGE',
102  '_PAGES_OVERLAY_REQUESTEDLANGUAGE',
103  ];
104 
109  const ‪DOKTYPE_LINK = 3;
111  const ‪DOKTYPE_BE_USER_SECTION = 6;
112  const ‪DOKTYPE_MOUNTPOINT = 7;
113  const ‪DOKTYPE_SPACER = 199;
114  const ‪DOKTYPE_SYSFOLDER = 254;
115  const ‪DOKTYPE_RECYCLER = 255;
116 
120  const ‪SHORTCUT_MODE_NONE = 0;
124 
128  protected ‪$context;
129 
136  public function ‪__construct(‪Context ‪$context = null)
137  {
138  $this->context = ‪$context ?? GeneralUtility::makeInstance(Context::class);
139  $this->versioningWorkspaceId = $this->context->getPropertyFromAspect('workspace', 'id');
140  // Only set up the where clauses for pages when TCA is set. This usually happens only in tests.
141  // Once all tests are written very well, this can be removed again
142  if (isset(‪$GLOBALS['TCA']['pages'])) {
143  $this->‪init($this->context->getPropertyFromAspect('visibility', 'includeHiddenPages'));
144  $this->where_groupAccess = $this->‪getMultipleGroupsWhereClause('pages.fe_group', 'pages');
145  $this->sys_language_uid = (int)$this->context->getPropertyFromAspect('language', 'id', 0);
146  }
147  }
148 
158  protected function ‪init($show_hidden)
159  {
160  $this->where_groupAccess = '';
161  // As PageRepository may be used multiple times during the frontend request, and may
162  // actually be used before the usergroups have been resolved, self::getMultipleGroupsWhereClause()
163  // and the hook in ->enableFields() need to be reconsidered when the usergroup state changes.
164  // When something changes in the context, a second runtime cache entry is built.
165  // However, the PageRepository is generally in use for generating e.g. hundreds of links, so they would all use
166  // the same cache identifier.
167  $userAspect = $this->context->getAspect('frontend.user');
168  $frontendUserIdentifier = 'user_' . (int)$userAspect->get('id') . '_groups_' . md5(implode(',', $userAspect->getGroupIds()));
169 
170  // We need to respect the date aspect as we might have subrequests with a different time (e.g. backend preview links)
171  $dateTimeIdentifier = $this->context->getAspect('date')->get('timestamp');
172 
173  $cache = $this->‪getRuntimeCache();
174  $cacheIdentifier = 'PageRepository_hidDelWhere' . ($show_hidden ? 'ShowHidden' : '') . '_' . (int)$this->versioningWorkspaceId . '_' . $frontendUserIdentifier . '_' . $dateTimeIdentifier;
175  $cacheEntry = $cache->get($cacheIdentifier);
176  if ($cacheEntry) {
177  $this->where_hid_del = $cacheEntry;
178  } else {
179  $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
180  ->getQueryBuilderForTable('pages')
181  ->expr();
182  if ($this->versioningWorkspaceId > 0) {
183  // For version previewing, make sure that enable-fields are not
184  // de-selecting hidden pages - we need versionOL() to unset them only
185  // if the overlay record instructs us to.
186  // Clear where_hid_del and restrict to live and current workspaces
187  $this->where_hid_del = ' AND ' . $expressionBuilder->andX(
188  $expressionBuilder->eq('pages.deleted', 0),
189  $expressionBuilder->orX(
190  $expressionBuilder->eq('pages.t3ver_wsid', 0),
191  $expressionBuilder->eq('pages.t3ver_wsid', (int)$this->versioningWorkspaceId)
192  ),
193  $expressionBuilder->neq('pages.doktype', self::DOKTYPE_RECYCLER)
194  );
195  } else {
196  // add starttime / endtime, and check for hidden/deleted
197  // Filter out new/deleted place-holder pages in case we are NOT in a
198  // versioning preview (that means we are online!)
199  $this->where_hid_del = ' AND ' . (string)$expressionBuilder->andX(
201  $this->enableFields('pages', (int)$show_hidden, ['fe_group' => true])
202  ),
203  $expressionBuilder->neq('pages.doktype', self::DOKTYPE_RECYCLER)
204  );
205  }
206  $cache->set($cacheIdentifier, $this->where_hid_del);
207  }
208 
209  if (is_array(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class]['init'] ?? false)) {
210  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class]['init'] as $classRef) {
211  $hookObject = GeneralUtility::makeInstance($classRef);
212  if (!$hookObject instanceof PageRepositoryInitHookInterface) {
213  throw new \UnexpectedValueException($classRef . ' must implement interface ' . PageRepositoryInitHookInterface::class, 1379579812);
214  }
215  $hookObject->init_postProcess($this);
216  }
217  }
218  }
219 
220  /**************************
221  *
222  * Selecting page records
223  *
224  **************************/
225 
254  public function ‪getPage($uid, $disableGroupAccessCheck = false)
255  {
256  // Hook to manipulate the page uid for special overlay handling
257  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPage'] ?? [] as $className) {
258  $hookObject = GeneralUtility::makeInstance($className);
259  if (!$hookObject instanceof PageRepositoryGetPageHookInterface) {
260  throw new \UnexpectedValueException($className . ' must implement interface ' . PageRepositoryGetPageHookInterface::class, 1251476766);
261  }
262  $hookObject->getPage_preProcess($uid, $disableGroupAccessCheck, $this);
263  }
264  $cacheIdentifier = 'PageRepository_getPage_' . md5(
265  implode(
266  '-',
267  [
268  $uid,
269  $disableGroupAccessCheck ? '' : $this->where_groupAccess,
270  $this->where_hid_del,
271  $this->sys_language_uid
272  ]
273  )
274  );
275  $cache = $this->‪getRuntimeCache();
276  $cacheEntry = $cache->get($cacheIdentifier);
277  if (is_array($cacheEntry)) {
278  return $cacheEntry;
279  }
280  $result = [];
281  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
282  $queryBuilder->getRestrictions()->removeAll();
283  $queryBuilder->select('*')
284  ->from('pages')
285  ->where(
286  $queryBuilder->expr()->eq('uid', (int)$uid),
287  ‪QueryHelper::stripLogicalOperatorPrefix($this->where_hid_del)
288  );
289 
290  $originalWhereGroupAccess = '';
291  if (!$disableGroupAccessCheck) {
292  $queryBuilder->andWhere(‪QueryHelper::stripLogicalOperatorPrefix($this->where_groupAccess));
293  } else {
294  $originalWhereGroupAccess = ‪$this->where_groupAccess;
295  $this->where_groupAccess = '';
296  }
297 
298  $row = $queryBuilder->execute()->fetch();
299  if ($row) {
300  $this->‪versionOL('pages', $row);
301  if (is_array($row)) {
302  $result = $this->‪getPageOverlay($row);
303  }
304  }
305 
306  if ($disableGroupAccessCheck) {
307  $this->where_groupAccess = $originalWhereGroupAccess;
308  }
309 
310  $cache->set($cacheIdentifier, $result);
311  return $result;
312  }
313 
322  public function ‪getPage_noCheck($uid)
323  {
324  $cache = $this->‪getRuntimeCache();
325  $cacheIdentifier = 'PageRepository_getPage_noCheck_' . $uid . '_' . $this->sys_language_uid . '_' . ‪$this->versioningWorkspaceId;
326  $cacheEntry = $cache->get($cacheIdentifier);
327  if ($cacheEntry !== false) {
328  return $cacheEntry;
329  }
330 
331  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
332  $queryBuilder->getRestrictions()
333  ->removeAll()
334  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
335  $row = $queryBuilder->select('*')
336  ->from('pages')
337  ->where($queryBuilder->expr()->eq('uid', (int)$uid))
338  ->execute()
339  ->fetch();
340 
341  $result = [];
342  if ($row) {
343  $this->‪versionOL('pages', $row);
344  if (is_array($row)) {
345  $result = $this->‪getPageOverlay($row);
346  }
347  }
348  $cache->set($cacheIdentifier, $result);
349  return $result;
350  }
351 
362  public function ‪getLanguageOverlay(string $table, array $row)
363  {
364  // table is not localizable, so return directly
365  if (!isset(‪$GLOBALS['TCA'][$table]['ctrl']['languageField'])) {
366  return $row;
367  }
368  try {
370  $languageAspect = $this->context->getAspect('language');
371  if ($languageAspect->doOverlays()) {
372  if ($table === 'pages') {
373  return $this->‪getPageOverlay($row, $languageAspect->getId());
374  }
375  return $this->‪getRecordOverlay(
376  $table,
377  $row,
378  $languageAspect->getContentId(),
379  $languageAspect->getOverlayType() === $languageAspect::OVERLAYS_MIXED ? '1' : 'hideNonTranslated'
380  );
381  }
382  } catch (AspectNotFoundException $e) {
383  // no overlays
384  }
385  return $row;
386  }
387 
396  public function ‪getPageOverlay($pageInput, $languageUid = null)
397  {
398  $rows = $this->‪getPagesOverlay([$pageInput], $languageUid);
399  // Always an array in return
400  return $rows[0] ?? [];
401  }
402 
414  public function ‪getPagesOverlay(array $pagesInput, $languageUid = null)
415  {
416  if (empty($pagesInput)) {
417  return [];
418  }
419  if ($languageUid === null) {
420  $languageUid = ‪$this->sys_language_uid;
421  }
422  foreach ($pagesInput as &$origPage) {
423  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPageOverlay'] ?? [] as $className) {
424  $hookObject = GeneralUtility::makeInstance($className);
425  if (!$hookObject instanceof PageRepositoryGetPageOverlayHookInterface) {
426  throw new \UnexpectedValueException($className . ' must implement interface ' . PageRepositoryGetPageOverlayHookInterface::class, 1269878881);
427  }
428  $hookObject->getPageOverlay_preProcess($origPage, $languageUid, $this);
429  }
430  }
431  unset($origPage);
432 
433  $overlays = [];
434  // If language UID is different from zero, do overlay:
435  if ($languageUid) {
436  $languageUids = array_merge([$languageUid], $this->‪getLanguageFallbackChain(null));
437 
438  $pageIds = [];
439  foreach ($pagesInput as $origPage) {
440  if (is_array($origPage)) {
441  // Was the whole record
442  $pageIds[] = (int)$origPage['uid'];
443  } else {
444  // Was the id
445  $pageIds[] = (int)$origPage;
446  }
447  }
448  $overlays = $this->‪getPageOverlaysForLanguageUids($pageIds, $languageUids);
449  }
450 
451  // Create output:
452  $pagesOutput = [];
453  foreach ($pagesInput as $key => $origPage) {
454  if (is_array($origPage)) {
455  $pagesOutput[$key] = $origPage;
456  if (isset($overlays[$origPage['uid']])) {
457  // Overwrite the original field with the overlay
458  foreach ($overlays[$origPage['uid']] as $fieldName => $fieldValue) {
459  if ($fieldName !== 'uid' && $fieldName !== 'pid') {
460  $pagesOutput[$key][$fieldName] = $fieldValue;
461  }
462  }
463  }
464  } else {
465  if (isset($overlays[$origPage])) {
466  $pagesOutput[$key] = $overlays[$origPage];
467  }
468  }
469  }
470  return $pagesOutput;
471  }
472 
481  public function ‪isPageSuitableForLanguage(array $page, LanguageAspect $languageAspect): bool
482  {
483  $languageUid = $languageAspect->getId();
484  // Checks if the default language version can be shown
485  // Block page is set, if l18n_cfg allows plus: 1) Either default language or 2) another language but NO overlay record set for page!
486  if (GeneralUtility::hideIfDefaultLanguage($page['l18n_cfg']) && (!$languageUid || $languageUid && !$page['_PAGES_OVERLAY'])) {
487  return false;
488  }
489  if ($languageUid > 0 && GeneralUtility::hideIfNotTranslated($page['l18n_cfg'])) {
490  if (!$page['_PAGES_OVERLAY'] || (int)$page['_PAGES_OVERLAY_LANGUAGE'] !== $languageUid) {
491  return false;
492  }
493  } elseif ($languageUid > 0) {
494  $languageUids = array_merge([$languageUid], $this->‪getLanguageFallbackChain($languageAspect));
495  return in_array((int)$page['sys_language_uid'], $languageUids, true);
496  }
497  return true;
498  }
499 
506  protected function ‪getLanguageFallbackChain(?LanguageAspect $languageAspect): array
507  {
508  $languageAspect = $languageAspect ?? $this->context->getAspect('language');
509  return array_filter($languageAspect->getFallbackChain(), ‪function ($item) {
511  });
512  }
513 
527  protected function ‪getPageOverlaysForLanguageUids(array $pageUids, array $languageUids): array
528  {
529  // Remove default language ("0")
530  $languageUids = array_filter($languageUids);
531  $languageField = ‪$GLOBALS['TCA']['pages']['ctrl']['languageField'];
532  $overlays = [];
533 
534  foreach ($pageUids as $pageId) {
535  // Create a map based on the order of values in $languageUids. Those entries reflect the order of the language + fallback chain.
536  // We can't work with database ordering since there is no common SQL clause to order by e.g. [7, 1, 2].
537  $orderedListByLanguages = array_flip($languageUids);
538 
539  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
540  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context));
541  // Because "fe_group" is an exclude field, so it is synced between overlays, the group restriction is removed for language overlays of pages
542  $queryBuilder->getRestrictions()->removeByType(FrontendGroupRestriction::class);
543  $result = $queryBuilder->select('*')
544  ->from('pages')
545  ->where(
546  $queryBuilder->expr()->eq(
547  ‪$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
548  $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
549  ),
550  $queryBuilder->expr()->in(
551  ‪$GLOBALS['TCA']['pages']['ctrl']['languageField'],
552  $queryBuilder->createNamedParameter($languageUids, Connection::PARAM_INT_ARRAY)
553  )
554  )
555  ->execute();
556 
557  // Create a list of rows ordered by values in $languageUids
558  while ($row = $result->fetch()) {
559  $orderedListByLanguages[$row[$languageField]] = $row;
560  }
561 
562  foreach ($orderedListByLanguages as $languageUid => $row) {
563  if (!is_array($row)) {
564  continue;
565  }
566 
567  // Found a result for the current language id
568  $this->‪versionOL('pages', $row);
569  if (is_array($row)) {
570  $row['_PAGES_OVERLAY'] = true;
571  $row['_PAGES_OVERLAY_UID'] = $row['uid'];
572  $row['_PAGES_OVERLAY_LANGUAGE'] = $languageUid;
573  $row['_PAGES_OVERLAY_REQUESTEDLANGUAGE'] = $languageUids[0];
574  // Unset vital fields that are NOT allowed to be overlaid:
575  unset($row['uid'], $row['pid']);
576  $overlays[$pageId] = $row;
577 
578  // Language fallback found, stop querying further languages
579  break;
580  }
581  }
582  }
583 
584  return $overlays;
585  }
586 
598  public function ‪getRecordOverlay($table, $row, $sys_language_content, $OLmode = '')
599  {
600  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'] ?? [] as $className) {
601  $hookObject = GeneralUtility::makeInstance($className);
602  if (!$hookObject instanceof PageRepositoryGetRecordOverlayHookInterface) {
603  throw new \UnexpectedValueException($className . ' must implement interface ' . PageRepositoryGetRecordOverlayHookInterface::class, 1269881658);
604  }
605  $hookObject->getRecordOverlay_preProcess($table, $row, $sys_language_content, $OLmode, $this);
606  }
607 
608  $tableControl = ‪$GLOBALS['TCA'][$table]['ctrl'] ?? [];
609 
610  if (!empty($tableControl['languageField'])
611  // Return record for ALL languages untouched
612  // TODO: Fix call stack to prevent this situation in the first place
613  && (int)$row[$tableControl['languageField']] !== -1
614  && !empty($tableControl['transOrigPointerField'])
615  && $row['uid'] > 0
616  && ($row['pid'] > 0 || in_array($tableControl['rootLevel'] ?? false, [true, 1, -1], true))) {
617  // Will try to overlay a record only if the sys_language_content value is larger than zero.
618  if ($sys_language_content > 0) {
619  // Must be default language, otherwise no overlaying
620  if ((int)$row[$tableControl['languageField']] === 0) {
621  // Select overlay record:
622  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
623  ->getQueryBuilderForTable($table);
624  $queryBuilder->setRestrictions(
625  GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context)
626  );
627  if ($this->versioningWorkspaceId > 0) {
628  // If not in live workspace, remove query based "enable fields" checks, it will be done in versionOL()
629  // @see functional workspace test createLocalizedNotHiddenWorkspaceContentHiddenInLive()
630  $queryBuilder->getRestrictions()->removeByType(HiddenRestriction::class);
631  $queryBuilder->getRestrictions()->removeByType(StartTimeRestriction::class);
632  $queryBuilder->getRestrictions()->removeByType(EndTimeRestriction::class);
633  }
634  $olrow = $queryBuilder->select('*')
635  ->from($table)
636  ->where(
637  $queryBuilder->expr()->eq(
638  'pid',
639  $queryBuilder->createNamedParameter($row['pid'], \PDO::PARAM_INT)
640  ),
641  $queryBuilder->expr()->eq(
642  $tableControl['languageField'],
643  $queryBuilder->createNamedParameter($sys_language_content, \PDO::PARAM_INT)
644  ),
645  $queryBuilder->expr()->eq(
646  $tableControl['transOrigPointerField'],
647  $queryBuilder->createNamedParameter($row['uid'], \PDO::PARAM_INT)
648  )
649  )
650  ->setMaxResults(1)
651  ->execute()
652  ->fetch();
653 
654  $this->‪versionOL($table, $olrow);
655  // Merge record content by traversing all fields:
656  if (is_array($olrow)) {
657  if (isset($olrow['_ORIG_uid'])) {
658  $row['_ORIG_uid'] = $olrow['_ORIG_uid'];
659  }
660  if (isset($olrow['_ORIG_pid'])) {
661  $row['_ORIG_pid'] = $olrow['_ORIG_pid'];
662  }
663  foreach ($row as $fN => $fV) {
664  if ($fN !== 'uid' && $fN !== 'pid' && array_key_exists($fN, $olrow)) {
665  $row[$fN] = $olrow[$fN];
666  } elseif ($fN === 'uid') {
667  $row['_LOCALIZED_UID'] = $olrow['uid'];
668  }
669  }
670  } elseif ($OLmode === 'hideNonTranslated' && (int)$row[$tableControl['languageField']] === 0) {
671  // Unset, if non-translated records should be hidden. ONLY done if the source
672  // record really is default language and not [All] in which case it is allowed.
673  $row = null;
674  }
675  } elseif ($sys_language_content != $row[$tableControl['languageField']]) {
676  $row = null;
677  }
678  } else {
679  // When default language is displayed, we never want to return a record carrying
680  // another language!
681  if ($row[$tableControl['languageField']] > 0) {
682  $row = null;
683  }
684  }
685  }
686 
687  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'] ?? [] as $className) {
688  $hookObject = GeneralUtility::makeInstance($className);
689  if (!$hookObject instanceof PageRepositoryGetRecordOverlayHookInterface) {
690  throw new \UnexpectedValueException($className . ' must implement interface ' . PageRepositoryGetRecordOverlayHookInterface::class, 1269881659);
691  }
692  $hookObject->getRecordOverlay_postProcess($table, $row, $sys_language_content, $OLmode, $this);
693  }
694 
695  return $row;
696  }
697 
698  /************************************************
699  *
700  * Page related: Menu, Domain record, Root line
701  *
702  ************************************************/
703 
721  public function ‪getMenu($pageId, ‪$fields = '*', $sortField = 'sorting', $additionalWhereClause = '', $checkShortcuts = true)
722  {
723  return $this->‪getSubpagesForPages((array)$pageId, ‪$fields, $sortField, $additionalWhereClause, $checkShortcuts);
724  }
725 
740  public function ‪getMenuForPages(array $pageIds, ‪$fields = '*', $sortField = 'sorting', $additionalWhereClause = '', $checkShortcuts = true)
741  {
742  return $this->‪getSubpagesForPages($pageIds, ‪$fields, $sortField, $additionalWhereClause, $checkShortcuts, false);
743  }
744 
781  protected function ‪getSubpagesForPages(
782  array $pageIds,
783  string ‪$fields = '*',
784  string $sortField = 'sorting',
785  string $additionalWhereClause = '',
786  bool $checkShortcuts = true,
787  bool $parentPages = true
788  ): array {
789  $relationField = $parentPages ? 'pid' : 'uid';
790  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
791  $queryBuilder->getRestrictions()
792  ->removeAll()
793  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, $this->versioningWorkspaceId));
794 
795  $res = $queryBuilder->select(...‪GeneralUtility::trimExplode(',', ‪$fields, true))
796  ->from('pages')
797  ->where(
798  $queryBuilder->expr()->in(
799  $relationField,
800  $queryBuilder->createNamedParameter($pageIds, Connection::PARAM_INT_ARRAY)
801  ),
802  $queryBuilder->expr()->eq(
803  ‪$GLOBALS['TCA']['pages']['ctrl']['languageField'],
804  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
805  ),
806  ‪QueryHelper::stripLogicalOperatorPrefix($this->where_hid_del),
807  ‪QueryHelper::stripLogicalOperatorPrefix($this->where_groupAccess),
808  ‪QueryHelper::stripLogicalOperatorPrefix($additionalWhereClause)
809  );
810 
811  if (!empty($sortField)) {
812  $orderBy = ‪QueryHelper::parseOrderBy($sortField);
813  foreach ($orderBy as $order) {
814  $res->addOrderBy($order[0], $order[1] ?? 'ASC');
815  }
816  }
817  $result = $res->execute();
818 
819  $pages = [];
820  while ($page = $result->fetch()) {
821  $originalUid = $page['uid'];
822 
823  // Versioning Preview Overlay
824  $this->‪versionOL('pages', $page, true);
825  // Skip if page got disabled due to version overlay
826  // (might be delete or move placeholder)
827  if (empty($page)) {
828  continue;
829  }
830 
831  // Add a mount point parameter if needed
832  $page = $this->‪addMountPointParameterToPage((array)$page);
833 
834  // If shortcut, look up if the target exists and is currently visible
835  if ($checkShortcuts) {
836  $page = $this->‪checkValidShortcutOfPage((array)$page, $additionalWhereClause);
837  }
838 
839  // If the page still is there, we add it to the output
840  if (!empty($page)) {
841  $pages[$originalUid] = $page;
842  }
843  }
844 
845  // Finally load language overlays
846  return $this->‪getPagesOverlay($pages);
847  }
848 
864  protected function ‪addMountPointParameterToPage(array $page): array
865  {
866  if (empty($page)) {
867  return [];
868  }
869 
870  // $page MUST have "uid", "pid", "doktype", "mount_pid", "mount_pid_ol" fields in it
871  $mountPointInfo = $this->‪getMountPointInfo($page['uid'], $page);
872 
873  // There is a valid mount point in overlay mode.
874  if (is_array($mountPointInfo) && $mountPointInfo['overlay']) {
875 
876  // Using "getPage" is OK since we need the check for enableFields AND for type 2
877  // of mount pids we DO require a doktype < 200!
878  $mountPointPage = $this->‪getPage($mountPointInfo['mount_pid']);
879 
880  if (!empty($mountPointPage)) {
881  $page = $mountPointPage;
882  $page['_MP_PARAM'] = $mountPointInfo['MPvar'];
883  } else {
884  $page = [];
885  }
886  }
887  return $page;
888  }
889 
897  protected function ‪checkValidShortcutOfPage(array $page, $additionalWhereClause)
898  {
899  if (empty($page)) {
900  return [];
901  }
902 
903  $dokType = (int)$page['doktype'];
904  $shortcutMode = (int)$page['shortcut_mode'];
905 
906  if ($dokType === self::DOKTYPE_SHORTCUT && ($page['shortcut'] || $shortcutMode)) {
907  if ($shortcutMode === self::SHORTCUT_MODE_NONE) {
908  // No shortcut_mode set, so target is directly set in $page['shortcut']
909  $searchField = 'uid';
910  $searchUid = (int)$page['shortcut'];
911  } elseif ($shortcutMode === self::SHORTCUT_MODE_FIRST_SUBPAGE || $shortcutMode === self::SHORTCUT_MODE_RANDOM_SUBPAGE) {
912  // Check subpages - first subpage or random subpage
913  $searchField = 'pid';
914  // If a shortcut mode is set and no valid page is given to select subpages
915  // from use the actual page.
916  $searchUid = (int)$page['shortcut'] ?: $page['uid'];
917  } elseif ($shortcutMode === self::SHORTCUT_MODE_PARENT_PAGE) {
918  // Shortcut to parent page
919  $searchField = 'uid';
920  $searchUid = $page['pid'];
921  } else {
922  $searchField = '';
923  $searchUid = 0;
924  }
925 
926  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
927  $queryBuilder->getRestrictions()->removeAll();
928  $count = $queryBuilder->count('uid')
929  ->from('pages')
930  ->where(
931  $queryBuilder->expr()->eq(
932  $searchField,
933  $queryBuilder->createNamedParameter($searchUid, \PDO::PARAM_INT)
934  ),
935  ‪QueryHelper::stripLogicalOperatorPrefix($this->where_hid_del),
936  ‪QueryHelper::stripLogicalOperatorPrefix($this->where_groupAccess),
937  ‪QueryHelper::stripLogicalOperatorPrefix($additionalWhereClause)
938  )
939  ->execute()
940  ->fetchColumn();
941 
942  if (!$count) {
943  $page = [];
944  }
945  } elseif ($dokType === self::DOKTYPE_SHORTCUT) {
946  // Neither shortcut target nor mode is set. Remove the page from the menu.
947  $page = [];
948  }
949  return $page;
950  }
951 
968  public function ‪getPageShortcut($shortcutFieldValue, $shortcutMode, $thisUid, $iteration = 20, $pageLog = [], $disableGroupCheck = false)
969  {
970  $idArray = ‪GeneralUtility::intExplode(',', $shortcutFieldValue);
971  // Find $page record depending on shortcut mode:
972  switch ($shortcutMode) {
975  $excludedDoktypes = [
980  ];
981  $pageArray = $this->‪getMenu($idArray[0] ?: $thisUid, '*', 'sorting', 'AND pages.doktype NOT IN (' . implode(', ', $excludedDoktypes) . ')');
982  $pO = 0;
983  if ($shortcutMode == self::SHORTCUT_MODE_RANDOM_SUBPAGE && !empty($pageArray)) {
984  $pO = (int)random_int(0, count($pageArray) - 1);
985  }
986  $c = 0;
987  $page = [];
988  foreach ($pageArray as $pV) {
989  if ($c === $pO) {
990  $page = $pV;
991  break;
992  }
993  $c++;
994  }
995  if (empty($page)) {
996  $message = 'This page (ID ' . $thisUid . ') is of type "Shortcut" and configured to redirect to a subpage. However, this page has no accessible subpages.';
997  throw new ShortcutTargetPageNotFoundException($message, 1301648328);
998  }
999  break;
1001  $parent = $this->‪getPage($idArray[0] ?: $thisUid, $disableGroupCheck);
1002  $page = $this->‪getPage($parent['pid'], $disableGroupCheck);
1003  if (empty($page)) {
1004  $message = 'This page (ID ' . $thisUid . ') is of type "Shortcut" and configured to redirect to its parent page. However, the parent page is not accessible.';
1005  throw new ShortcutTargetPageNotFoundException($message, 1301648358);
1006  }
1007  break;
1008  default:
1009  $page = $this->‪getPage($idArray[0], $disableGroupCheck);
1010  if (empty($page)) {
1011  $message = 'This page (ID ' . $thisUid . ') is of type "Shortcut" and configured to redirect to a page, which is not accessible (ID ' . $idArray[0] . ').';
1012  throw new ShortcutTargetPageNotFoundException($message, 1301648404);
1013  }
1014  }
1015  // Check if short cut page was a shortcut itself, if so look up recursively:
1016  if ($page['doktype'] == self::DOKTYPE_SHORTCUT) {
1017  if (!in_array($page['uid'], $pageLog) && $iteration > 0) {
1018  $pageLog[] = $page['uid'];
1019  $page = $this->‪getPageShortcut($page['shortcut'], $page['shortcut_mode'], $page['uid'], $iteration - 1, $pageLog, $disableGroupCheck);
1020  } else {
1021  $pageLog[] = $page['uid'];
1022  $message = 'Page shortcuts were looping in uids ' . implode(',', $pageLog) . '...!';
1023  $this->logger->error($message);
1024  throw new \RuntimeException($message, 1294587212);
1025  }
1026  }
1027  // Return resulting page:
1028  return $page;
1029  }
1030 
1037  public function ‪getExtURL($pagerow)
1038  {
1039  if ((int)$pagerow['doktype'] === self::DOKTYPE_LINK) {
1040  $redirectTo = $pagerow['url'];
1041  $uI = parse_url($redirectTo);
1042  // If relative path, prefix Site URL
1043  // If it's a valid email without protocol, add "mailto:"
1044  if (!($uI['scheme'] ?? false)) {
1045  if (GeneralUtility::validEmail($redirectTo)) {
1046  $redirectTo = 'mailto:' . $redirectTo;
1047  } elseif ($redirectTo[0] !== '/') {
1048  $redirectTo = GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . $redirectTo;
1049  }
1050  }
1051  return $redirectTo;
1052  }
1053  return false;
1054  }
1055 
1088  public function ‪getMountPointInfo($pageId, $pageRec = false, $prevMountPids = [], $firstPageUid = 0)
1089  {
1090  if (!‪$GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) {
1091  return false;
1092  }
1093  $cacheIdentifier = 'PageRepository_getMountPointInfo_' . $pageId;
1094  $cache = $this->‪getRuntimeCache();
1095  if ($cache->has($cacheIdentifier)) {
1096  return $cache->get($cacheIdentifier);
1097  }
1098  $result = false;
1099  // Get pageRec if not supplied:
1100  if (!is_array($pageRec)) {
1101  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
1102  $queryBuilder->getRestrictions()
1103  ->removeAll()
1104  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1105 
1106  $pageRec = $queryBuilder->select('uid', 'pid', 'doktype', 'mount_pid', 'mount_pid_ol', 't3ver_state', 'l10n_parent')
1107  ->from('pages')
1108  ->where(
1109  $queryBuilder->expr()->eq(
1110  'uid',
1111  $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
1112  ),
1113  $queryBuilder->expr()->neq(
1114  'doktype',
1115  $queryBuilder->createNamedParameter(self::DOKTYPE_RECYCLER, \PDO::PARAM_INT)
1116  )
1117  )
1118  ->execute()
1119  ->fetch();
1120 
1121  // Only look for version overlay if page record is not supplied; This assumes
1122  // that the input record is overlaid with preview version, if any!
1123  $this->‪versionOL('pages', $pageRec);
1124  }
1125  // Set first Page uid:
1126  if (!$firstPageUid) {
1127  $firstPageUid = (int)($pageRec['l10n_parent'] ?: $pageRec['uid']);
1128  }
1129  // Look for mount pid value plus other required circumstances:
1130  $mount_pid = (int)$pageRec['mount_pid'];
1131  if (is_array($pageRec) && (int)$pageRec['doktype'] === self::DOKTYPE_MOUNTPOINT && $mount_pid > 0 && !in_array($mount_pid, $prevMountPids, true)) {
1132  // Get the mount point record (to verify its general existence):
1133  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
1134  $queryBuilder->getRestrictions()
1135  ->removeAll()
1136  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1137 
1138  $mountRec = $queryBuilder->select('uid', 'pid', 'doktype', 'mount_pid', 'mount_pid_ol', 't3ver_state', 'l10n_parent')
1139  ->from('pages')
1140  ->where(
1141  $queryBuilder->expr()->eq(
1142  'uid',
1143  $queryBuilder->createNamedParameter($mount_pid, \PDO::PARAM_INT)
1144  ),
1145  $queryBuilder->expr()->neq(
1146  'doktype',
1147  $queryBuilder->createNamedParameter(self::DOKTYPE_RECYCLER, \PDO::PARAM_INT)
1148  )
1149  )
1150  ->execute()
1151  ->fetch();
1152 
1153  $this->‪versionOL('pages', $mountRec);
1154  if (is_array($mountRec)) {
1155  // Look for recursive mount point:
1156  $prevMountPids[] = $mount_pid;
1157  $recursiveMountPid = $this->‪getMountPointInfo($mount_pid, $mountRec, $prevMountPids, $firstPageUid);
1158  // Return mount point information:
1159  $result = $recursiveMountPid ?: [
1160  'mount_pid' => $mount_pid,
1161  'overlay' => $pageRec['mount_pid_ol'],
1162  'MPvar' => $mount_pid . '-' . $firstPageUid,
1163  'mount_point_rec' => $pageRec,
1164  'mount_pid_rec' => $mountRec
1165  ];
1166  } else {
1167  // Means, there SHOULD have been a mount point, but there was none!
1168  $result = -1;
1169  }
1170  }
1171  $cache->set($cacheIdentifier, $result);
1172  return $result;
1173  }
1174 
1183  public function ‪filterAccessiblePageIds(array $pageIds, QueryRestrictionContainerInterface $restrictionContainer = null): array
1184  {
1185  if ($pageIds === []) {
1186  return [];
1187  }
1188  $validPageIds = [];
1189  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
1190  if ($restrictionContainer instanceof QueryRestrictionContainerInterface) {
1191  $queryBuilder->setRestrictions($restrictionContainer);
1192  } else {
1193  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context));
1194  }
1195  $statement = $queryBuilder->select('uid')
1196  ->from('pages')
1197  ->where(
1198  $queryBuilder->expr()->in(
1199  'uid',
1200  $queryBuilder->createNamedParameter($pageIds, Connection::PARAM_INT_ARRAY)
1201  )
1202  )
1203  ->execute();
1204  while ($row = $statement->fetch()) {
1205  $validPageIds[] = (int)$row['uid'];
1206  }
1207  return $validPageIds;
1208  }
1209  /********************************
1210  *
1211  * Selecting records in general
1212  *
1213  ********************************/
1214 
1224  public function ‪checkRecord($table, $uid, $checkPage = 0)
1225  {
1226  $uid = (int)$uid;
1227  if (is_array(‪$GLOBALS['TCA'][$table]) && $uid > 0) {
1228  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1229  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context));
1230  $row = $queryBuilder->select('*')
1231  ->from($table)
1232  ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)))
1233  ->execute()
1234  ->fetch();
1235 
1236  if ($row) {
1237  $this->‪versionOL($table, $row);
1238  if (is_array($row)) {
1239  if ($checkPage) {
1240  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1241  ->getQueryBuilderForTable('pages');
1242  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context));
1243  $numRows = (int)$queryBuilder->count('*')
1244  ->from('pages')
1245  ->where(
1246  $queryBuilder->expr()->eq(
1247  'uid',
1248  $queryBuilder->createNamedParameter($row['pid'], \PDO::PARAM_INT)
1249  )
1250  )
1251  ->execute()
1252  ->fetchColumn();
1253  if ($numRows > 0) {
1254  return $row;
1255  }
1256  return 0;
1257  }
1258  return $row;
1259  }
1260  }
1261  }
1262  return 0;
1263  }
1264 
1275  public function ‪getRawRecord($table, $uid, ‪$fields = '*')
1276  {
1277  $uid = (int)$uid;
1278  if (isset(‪$GLOBALS['TCA'][$table]) && is_array(‪$GLOBALS['TCA'][$table]) && $uid > 0) {
1279  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1280  $queryBuilder->getRestrictions()
1281  ->removeAll()
1282  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1283  $row = $queryBuilder->select(...‪GeneralUtility::trimExplode(',', ‪$fields, true))
1284  ->from($table)
1285  ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)))
1286  ->execute()
1287  ->fetch();
1288 
1289  if ($row) {
1290  $this->‪versionOL($table, $row);
1291  if (is_array($row)) {
1292  return $row;
1293  }
1294  }
1295  }
1296  return 0;
1297  }
1298 
1299  /********************************
1300  *
1301  * Standard clauses
1302  *
1303  ********************************/
1304 
1320  public function ‪enableFields($table, $show_hidden = -1, $ignore_array = [])
1321  {
1322  if ($show_hidden === -1) {
1323  // If show_hidden was not set from outside, use the current context
1324  $show_hidden = (int)$this->context->getPropertyFromAspect('visibility', $table === 'pages' ? 'includeHiddenPages' : 'includeHiddenContent', false);
1325  }
1326  // If show_hidden was not changed during the previous evaluation, do it here.
1327  $ctrl = ‪$GLOBALS['TCA'][$table]['ctrl'] ?? null;
1328  $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1329  ->getQueryBuilderForTable($table)
1330  ->expr();
1331  $constraints = [];
1332  if (is_array($ctrl)) {
1333  // Delete field check:
1334  if ($ctrl['delete']) {
1335  $constraints[] = $expressionBuilder->eq($table . '.' . $ctrl['delete'], 0);
1336  }
1337  if ($this->‪hasTableWorkspaceSupport($table)) {
1338  // this should work exactly as WorkspaceRestriction and WorkspaceRestriction should be used instead
1339  if ($this->versioningWorkspaceId === 0) {
1340  // Filter out placeholder records (new/moved/deleted items)
1341  // in case we are NOT in a versioning preview (that means we are online!)
1342  $constraints[] = $expressionBuilder->lte(
1343  $table . '.t3ver_state',
1344  new VersionState(‪VersionState::DEFAULT_STATE)
1345  );
1346  $constraints[] = $expressionBuilder->eq($table . '.t3ver_wsid', 0);
1347  } else {
1348  // show only records of live and of the current workspace
1349  // in case we are in a versioning preview
1350  $constraints[] = $expressionBuilder->orX(
1351  $expressionBuilder->eq($table . '.t3ver_wsid', 0),
1352  $expressionBuilder->eq($table . '.t3ver_wsid', (int)$this->versioningWorkspaceId)
1353  );
1354  }
1355 
1356  // Filter out versioned records
1357  if (empty($ignore_array['pid'])) {
1358  // Always filter out versioned records that have an "offline" record
1359  $constraints[] = $expressionBuilder->eq($table . '.t3ver_oid', 0);
1360  }
1361  }
1362 
1363  // Enable fields:
1364  if (is_array($ctrl['enablecolumns'])) {
1365  // In case of versioning-preview, enableFields are ignored (checked in
1366  // versionOL())
1367  if ($this->versioningWorkspaceId === 0 || !$this->‪hasTableWorkspaceSupport($table)) {
1368  if (($ctrl['enablecolumns']['disabled'] ?? false) && !$show_hidden && !($ignore_array['disabled'] ?? false)) {
1369  $field = $table . '.' . $ctrl['enablecolumns']['disabled'];
1370  $constraints[] = $expressionBuilder->eq($field, 0);
1371  }
1372  if (($ctrl['enablecolumns']['starttime'] ?? false) && !($ignore_array['starttime'] ?? false)) {
1373  $field = $table . '.' . $ctrl['enablecolumns']['starttime'];
1374  $constraints[] = $expressionBuilder->lte(
1375  $field,
1376  $this->context->getPropertyFromAspect('date', 'accessTime', 0)
1377  );
1378  }
1379  if (($ctrl['enablecolumns']['endtime'] ?? false) && !($ignore_array['endtime'] ?? false)) {
1380  $field = $table . '.' . $ctrl['enablecolumns']['endtime'];
1381  $constraints[] = $expressionBuilder->orX(
1382  $expressionBuilder->eq($field, 0),
1383  $expressionBuilder->gt(
1384  $field,
1385  $this->context->getPropertyFromAspect('date', 'accessTime', 0)
1386  )
1387  );
1388  }
1389  if (($ctrl['enablecolumns']['fe_group'] ?? false) && !($ignore_array['fe_group'] ?? false)) {
1390  $field = $table . '.' . $ctrl['enablecolumns']['fe_group'];
1392  $this->‪getMultipleGroupsWhereClause($field, $table)
1393  );
1394  }
1395  // Call hook functions for additional enableColumns
1396  // It is used by the extension ingmar_accessctrl which enables assigning more
1397  // than one usergroup to content and page records
1398  $_params = [
1399  'table' => $table,
1400  'show_hidden' => $show_hidden,
1401  'ignore_array' => $ignore_array,
1402  'ctrl' => $ctrl
1403  ];
1404  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['addEnableColumns'] ?? [] as $_funcRef) {
1406  GeneralUtility::callUserFunction($_funcRef, $_params, $this)
1407  );
1408  }
1409  }
1410  }
1411  } else {
1412  throw new \InvalidArgumentException('There is no entry in the $TCA array for the table "' . $table . '". This means that the function enableFields() is called with an invalid table name as argument.', 1283790586);
1413  }
1414 
1415  return empty($constraints) ? '' : ' AND ' . $expressionBuilder->andX(...$constraints);
1416  }
1417 
1427  public function ‪getMultipleGroupsWhereClause($field, $table)
1428  {
1429  if (!$this->context->hasAspect('frontend.user')) {
1430  return '';
1431  }
1433  $userAspect = $this->context->getAspect('frontend.user');
1434  $memberGroups = $userAspect->getGroupIds();
1435  $cache = $this->‪getRuntimeCache();
1436  $cacheIdentifier = 'PageRepository_groupAccessWhere_' . md5($field . '_' . $table . '_' . implode('_', $memberGroups));
1437  $cacheEntry = $cache->get($cacheIdentifier);
1438  if ($cacheEntry) {
1439  return $cacheEntry;
1440  }
1441 
1442  $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1443  ->getQueryBuilderForTable($table)
1444  ->expr();
1445  $orChecks = [];
1446  // If the field is empty, then OK
1447  $orChecks[] = $expressionBuilder->eq($field, $expressionBuilder->literal(''));
1448  // If the field is NULL, then OK
1449  $orChecks[] = $expressionBuilder->isNull($field);
1450  // If the field contains zero, then OK
1451  $orChecks[] = $expressionBuilder->eq($field, $expressionBuilder->literal('0'));
1452  foreach ($memberGroups as $value) {
1453  $orChecks[] = $expressionBuilder->inSet($field, $expressionBuilder->literal($value));
1454  }
1455 
1456  $accessGroupWhere = ' AND (' . $expressionBuilder->orX(...$orChecks) . ')';
1457  $cache->set($cacheIdentifier, $accessGroupWhere);
1458  return $accessGroupWhere;
1459  }
1460 
1461  /**********************
1462  *
1463  * Versioning Preview
1464  *
1465  **********************/
1466 
1490  public function ‪fixVersioningPid($table, &$rr)
1491  {
1492  if ($this->versioningWorkspaceId <= 0) {
1493  return;
1494  }
1495  if (!is_array($rr)) {
1496  return;
1497  }
1498  if (!$this->‪hasTableWorkspaceSupport($table)) {
1499  return;
1500  }
1501  $uid = (int)$rr['uid'];
1502  $oid = 0;
1503  $workspaceId = 0;
1504  $versionState = null;
1505  // Check values for t3ver_oid and t3ver_wsid
1506  if (isset($rr['t3ver_oid']) && isset($rr['t3ver_wsid']) && isset($rr['t3ver_state'])) {
1507  // If "t3ver_oid" is already a field, just set this:
1508  $oid = $rr['t3ver_oid'];
1509  $workspaceId = (int)$rr['t3ver_wsid'];
1510  $versionState = (int)$rr['t3ver_state'];
1511  } elseif ($uid > 0) {
1512  // Otherwise we have to expect "uid" to be in the record and look up based
1513  // on this:
1514  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1515  $queryBuilder->getRestrictions()
1516  ->removeAll()
1517  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1518  $newPidRec = $queryBuilder->select('t3ver_oid', 't3ver_wsid', 't3ver_state')
1519  ->from($table)
1520  ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)))
1521  ->execute()
1522  ->fetch();
1523 
1524  if (is_array($newPidRec)) {
1525  $oid = $newPidRec['t3ver_oid'];
1526  $workspaceId = (int)$newPidRec['t3ver_wsid'];
1527  $versionState = (int)$newPidRec['t3ver_state'];
1528  }
1529  }
1530 
1531  // Workspace does not match, so this is skipped
1532  if ($workspaceId !== (int)‪$this->versioningWorkspaceId) {
1533  return;
1534  }
1535  // Now set the "pid" properly.
1536  // This will only make a difference when handing in move placeholders but is kept for backwards-compat
1537  // however it's always the same for live + versioned record, except for moving, where _ORIG_pid will
1538  // be set to the live PID, and pid to the moved location
1539  if ($oid) {
1540  $rr['_ORIG_pid'] = $rr['pid'];
1541  }
1542  // Changing PID in case there is a move pointer
1543  // This happens if the $uid is still a live version but the overlay happened (via t3ver_oid) and the t3ver_state was
1544  // Changed to MOVE_POINTER. This logic happens in versionOL(), where the "pid" of the live version is kept.
1545  if ($versionState === ‪VersionState::MOVE_POINTER && $movedPageId = $this->‪getMovedPidOfVersionedRecord($table, $uid)) {
1546  $rr['_ORIG_pid'] = $rr['pid'];
1547  $rr['pid'] = $movedPageId;
1548  }
1549  }
1550 
1571  public function ‪versionOL($table, &$row, $unsetMovePointers = false, $bypassEnableFieldsCheck = false)
1572  {
1573  if ($this->versioningWorkspaceId > 0 && is_array($row)) {
1574  // will overlay any movePlhOL found with the real record, which in turn
1575  // will be overlaid with its workspace version if any.
1576  $movePldSwap = $this->‪movePlhOL($table, $row);
1577  // implode(',',array_keys($row)) = Using fields from original record to make
1578  // sure no additional fields are selected. This is best for eg. getPageOverlay()
1579  // Computed properties are excluded since those would lead to SQL errors.
1580  $fieldNames = implode(',', array_keys($this->‪purgeComputedProperties($row)));
1581  if ($wsAlt = $this->‪getWorkspaceVersionOfRecord($this->versioningWorkspaceId, $table, $row['uid'], $fieldNames, $bypassEnableFieldsCheck)) {
1582  if (is_array($wsAlt)) {
1583  // Always fix PID (like in fixVersioningPid() above). [This is usually not
1584  // the important factor for versioning OL]
1585  // Keep the old (-1) - indicates it was a version...
1586  $wsAlt['_ORIG_pid'] = $wsAlt['pid'];
1587  // Set in the online versions PID.
1588  // Side note: For move pointers, this is set back to the PID of the live record now
1589  // The only place where PID is actually different.
1590  $wsAlt['pid'] = $row['pid'];
1591  // For versions of single elements or page+content, preserve online UID and PID
1592  // (this will produce true "overlay" of element _content_, not any references)
1593  // For page+content the "_ORIG_uid" should actually be used as PID for selection.
1594  $wsAlt['_ORIG_uid'] = $wsAlt['uid'];
1595  $wsAlt['uid'] = $row['uid'];
1596  // Changing input record to the workspace version alternative:
1597  $row = $wsAlt;
1598  // Check if it is deleted/new
1599  $rowVersionState = ‪VersionState::cast($row['t3ver_state'] ?? null);
1600  if (
1601  $rowVersionState->equals(‪VersionState::NEW_PLACEHOLDER)
1602  || $rowVersionState->equals(‪VersionState::DELETE_PLACEHOLDER)
1603  ) {
1604  // Unset record if it turned out to be deleted in workspace
1605  $row = false;
1606  }
1607  // Check if move-pointer in workspace (unless if a move-placeholder is the
1608  // reason why it appears!):
1609  // You have to specifically set $unsetMovePointers in order to clear these
1610  // because it is normally a display issue if it should be shown or not.
1611  if (
1612  (
1613  $rowVersionState->equals(‪VersionState::MOVE_POINTER)
1614  && !$movePldSwap
1615  ) && $unsetMovePointers
1616  ) {
1617  // Unset record if it turned out to be deleted in workspace
1618  $row = false;
1619  }
1620  } else {
1621  // No version found, then check if t3ver_state = VersionState::NEW_PLACEHOLDER
1622  // (online version is dummy-representation)
1623  // Notice, that unless $bypassEnableFieldsCheck is TRUE, the $row is unset if
1624  // enablefields for BOTH the version AND the online record deselects it. See
1625  // note for $bypassEnableFieldsCheck
1627  $versionState = ‪VersionState::cast($row['t3ver_state']);
1628  if ($wsAlt <= -1 || $versionState->indicatesPlaceholder()) {
1629  // Unset record if it turned out to be "hidden"
1630  $row = false;
1631  }
1632  }
1633  }
1634  }
1635  }
1636 
1647  protected function ‪movePlhOL($table, &$row)
1648  {
1649  if ($this->‪hasTableWorkspaceSupport($table)
1650  && (int)‪VersionState::cast($row['t3ver_state'])->equals(‪VersionState::MOVE_PLACEHOLDER)
1651  ) {
1652  $moveID = 0;
1653  // If t3ver_move_id is not found, then find it (but we like best if it is here)
1654  if (!isset($row['t3ver_move_id'])) {
1655  if ((int)$row['uid'] > 0) {
1656  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1657  $queryBuilder->getRestrictions()
1658  ->removeAll()
1659  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1660  $moveIDRec = $queryBuilder->select('t3ver_move_id')
1661  ->from($table)
1662  ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($row['uid'], \PDO::PARAM_INT)))
1663  ->execute()
1664  ->fetch();
1665 
1666  if (is_array($moveIDRec)) {
1667  $moveID = $moveIDRec['t3ver_move_id'];
1668  }
1669  }
1670  } else {
1671  $moveID = $row['t3ver_move_id'];
1672  }
1673  // Find pointed-to record.
1674  if ($moveID) {
1675  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1676  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context));
1677  $queryBuilder->getRestrictions()->removeByType(HiddenRestriction::class);
1678  $origRow = $queryBuilder->select(...array_keys($this->‪purgeComputedProperties($row)))
1679  ->from($table)
1680  ->where(
1681  $queryBuilder->expr()->eq(
1682  'uid',
1683  $queryBuilder->createNamedParameter($moveID, \PDO::PARAM_INT)
1684  )
1685  )
1686  ->setMaxResults(1)
1687  ->execute()
1688  ->fetch();
1689 
1690  if ($origRow) {
1691  $row = $origRow;
1692  return true;
1693  }
1694  }
1695  }
1696  return false;
1697  }
1698 
1711  protected function ‪getMovedPidOfVersionedRecord(string $table, int $liveUid): ?int
1712  {
1713  if ($this->versioningWorkspaceId <= 0) {
1714  return null;
1715  }
1716  if (!$this->‪hasTableWorkspaceSupport($table)) {
1717  return null;
1718  }
1719  // Select workspace version of record
1720  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1721  $queryBuilder->getRestrictions()
1722  ->removeAll()
1723  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1724 
1725  $row = $queryBuilder->select('pid')
1726  ->from($table)
1727  ->where(
1728  $queryBuilder->expr()->eq(
1729  't3ver_state',
1730  $queryBuilder->createNamedParameter(
1732  \PDO::PARAM_INT
1733  )
1734  ),
1735  $queryBuilder->expr()->eq(
1736  't3ver_oid',
1737  $queryBuilder->createNamedParameter($liveUid, \PDO::PARAM_INT)
1738  ),
1739  $queryBuilder->expr()->eq(
1740  't3ver_wsid',
1741  $queryBuilder->createNamedParameter($this->versioningWorkspaceId, \PDO::PARAM_INT)
1742  )
1743  )
1744  ->setMaxResults(1)
1745  ->execute()
1746  ->fetch();
1747 
1748  if (is_array($row)) {
1749  return (int)$row['pid'];
1750  }
1751  return null;
1752  }
1753 
1766  public function ‪getWorkspaceVersionOfRecord($workspace, $table, $uid, ‪$fields = '*', $bypassEnableFieldsCheck = false)
1767  {
1768  if ($workspace !== 0 && $this->‪hasTableWorkspaceSupport($table)) {
1769  $workspace = (int)$workspace;
1770  $uid = (int)$uid;
1771  // Select workspace version of record, only testing for deleted.
1772  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1773  $queryBuilder->getRestrictions()
1774  ->removeAll()
1775  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1776 
1777  $newrow = $queryBuilder->select(...‪GeneralUtility::trimExplode(',', ‪$fields, true))
1778  ->from($table)
1779  ->where(
1780  $queryBuilder->expr()->eq(
1781  't3ver_oid',
1782  $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
1783  ),
1784  $queryBuilder->expr()->eq(
1785  't3ver_wsid',
1786  $queryBuilder->createNamedParameter($workspace, \PDO::PARAM_INT)
1787  )
1788  )
1789  ->setMaxResults(1)
1790  ->execute()
1791  ->fetch();
1792 
1793  // If version found, check if it could have been selected with enableFields on
1794  // as well:
1795  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1796  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context));
1797  // Remove the frontend workspace restriction because we are testing a version record
1798  $queryBuilder->getRestrictions()->removeByType(FrontendWorkspaceRestriction::class);
1799  $queryBuilder->select('uid')
1800  ->from($table)
1801  ->setMaxResults(1);
1802 
1803  if (is_array($newrow)) {
1804  $queryBuilder->where(
1805  $queryBuilder->expr()->eq(
1806  't3ver_oid',
1807  $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
1808  ),
1809  $queryBuilder->expr()->eq(
1810  't3ver_wsid',
1811  $queryBuilder->createNamedParameter($workspace, \PDO::PARAM_INT)
1812  )
1813  );
1814  if ($bypassEnableFieldsCheck || $queryBuilder->execute()->fetchColumn()) {
1815  // Return offline version, tested for its enableFields.
1816  return $newrow;
1817  }
1818  // Return -1 because offline version was de-selected due to its enableFields.
1819  return -1;
1820  }
1821  // OK, so no workspace version was found. Then check if online version can be
1822  // selected with full enable fields and if so, return 1:
1823  $queryBuilder->where(
1824  $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
1825  );
1826  if ($bypassEnableFieldsCheck || $queryBuilder->execute()->fetchColumn()) {
1827  // Means search was done, but no version found.
1828  return 1;
1829  }
1830  // Return -2 because the online record was de-selected due to its enableFields.
1831  return -2;
1832  }
1833  // No look up in database because versioning not enabled / or workspace not
1834  // offline
1835  return false;
1836  }
1837 
1845  protected function ‪purgeComputedProperties(array $row)
1846  {
1847  foreach ($this->computedPropertyNames as $computedPropertyName) {
1848  if (array_key_exists($computedPropertyName, $row)) {
1849  unset($row[$computedPropertyName]);
1850  }
1851  }
1852  return $row;
1853  }
1854 
1858  protected function ‪getRuntimeCache(): ‪VariableFrontend
1859  {
1860  return GeneralUtility::makeInstance(CacheManager::class)->getCache('runtime');
1861  }
1862 
1863  protected function ‪hasTableWorkspaceSupport(string $tableName): bool
1864  {
1865  return !empty(‪$GLOBALS['TCA'][$tableName]['ctrl']['versioningWS']);
1866  }
1867 }
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\$versioningWorkspaceId
‪int $versioningWorkspaceId
Definition: PageRepository.php:83
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\isPageSuitableForLanguage
‪bool isPageSuitableForLanguage(array $page, LanguageAspect $languageAspect)
Definition: PageRepository.php:475
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getMultipleGroupsWhereClause
‪string getMultipleGroupsWhereClause($field, $table)
Definition: PageRepository.php:1421
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getLanguageOverlay
‪array null getLanguageOverlay(string $table, array $row)
Definition: PageRepository.php:356
‪TYPO3\CMS\Core\Database\Query\QueryHelper\parseOrderBy
‪static array array[] parseOrderBy(string $input)
Definition: QueryHelper.php:44
‪TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction
Definition: HiddenRestriction.php:27
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\versionOL
‪versionOL($table, &$row, $unsetMovePointers=false, $bypassEnableFieldsCheck=false)
Definition: PageRepository.php:1565
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger($var)
Definition: MathUtility.php:74
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getMenu
‪array getMenu($pageId, $fields=' *', $sortField='sorting', $additionalWhereClause='', $checkShortcuts=true)
Definition: PageRepository.php:715
‪TYPO3\CMS\Core\Versioning\VersionState\NEW_PLACEHOLDER
‪const NEW_PLACEHOLDER
Definition: VersionState.php:47
‪TYPO3\CMS\Core\Database\Query\Restriction\EndTimeRestriction
Definition: EndTimeRestriction.php:27
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_DEFAULT
‪const DOKTYPE_DEFAULT
Definition: PageRepository.php:103
‪TYPO3\CMS\Core\Database\Query\Restriction\StartTimeRestriction
Definition: StartTimeRestriction.php:27
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\$context
‪Context $context
Definition: PageRepository.php:122
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getLanguageFallbackChain
‪int[] getLanguageFallbackChain(?LanguageAspect $languageAspect)
Definition: PageRepository.php:500
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\checkRecord
‪array int checkRecord($table, $uid, $checkPage=0)
Definition: PageRepository.php:1218
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\$where_hid_del
‪string $where_hid_del
Definition: PageRepository.php:61
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getWorkspaceVersionOfRecord
‪mixed getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields=' *', $bypassEnableFieldsCheck=false)
Definition: PageRepository.php:1760
‪TYPO3\CMS\Core\Context\LanguageAspect\getId
‪int getId()
Definition: LanguageAspect.php:111
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getPage_noCheck
‪array getPage_noCheck($uid)
Definition: PageRepository.php:316
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getPage
‪array getPage($uid, $disableGroupAccessCheck=false)
Definition: PageRepository.php:248
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\movePlhOL
‪bool movePlhOL($table, &$row)
Definition: PageRepository.php:1641
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_SHORTCUT
‪const DOKTYPE_SHORTCUT
Definition: PageRepository.php:105
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_LINK
‪const DOKTYPE_LINK
Definition: PageRepository.php:104
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\$computedPropertyNames
‪array $computedPropertyNames
Definition: PageRepository.php:89
‪TYPO3\CMS\Core\Database\Query\Restriction\FrontendWorkspaceRestriction
Definition: FrontendWorkspaceRestriction.php:30
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\$sys_language_uid
‪int $sys_language_uid
Definition: PageRepository.php:73
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\filterAccessiblePageIds
‪int[] filterAccessiblePageIds(array $pageIds, QueryRestrictionContainerInterface $restrictionContainer=null)
Definition: PageRepository.php:1177
‪TYPO3\CMS\Core\Domain\Repository\PageRepositoryInitHookInterface
Definition: PageRepositoryInitHookInterface.php:22
‪TYPO3\CMS\Core\Database\Query\Restriction\QueryRestrictionContainerInterface
Definition: QueryRestrictionContainerInterface.php:25
‪TYPO3\CMS\Core\Versioning\VersionState\DELETE_PLACEHOLDER
‪const DELETE_PLACEHOLDER
Definition: VersionState.php:55
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\addMountPointParameterToPage
‪array addMountPointParameterToPage(array $page)
Definition: PageRepository.php:858
‪TYPO3\CMS\Core\Versioning\VersionState\MOVE_POINTER
‪const MOVE_POINTER
Definition: VersionState.php:73
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\SHORTCUT_MODE_RANDOM_SUBPAGE
‪const SHORTCUT_MODE_RANDOM_SUBPAGE
Definition: PageRepository.php:117
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\purgeComputedProperties
‪array purgeComputedProperties(array $row)
Definition: PageRepository.php:1839
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getMenuForPages
‪array getMenuForPages(array $pageIds, $fields=' *', $sortField='sorting', $additionalWhereClause='', $checkShortcuts=true)
Definition: PageRepository.php:734
‪$fields
‪$fields
Definition: pages.php:5
‪TYPO3\CMS\Core\Database\Query\Restriction\FrontendGroupRestriction
Definition: FrontendGroupRestriction.php:30
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:53
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getRecordOverlay
‪mixed getRecordOverlay($table, $row, $sys_language_content, $OLmode='')
Definition: PageRepository.php:592
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\SHORTCUT_MODE_FIRST_SUBPAGE
‪const SHORTCUT_MODE_FIRST_SUBPAGE
Definition: PageRepository.php:116
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getMovedPidOfVersionedRecord
‪int null getMovedPidOfVersionedRecord(string $table, int $liveUid)
Definition: PageRepository.php:1705
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_MOUNTPOINT
‪const DOKTYPE_MOUNTPOINT
Definition: PageRepository.php:107
‪TYPO3\CMS\Core\Type\Enumeration\cast
‪static static cast($value)
Definition: Enumeration.php:186
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\checkValidShortcutOfPage
‪array checkValidShortcutOfPage(array $page, $additionalWhereClause)
Definition: PageRepository.php:891
‪TYPO3\CMS\Core\Context\LanguageAspect\getFallbackChain
‪getFallbackChain()
Definition: LanguageAspect.php:128
‪TYPO3\CMS\Core\Database\Query\QueryHelper
Definition: QueryHelper.php:32
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\fixVersioningPid
‪fixVersioningPid($table, &$rr)
Definition: PageRepository.php:1484
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getRuntimeCache
‪VariableFrontend getRuntimeCache()
Definition: PageRepository.php:1852
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\hasTableWorkspaceSupport
‪hasTableWorkspaceSupport(string $tableName)
Definition: PageRepository.php:1857
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\__construct
‪__construct(Context $context=null)
Definition: PageRepository.php:130
‪TYPO3\CMS\Core\Cache\Frontend\VariableFrontend
Definition: VariableFrontend.php:25
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getPagesOverlay
‪array getPagesOverlay(array $pagesInput, $languageUid=null)
Definition: PageRepository.php:408
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_SPACER
‪const DOKTYPE_SPACER
Definition: PageRepository.php:108
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_BE_USER_SECTION
‪const DOKTYPE_BE_USER_SECTION
Definition: PageRepository.php:106
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:35
‪TYPO3\CMS\Core\Domain\Repository\PageRepositoryGetRecordOverlayHookInterface
Definition: PageRepositoryGetRecordOverlayHookInterface.php:22
‪TYPO3\CMS\Core\Domain\Repository\PageRepositoryGetPageOverlayHookInterface
Definition: PageRepositoryGetPageOverlayHookInterface.php:22
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_SYSFOLDER
‪const DOKTYPE_SYSFOLDER
Definition: PageRepository.php:109
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\init
‪init($show_hidden)
Definition: PageRepository.php:152
‪TYPO3\CMS\Core\Context\LanguageAspect
Definition: LanguageAspect.php:57
‪TYPO3\CMS\Core\Versioning\VersionState
Definition: VersionState.php:24
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\enableFields
‪string enableFields($table, $show_hidden=-1, $ignore_array=[])
Definition: PageRepository.php:1314
‪TYPO3\CMS\Core\Utility\GeneralUtility\trimExplode
‪static string[] trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:1059
‪TYPO3\CMS\Core\Domain\Repository
Definition: PageRepository.php:16
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\SHORTCUT_MODE_PARENT_PAGE
‪const SHORTCUT_MODE_PARENT_PAGE
Definition: PageRepository.php:118
‪TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
Definition: AspectNotFoundException.php:26
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getSubpagesForPages
‪array getSubpagesForPages(array $pageIds, string $fields=' *', string $sortField='sorting', string $additionalWhereClause='', bool $checkShortcuts=true, bool $parentPages=true)
Definition: PageRepository.php:775
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:36
‪TYPO3\CMS\Core\function
‪return function(ContainerConfigurator $container, ContainerBuilder $containerBuilder)
Definition: Services.php:12
‪TYPO3\CMS\Core\Error\Http\ShortcutTargetPageNotFoundException
Definition: ShortcutTargetPageNotFoundException.php:24
‪TYPO3\CMS\Core\Database\Query\QueryHelper\stripLogicalOperatorPrefix
‪static string stripLogicalOperatorPrefix(string $constraint)
Definition: QueryHelper.php:165
‪TYPO3\CMS\Core\Versioning\VersionState\DEFAULT_STATE
‪const DEFAULT_STATE
Definition: VersionState.php:39
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\SHORTCUT_MODE_NONE
‪const SHORTCUT_MODE_NONE
Definition: PageRepository.php:115
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\$where_groupAccess
‪string $where_groupAccess
Definition: PageRepository.php:67
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:28
‪TYPO3\CMS\Core\Utility\GeneralUtility\intExplode
‪static int[] intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
Definition: GeneralUtility.php:988
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:22
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getExtURL
‪string bool getExtURL($pagerow)
Definition: PageRepository.php:1031
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getPageOverlaysForLanguageUids
‪array getPageOverlaysForLanguageUids(array $pageUids, array $languageUids)
Definition: PageRepository.php:521
‪TYPO3\CMS\Core\Domain\Repository\PageRepository
Definition: PageRepository.php:52
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getPageOverlay
‪array getPageOverlay($pageInput, $languageUid=null)
Definition: PageRepository.php:390
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:46
‪TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer
Definition: FrontendRestrictionContainer.php:31
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getRawRecord
‪mixed getRawRecord($table, $uid, $fields=' *')
Definition: PageRepository.php:1269
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getPageShortcut
‪mixed getPageShortcut($shortcutFieldValue, $shortcutMode, $thisUid, $iteration=20, $pageLog=[], $disableGroupCheck=false)
Definition: PageRepository.php:962
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\DOKTYPE_RECYCLER
‪const DOKTYPE_RECYCLER
Definition: PageRepository.php:110
‪TYPO3\CMS\Core\Domain\Repository\PageRepositoryGetPageHookInterface
Definition: PageRepositoryGetPageHookInterface.php:22
‪TYPO3\CMS\Core\Domain\Repository\PageRepository\getMountPointInfo
‪mixed getMountPointInfo($pageId, $pageRec=false, $prevMountPids=[], $firstPageUid=0)
Definition: PageRepository.php:1082
‪TYPO3\CMS\Core\Context\UserAspect
Definition: UserAspect.php:38
‪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