‪TYPO3CMS  9.5
PageRepository.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
17 use Psr\Log\LoggerAwareInterface;
18 use Psr\Log\LoggerAwareTrait;
43 
52 class ‪PageRepository implements LoggerAwareInterface
53 {
54  use LoggerAwareTrait;
57 
62  protected ‪$deprecatedPublicProperties = [
63  'versioningPreview' => 'Using $versioningPreview of class PageRepository is discouraged, just use versioningWorkspaceId to determine if a workspace should be previewed.',
64  'workspaceCache' => 'Using $workspaceCache of class PageRepository from the outside is discouraged, as this only reflects a local runtime cache.',
65  'error_getRootLine' => 'Using $error_getRootLine of class PageRepository from the outside is deprecated as this property only exists for legacy reasons.',
66  'error_getRootLine_failPid' => 'Using $error_getRootLine_failPid of class PageRepository from the outside is deprecated as this property only exists for legacy reasons.',
67  'sys_language_uid' => 'Using $sys_language_uid of class PageRepository from the outside is deprecated as this information is now stored within the Context Language Aspect given by the constructor.',
68  'versioningWorkspaceId' => 'Using $versioningWorkspaceId of class PageRepository from the outside is deprecated as this information is now stored within the Context Workspace Aspect given by the constructor.',
69  ];
70 
75  protected ‪$deprecatedPublicMethods = [
76  'init' => 'init() is now called implicitly on object creation, and is not necessary anymore to be called explicitly. Calling init() will throw an error in TYPO3 v10.0.',
77  'movePlhOL' => 'Using movePlhOL is deprecated and will not be possible anymore in TYPO3 v10.0.',
78  'getMovePlaceholder' => 'Using getMovePlaceholder is deprecated and will not be possible anymore in TYPO3 v10.0.'
79  ];
80 
88  public ‪$where_hid_del = ' AND pages.deleted=0';
89 
95  public ‪$where_groupAccess = '';
96 
102  protected ‪$sys_language_uid = 0;
103 
112  protected ‪$versioningPreview = false;
113 
123  protected ‪$versioningWorkspaceId = 0;
124 
128  protected ‪$workspaceCache = [];
129 
135  protected ‪$error_getRootLine = '';
136 
142  protected ‪$error_getRootLine_failPid = 0;
143 
147  protected ‪$cache_getPage = [];
148 
152  protected ‪$cache_getPage_noCheck = [];
153 
157  protected ‪$cache_getPageIdFromAlias = [];
158 
162  protected ‪$cache_getMountPointInfo = [];
163 
170  '_LOCALIZED_UID',
171  '_MP_PARAM',
172  '_ORIG_uid',
173  '_ORIG_pid',
174  '_PAGES_OVERLAY',
175  '_PAGES_OVERLAY_UID',
176  '_PAGES_OVERLAY_LANGUAGE',
177  '_PAGES_OVERLAY_REQUESTEDLANGUAGE',
178  ];
179 
184  const ‪DOKTYPE_LINK = 3;
185  const ‪DOKTYPE_SHORTCUT = 4;
186  const ‪DOKTYPE_BE_USER_SECTION = 6;
188  const ‪DOKTYPE_SPACER = 199;
189  const ‪DOKTYPE_SYSFOLDER = 254;
190  const ‪DOKTYPE_RECYCLER = 255;
191 
199 
203  protected ‪$context;
204 
211  public function ‪__construct(‪Context ‪$context = null)
212  {
213  $this->context = ‪$context ?? GeneralUtility::makeInstance(Context::class);
214  $this->versioningWorkspaceId = $this->context->getPropertyFromAspect('workspace', 'id');
215  // Only set up the where clauses for pages when TCA is set. This usually happens only in tests.
216  // Once all tests are written very well, this can be removed again
217  if (isset(‪$GLOBALS['TCA']['pages'])) {
218  $this->‪init($this->context->getPropertyFromAspect('visibility', 'includeHiddenPages'));
219  $this->where_groupAccess = $this->‪getMultipleGroupsWhereClause('pages.fe_group', 'pages');
220  $this->sys_language_uid = (int)$this->context->getPropertyFromAspect('language', 'id', 0);
221  }
222  }
223 
233  protected function ‪init($show_hidden)
234  {
235  $this->where_groupAccess = '';
236  // As PageRepository may be used multiple times during the frontend request, and may
237  // actually be used before the usergroups have been resolved, self::getMultipleGroupsWhereClause()
238  // and the hook in ->enableFields() need to be reconsidered when the usergroup state changes.
239  // When something changes in the context, a second runtime cache entry is built.
240  // However, the PageRepository is generally in use for generating e.g. hundreds of links, so they would all use
241  // the same cache identifier.
242  $userAspect = $this->context->getAspect('frontend.user');
243  $frontendUserIdentifier = 'user_' . (int)$userAspect->get('id') . '_groups_' . md5(implode(',', $userAspect->getGroupIds()));
244 
245  // We need to respect the date aspect as we might have subrequests with a different time (e.g. backend preview links)
246  $dateTimeIdentifier = $this->context->getAspect('date')->get('timestamp');
247 
248  $cache = $this->‪getRuntimeCache();
249  $cacheIdentifier = 'PageRepository_hidDelWhere' . ($show_hidden ? 'ShowHidden' : '') . '_' . (int)$this->versioningWorkspaceId . '_' . $frontendUserIdentifier . '_' . $dateTimeIdentifier;
250  $cacheEntry = $cache->get($cacheIdentifier);
251  if ($cacheEntry) {
252  $this->where_hid_del = $cacheEntry;
253  } else {
254  $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
255  ->getQueryBuilderForTable('pages')
256  ->expr();
257  if ($this->versioningWorkspaceId > 0) {
258  // For version previewing, make sure that enable-fields are not
259  // de-selecting hidden pages - we need versionOL() to unset them only
260  // if the overlay record instructs us to.
261  // Clear where_hid_del and restrict to live and current workspaces
262  $this->where_hid_del = ' AND ' . $expressionBuilder->andX(
263  $expressionBuilder->eq('pages.deleted', 0),
264  $expressionBuilder->orX(
265  $expressionBuilder->eq('pages.t3ver_wsid', 0),
266  $expressionBuilder->eq('pages.t3ver_wsid', (int)$this->versioningWorkspaceId)
267  ),
268  $expressionBuilder->lt('pages.doktype', 200)
269  );
270  } else {
271  // add starttime / endtime, and check for hidden/deleted
272  // Filter out new/deleted place-holder pages in case we are NOT in a
273  // versioning preview (that means we are online!)
274  $this->where_hid_del = ' AND ' . (string)$expressionBuilder->andX(
276  $this->enableFields('pages', $show_hidden, ['fe_group' => true], true)
277  ),
278  $expressionBuilder->lt('pages.doktype', 200)
279  );
280  }
281  $cache->set($cacheIdentifier, $this->where_hid_del);
282  }
283  if (is_array(‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class]['init'] ?? false)) {
284  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class]['init'] as $classRef) {
285  $hookObject = GeneralUtility::makeInstance($classRef);
286  if (!$hookObject instanceof PageRepositoryInitHookInterface) {
287  throw new \UnexpectedValueException($classRef . ' must implement interface ' . PageRepositoryInitHookInterface::class, 1379579812);
288  }
289  $hookObject->init_postProcess($this);
290  }
291  }
292  }
293 
294  /**************************
295  *
296  * Selecting page records
297  *
298  **************************/
299 
328  public function ‪getPage($uid, $disableGroupAccessCheck = false)
329  {
330  // Hook to manipulate the page uid for special overlay handling
331  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPage'] ?? [] as $className) {
332  $hookObject = GeneralUtility::makeInstance($className);
333  if (!$hookObject instanceof PageRepositoryGetPageHookInterface) {
334  throw new \UnexpectedValueException($className . ' must implement interface ' . PageRepositoryGetPageHookInterface::class, 1251476766);
335  }
336  $hookObject->getPage_preProcess($uid, $disableGroupAccessCheck, $this);
337  }
338  $cacheIdentifier = 'PageRepository_getPage_' . md5(
339  implode(
340  '-',
341  [
342  $uid,
343  $disableGroupAccessCheck ? '' : $this->where_groupAccess,
344  $this->where_hid_del,
345  $this->sys_language_uid
346  ]
347  )
348  );
349  $cache = $this->‪getRuntimeCache();
350  $cacheEntry = $cache->get($cacheIdentifier);
351  if (is_array($cacheEntry)) {
352  return $cacheEntry;
353  }
354  $result = [];
355  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
356  $queryBuilder->getRestrictions()->removeAll();
357  $queryBuilder->select('*')
358  ->from('pages')
359  ->where(
360  $queryBuilder->expr()->eq('uid', (int)$uid),
361  ‪QueryHelper::stripLogicalOperatorPrefix($this->where_hid_del)
362  );
363 
364  $originalWhereGroupAccess = '';
365  if (!$disableGroupAccessCheck) {
366  $queryBuilder->andWhere(‪QueryHelper::stripLogicalOperatorPrefix($this->where_groupAccess));
367  } else {
368  $originalWhereGroupAccess = ‪$this->where_groupAccess;
369  $this->where_groupAccess = '';
370  }
371 
372  $row = $queryBuilder->execute()->fetch();
373  if ($row) {
374  $this->‪versionOL('pages', $row);
375  if (is_array($row)) {
376  $result = $this->‪getPageOverlay($row);
377  }
378  }
379 
380  if ($disableGroupAccessCheck) {
381  $this->where_groupAccess = $originalWhereGroupAccess;
382  }
383 
384  $cache->set($cacheIdentifier, $result);
385  return $result;
386  }
387 
396  public function ‪getPage_noCheck($uid)
397  {
398  $cache = $this->‪getRuntimeCache();
399  $cacheIdentifier = 'PageRepository_getPage_noCheck_' . $uid . '_' . $this->sys_language_uid . '_' . ‪$this->versioningWorkspaceId;
400  $cacheEntry = $cache->get($cacheIdentifier);
401  if ($cacheEntry !== false) {
402  return $cacheEntry;
403  }
404 
405  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
406  $queryBuilder->getRestrictions()
407  ->removeAll()
408  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
409  $row = $queryBuilder->select('*')
410  ->from('pages')
411  ->where($queryBuilder->expr()->eq('uid', (int)$uid))
412  ->execute()
413  ->fetch();
414 
415  $result = [];
416  if ($row) {
417  $this->‪versionOL('pages', $row);
418  if (is_array($row)) {
419  $result = $this->‪getPageOverlay($row);
420  }
421  }
422  $cache->set($cacheIdentifier, $result);
423  return $result;
424  }
425 
434  public function ‪getFirstWebPage($uid)
435  {
436  trigger_error('PageRepository->getFirstWebPage() will be removed in TYPO3 v10.0. Use "getMenu()" instead.', E_USER_DEPRECATED);
437  ‪$output = '';
438  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
439  $queryBuilder->getRestrictions()->removeAll();
440  $row = $queryBuilder->select('*')
441  ->from('pages')
442  ->where(
443  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)),
444  ‪QueryHelper::stripLogicalOperatorPrefix($this->where_hid_del),
445  ‪QueryHelper::stripLogicalOperatorPrefix($this->where_groupAccess)
446  )
447  ->orderBy('sorting')
448  ->setMaxResults(1)
449  ->execute()
450  ->fetch();
451 
452  if ($row) {
453  $this->‪versionOL('pages', $row);
454  if (is_array($row)) {
455  ‪$output = $this->‪getPageOverlay($row);
456  }
457  }
458  return ‪$output;
459  }
460 
468  public function ‪getPageIdFromAlias($alias)
469  {
470  $alias = strtolower($alias);
471  $cacheIdentifier = 'PageRepository_getPageIdFromAlias_' . md5($alias);
472  $cache = $this->‪getRuntimeCache();
473  $cacheEntry = $cache->get($cacheIdentifier);
474  if ($cacheEntry !== false) {
475  return $cacheEntry;
476  }
477  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
478  $queryBuilder->getRestrictions()
479  ->removeAll()
480  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
481 
482  $row = $queryBuilder->select('uid')
483  ->from('pages')
484  ->where(
485  $queryBuilder->expr()->eq('alias', $queryBuilder->createNamedParameter($alias, \PDO::PARAM_STR)),
486  // "AND pid>=0" because of versioning (means that aliases sent MUST be online!)
487  $queryBuilder->expr()->gte('pid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT))
488  )
489  ->setMaxResults(1)
490  ->execute()
491  ->fetch();
492 
493  if ($row) {
494  $cache->set($cacheIdentifier, $row['uid']);
495  return $row['uid'];
496  }
497  $cache->set($cacheIdentifier, 0);
498  return 0;
499  }
500 
511  public function ‪getLanguageOverlay(string $table, array $row)
512  {
513  // table is not localizable, so return directly
514  if (!isset(‪$GLOBALS['TCA'][$table]['ctrl']['languageField'])) {
515  return $row;
516  }
517  try {
519  $languageAspect = $this->context->getAspect('language');
520  if ($languageAspect->doOverlays()) {
521  if ($table === 'pages') {
522  return $this->‪getPageOverlay($row, $languageAspect->getId());
523  }
524  return $this->‪getRecordOverlay(
525  $table,
526  $row,
527  $languageAspect->getContentId(),
528  $languageAspect->getOverlayType() === $languageAspect::OVERLAYS_MIXED ? '1' : 'hideNonTranslated'
529  );
530  }
531  } catch (AspectNotFoundException $e) {
532  // no overlays
533  }
534  return $row;
535  }
536 
545  public function ‪getPageOverlay($pageInput, $languageUid = null)
546  {
547  if ($languageUid === -1) {
548  trigger_error('Calling getPageOverlay() with "-1" as languageId is discouraged and will be unsupported in TYPO3 v10.0. Omit the parameter or use "null" instead.', E_USER_DEPRECATED);
549  $languageUid = null;
550  }
551  $rows = $this->‪getPagesOverlay([$pageInput], $languageUid);
552  // Always an array in return
553  return $rows[0] ?? [];
554  }
555 
567  public function ‪getPagesOverlay(array $pagesInput, $languageUid = null)
568  {
569  if (empty($pagesInput)) {
570  return [];
571  }
572  if ($languageUid === null) {
573  $languageUid = ‪$this->sys_language_uid;
574  } elseif ($languageUid < 0) {
575  trigger_error('Calling getPagesOverlay() with "-1" as languageId is discouraged and will be unsupported in TYPO3 v10.0. Omit the parameter or use "null" instead.', E_USER_DEPRECATED);
576  $languageUid = ‪$this->sys_language_uid;
577  }
578  foreach ($pagesInput as &$origPage) {
579  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPageOverlay'] ?? [] as $className) {
580  $hookObject = GeneralUtility::makeInstance($className);
581  if (!$hookObject instanceof PageRepositoryGetPageOverlayHookInterface) {
582  throw new \UnexpectedValueException($className . ' must implement interface ' . PageRepositoryGetPageOverlayHookInterface::class, 1269878881);
583  }
584  $hookObject->getPageOverlay_preProcess($origPage, $languageUid, $this);
585  }
586  }
587  unset($origPage);
588 
589  $overlays = [];
590  // If language UID is different from zero, do overlay:
591  if ($languageUid) {
592  $languageUids = array_merge([$languageUid], $this->‪getLanguageFallbackChain(null));
593 
594  $pageIds = [];
595  foreach ($pagesInput as $origPage) {
596  if (is_array($origPage)) {
597  // Was the whole record
598  $pageIds[] = (int)$origPage['uid'];
599  } else {
600  // Was the id
601  $pageIds[] = (int)$origPage;
602  }
603  }
604  $overlays = $this->‪getPageOverlaysForLanguageUids($pageIds, $languageUids);
605  }
606 
607  // Create output:
608  $pagesOutput = [];
609  foreach ($pagesInput as $key => $origPage) {
610  if (is_array($origPage)) {
611  $pagesOutput[$key] = $origPage;
612  if (isset($overlays[$origPage['uid']])) {
613  // Overwrite the original field with the overlay
614  foreach ($overlays[$origPage['uid']] as $fieldName => $fieldValue) {
615  if ($fieldName !== 'uid' && $fieldName !== 'pid') {
616  $pagesOutput[$key][$fieldName] = $fieldValue;
617  }
618  }
619  }
620  } else {
621  if (isset($overlays[$origPage])) {
622  $pagesOutput[$key] = $overlays[$origPage];
623  }
624  }
625  }
626  return $pagesOutput;
627  }
628 
637  public function ‪isPageSuitableForLanguage(array $page, LanguageAspect $languageAspect): bool
638  {
639  $languageUid = $languageAspect->getId();
640  // Checks if the default language version can be shown
641  // Block page is set, if l18n_cfg allows plus: 1) Either default language or 2) another language but NO overlay record set for page!
642  if (GeneralUtility::hideIfDefaultLanguage($page['l18n_cfg']) && (!$languageUid || $languageUid && !$page['_PAGES_OVERLAY'])) {
643  return false;
644  }
645  if ($languageUid > 0 && GeneralUtility::hideIfNotTranslated($page['l18n_cfg'])) {
646  if (!$page['_PAGES_OVERLAY'] || (int)$page['_PAGES_OVERLAY_LANGUAGE'] !== $languageUid) {
647  return false;
648  }
649  } elseif ($languageUid > 0) {
650  $languageUids = array_merge([$languageUid], $this->‪getLanguageFallbackChain($languageAspect));
651  return in_array((int)$page['sys_language_uid'], $languageUids, true);
652  }
653  return true;
654  }
655 
662  protected function ‪getLanguageFallbackChain(?LanguageAspect $languageAspect): array
663  {
664  $languageAspect = $languageAspect ?? $this->context->getAspect('language');
665  return array_filter($languageAspect->getFallbackChain(), function ($item) {
667  });
668  }
669 
683  protected function ‪getPageOverlaysForLanguageUids(array $pageUids, array $languageUids): array
684  {
685  // Remove default language ("0")
686  $languageUids = array_filter($languageUids);
687  $languageField = ‪$GLOBALS['TCA']['pages']['ctrl']['languageField'];
688  $overlays = [];
689 
690  foreach ($pageUids as $pageId) {
691  // Create a map based on the order of values in $languageUids. Those entries reflect the order of the language + fallback chain.
692  // We can't work with database ordering since there is no common SQL clause to order by e.g. [7, 1, 2].
693  $orderedListByLanguages = array_flip($languageUids);
694 
695  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
696  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context));
697  // Because "fe_group" is an exclude field, so it is synced between overlays, the group restriction is removed for language overlays of pages
698  $queryBuilder->getRestrictions()->removeByType(FrontendGroupRestriction::class);
699  $result = $queryBuilder->select('*')
700  ->from('pages')
701  ->where(
702  $queryBuilder->expr()->eq(
703  ‪$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
704  $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
705  ),
706  $queryBuilder->expr()->in(
707  ‪$GLOBALS['TCA']['pages']['ctrl']['languageField'],
708  $queryBuilder->createNamedParameter($languageUids, Connection::PARAM_INT_ARRAY)
709  )
710  )
711  ->execute();
712 
713  // Create a list of rows ordered by values in $languageUids
714  while ($row = $result->fetch()) {
715  $orderedListByLanguages[$row[$languageField]] = $row;
716  }
717 
718  foreach ($orderedListByLanguages as $languageUid => $row) {
719  if (!is_array($row)) {
720  continue;
721  }
722 
723  // Found a result for the current language id
724  $this->‪versionOL('pages', $row);
725  if (is_array($row)) {
726  $row['_PAGES_OVERLAY'] = true;
727  $row['_PAGES_OVERLAY_UID'] = $row['uid'];
728  $row['_PAGES_OVERLAY_LANGUAGE'] = $languageUid;
729  $row['_PAGES_OVERLAY_REQUESTEDLANGUAGE'] = $languageUids[0];
730  // Unset vital fields that are NOT allowed to be overlaid:
731  unset($row['uid'], $row['pid'], $row['alias']);
732  $overlays[$pageId] = $row;
733 
734  // Language fallback found, stop querying further languages
735  break;
736  }
737  }
738  }
739 
740  return $overlays;
741  }
742 
754  public function ‪getRecordOverlay($table, $row, $sys_language_content, $OLmode = '')
755  {
756  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'] ?? [] as $className) {
757  $hookObject = GeneralUtility::makeInstance($className);
758  if (!$hookObject instanceof PageRepositoryGetRecordOverlayHookInterface) {
759  throw new \UnexpectedValueException($className . ' must implement interface ' . PageRepositoryGetRecordOverlayHookInterface::class, 1269881658);
760  }
761  $hookObject->getRecordOverlay_preProcess($table, $row, $sys_language_content, $OLmode, $this);
762  }
763 
764  $tableControl = ‪$GLOBALS['TCA'][$table]['ctrl'] ?? [];
765 
766  if (!empty($tableControl['languageField'])
767  // Return record for ALL languages untouched
768  // TODO: Fix call stack to prevent this situation in the first place
769  && (int)$row[$tableControl['languageField']] !== -1
770  && !empty($tableControl['transOrigPointerField'])
771  && $row['uid'] > 0
772  && ($row['pid'] > 0 || in_array($tableControl['rootLevel'] ?? false, [true, 1, -1], true))) {
773  // Will try to overlay a record only if the sys_language_content value is larger than zero.
774  if ($sys_language_content > 0) {
775  // Must be default language, otherwise no overlaying
776  if ((int)$row[$tableControl['languageField']] === 0) {
777  // Select overlay record:
778  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
779  ->getQueryBuilderForTable($table);
780  $queryBuilder->setRestrictions(
781  GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context)
782  );
783  $olrow = $queryBuilder->select('*')
784  ->from($table)
785  ->where(
786  $queryBuilder->expr()->eq(
787  'pid',
788  $queryBuilder->createNamedParameter($row['pid'], \PDO::PARAM_INT)
789  ),
790  $queryBuilder->expr()->eq(
791  $tableControl['languageField'],
792  $queryBuilder->createNamedParameter($sys_language_content, \PDO::PARAM_INT)
793  ),
794  $queryBuilder->expr()->eq(
795  $tableControl['transOrigPointerField'],
796  $queryBuilder->createNamedParameter($row['uid'], \PDO::PARAM_INT)
797  )
798  )
799  ->setMaxResults(1)
800  ->execute()
801  ->fetch();
802 
803  $this->‪versionOL($table, $olrow);
804  // Merge record content by traversing all fields:
805  if (is_array($olrow)) {
806  if (isset($olrow['_ORIG_uid'])) {
807  $row['_ORIG_uid'] = $olrow['_ORIG_uid'];
808  }
809  if (isset($olrow['_ORIG_pid'])) {
810  $row['_ORIG_pid'] = $olrow['_ORIG_pid'];
811  }
812  foreach ($row as $fN => $fV) {
813  if ($fN !== 'uid' && $fN !== 'pid' && isset($olrow[$fN])) {
814  $row[$fN] = $olrow[$fN];
815  } elseif ($fN === 'uid') {
816  $row['_LOCALIZED_UID'] = $olrow['uid'];
817  }
818  }
819  } elseif ($OLmode === 'hideNonTranslated' && (int)$row[$tableControl['languageField']] === 0) {
820  // Unset, if non-translated records should be hidden. ONLY done if the source
821  // record really is default language and not [All] in which case it is allowed.
822  unset($row);
823  }
824  } elseif ($sys_language_content != $row[$tableControl['languageField']]) {
825  unset($row);
826  }
827  } else {
828  // When default language is displayed, we never want to return a record carrying
829  // another language!
830  if ($row[$tableControl['languageField']] > 0) {
831  unset($row);
832  }
833  }
834  }
835 
836  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'] ?? [] as $className) {
837  $hookObject = GeneralUtility::makeInstance($className);
838  if (!$hookObject instanceof PageRepositoryGetRecordOverlayHookInterface) {
839  throw new \UnexpectedValueException($className . ' must implement interface ' . PageRepositoryGetRecordOverlayHookInterface::class, 1269881659);
840  }
841  $hookObject->getRecordOverlay_postProcess($table, $row, $sys_language_content, $OLmode, $this);
842  }
843 
844  return $row;
845  }
846 
847  /************************************************
848  *
849  * Page related: Menu, Domain record, Root line
850  *
851  ************************************************/
852 
868  public function ‪getMenu($pageId, ‪$fields = '*', $sortField = 'sorting', $additionalWhereClause = '', $checkShortcuts = true)
869  {
870  return $this->‪getSubpagesForPages((array)$pageId, ‪$fields, $sortField, $additionalWhereClause, $checkShortcuts);
871  }
872 
886  public function ‪getMenuForPages(array $pageIds, ‪$fields = '*', $sortField = 'sorting', $additionalWhereClause = '', $checkShortcuts = true)
887  {
888  return $this->‪getSubpagesForPages($pageIds, ‪$fields, $sortField, $additionalWhereClause, $checkShortcuts, false);
889  }
890 
926  protected function ‪getSubpagesForPages(
927  array $pageIds,
928  string ‪$fields = '*',
929  string $sortField = 'sorting',
930  string $additionalWhereClause = '',
931  bool $checkShortcuts = true,
932  bool $parentPages = true
933  ): array {
934  $relationField = $parentPages ? 'pid' : 'uid';
935  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
936  $queryBuilder->getRestrictions()->removeAll();
937 
938  $res = $queryBuilder->select(...GeneralUtility::trimExplode(',', ‪$fields, true))
939  ->from('pages')
940  ->where(
941  $queryBuilder->expr()->in(
942  $relationField,
943  $queryBuilder->createNamedParameter($pageIds, Connection::PARAM_INT_ARRAY)
944  ),
945  $queryBuilder->expr()->eq(
946  ‪$GLOBALS['TCA']['pages']['ctrl']['languageField'],
947  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
948  ),
949  ‪QueryHelper::stripLogicalOperatorPrefix($this->where_hid_del),
950  ‪QueryHelper::stripLogicalOperatorPrefix($this->where_groupAccess),
951  ‪QueryHelper::stripLogicalOperatorPrefix($additionalWhereClause)
952  );
953 
954  if (!empty($sortField)) {
955  $orderBy = ‪QueryHelper::parseOrderBy($sortField);
956  foreach ($orderBy as $order) {
957  $res->addOrderBy($order[0], $order[1] ?? 'ASC');
958  }
959  }
960  $result = $res->execute();
961 
962  $pages = [];
963  while ($page = $result->fetch()) {
964  $originalUid = $page['uid'];
965 
966  // Versioning Preview Overlay
967  $this->‪versionOL('pages', $page, true);
968  // Skip if page got disabled due to version overlay
969  // (might be delete or move placeholder)
970  if (empty($page)) {
971  continue;
972  }
973 
974  // Add a mount point parameter if needed
975  $page = $this->‪addMountPointParameterToPage((array)$page);
976 
977  // If shortcut, look up if the target exists and is currently visible
978  if ($checkShortcuts) {
979  $page = $this->‪checkValidShortcutOfPage((array)$page, $additionalWhereClause);
980  }
981 
982  // If the page still is there, we add it to the output
983  if (!empty($page)) {
984  $pages[$originalUid] = $page;
985  }
986  }
987 
988  // Finally load language overlays
989  return $this->‪getPagesOverlay($pages);
990  }
991 
1007  protected function ‪addMountPointParameterToPage(array $page): array
1008  {
1009  if (empty($page)) {
1010  return [];
1011  }
1012 
1013  // $page MUST have "uid", "pid", "doktype", "mount_pid", "mount_pid_ol" fields in it
1014  $mountPointInfo = $this->‪getMountPointInfo($page['uid'], $page);
1015 
1016  // There is a valid mount point in overlay mode.
1017  if (is_array($mountPointInfo) && $mountPointInfo['overlay']) {
1018 
1019  // Using "getPage" is OK since we need the check for enableFields AND for type 2
1020  // of mount pids we DO require a doktype < 200!
1021  $mountPointPage = $this->‪getPage($mountPointInfo['mount_pid']);
1022 
1023  if (!empty($mountPointPage)) {
1024  $page = $mountPointPage;
1025  $page['_MP_PARAM'] = $mountPointInfo['MPvar'];
1026  } else {
1027  $page = [];
1028  }
1029  }
1030  return $page;
1031  }
1032 
1040  protected function ‪checkValidShortcutOfPage(array $page, $additionalWhereClause)
1041  {
1042  if (empty($page)) {
1043  return [];
1044  }
1045 
1046  $dokType = (int)$page['doktype'];
1047  $shortcutMode = (int)$page['shortcut_mode'];
1048 
1049  if ($dokType === self::DOKTYPE_SHORTCUT && ($page['shortcut'] || $shortcutMode)) {
1050  if ($shortcutMode === self::SHORTCUT_MODE_NONE) {
1051  // No shortcut_mode set, so target is directly set in $page['shortcut']
1052  $searchField = 'uid';
1053  $searchUid = (int)$page['shortcut'];
1054  } elseif ($shortcutMode === self::SHORTCUT_MODE_FIRST_SUBPAGE || $shortcutMode === self::SHORTCUT_MODE_RANDOM_SUBPAGE) {
1055  // Check subpages - first subpage or random subpage
1056  $searchField = 'pid';
1057  // If a shortcut mode is set and no valid page is given to select subpags
1058  // from use the actual page.
1059  $searchUid = (int)$page['shortcut'] ?: $page['uid'];
1060  } elseif ($shortcutMode === self::SHORTCUT_MODE_PARENT_PAGE) {
1061  // Shortcut to parent page
1062  $searchField = 'uid';
1063  $searchUid = $page['pid'];
1064  } else {
1065  $searchField = '';
1066  $searchUid = 0;
1067  }
1068 
1069  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
1070  $queryBuilder->getRestrictions()->removeAll();
1071  $count = $queryBuilder->count('uid')
1072  ->from('pages')
1073  ->where(
1074  $queryBuilder->expr()->eq(
1075  $searchField,
1076  $queryBuilder->createNamedParameter($searchUid, \PDO::PARAM_INT)
1077  ),
1078  ‪QueryHelper::stripLogicalOperatorPrefix($this->where_hid_del),
1079  ‪QueryHelper::stripLogicalOperatorPrefix($this->where_groupAccess),
1080  ‪QueryHelper::stripLogicalOperatorPrefix($additionalWhereClause)
1081  )
1082  ->execute()
1083  ->fetchColumn();
1084 
1085  if (!$count) {
1086  $page = [];
1087  }
1088  } elseif ($dokType === self::DOKTYPE_SHORTCUT) {
1089  // Neither shortcut target nor mode is set. Remove the page from the menu.
1090  $page = [];
1091  }
1092  return $page;
1093  }
1094 
1111  public function ‪getPageShortcut($shortcutFieldValue, $shortcutMode, $thisUid, $iteration = 20, $pageLog = [], $disableGroupCheck = false)
1112  {
1113  $idArray = GeneralUtility::intExplode(',', $shortcutFieldValue);
1114  // Find $page record depending on shortcut mode:
1115  switch ($shortcutMode) {
1118  $pageArray = $this->‪getMenu($idArray[0] ?: $thisUid, '*', 'sorting', 'AND pages.doktype<199 AND pages.doktype!=' . self::DOKTYPE_BE_USER_SECTION);
1119  $pO = 0;
1120  if ($shortcutMode == self::SHORTCUT_MODE_RANDOM_SUBPAGE && !empty($pageArray)) {
1121  $pO = (int)rand(0, count($pageArray) - 1);
1122  }
1123  $c = 0;
1124  $page = [];
1125  foreach ($pageArray as $pV) {
1126  if ($c === $pO) {
1127  $page = $pV;
1128  break;
1129  }
1130  $c++;
1131  }
1132  if (empty($page)) {
1133  $message = 'This page (ID ' . $thisUid . ') is of type "Shortcut" and configured to redirect to a subpage. However, this page has no accessible subpages.';
1134  throw new ShortcutTargetPageNotFoundException($message, 1301648328);
1135  }
1136  break;
1138  $parent = $this->‪getPage($idArray[0] ?: $thisUid, $disableGroupCheck);
1139  $page = $this->‪getPage($parent['pid'], $disableGroupCheck);
1140  if (empty($page)) {
1141  $message = 'This page (ID ' . $thisUid . ') is of type "Shortcut" and configured to redirect to its parent page. However, the parent page is not accessible.';
1142  throw new ShortcutTargetPageNotFoundException($message, 1301648358);
1143  }
1144  break;
1145  default:
1146  $page = $this->‪getPage($idArray[0], $disableGroupCheck);
1147  if (empty($page)) {
1148  $message = 'This page (ID ' . $thisUid . ') is of type "Shortcut" and configured to redirect to a page, which is not accessible (ID ' . $idArray[0] . ').';
1149  throw new ShortcutTargetPageNotFoundException($message, 1301648404);
1150  }
1151  }
1152  // Check if short cut page was a shortcut itself, if so look up recursively:
1153  if ($page['doktype'] == self::DOKTYPE_SHORTCUT) {
1154  if (!in_array($page['uid'], $pageLog) && $iteration > 0) {
1155  $pageLog[] = $page['uid'];
1156  $page = $this->‪getPageShortcut($page['shortcut'], $page['shortcut_mode'], $page['uid'], $iteration - 1, $pageLog, $disableGroupCheck);
1157  } else {
1158  $pageLog[] = $page['uid'];
1159  $message = 'Page shortcuts were looping in uids ' . implode(',', $pageLog) . '...!';
1160  $this->logger->error($message);
1161  throw new \RuntimeException($message, 1294587212);
1162  }
1163  }
1164  // Return resulting page:
1165  return $page;
1166  }
1167 
1178  public function ‪getDomainStartPage($domain, $path = '', $request_uri = '')
1179  {
1180  trigger_error('This method will be removed in TYPO3 v10.0. As the SiteResolver middleware resolves the domain start page.', E_USER_DEPRECATED);
1181  $domain = explode(':', $domain);
1182  $domain = strtolower(preg_replace('/\\.$/', '', $domain[0]));
1183  // Removing extra trailing slashes
1184  $path = trim(preg_replace('/\\/[^\\/]*$/', '', $path));
1185  // Appending to domain string
1186  $domain .= $path;
1187  $domain = preg_replace('/\\/*$/', '', $domain);
1188  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
1189  $queryBuilder->getRestrictions()->removeAll();
1190  $row = $queryBuilder
1191  ->select(
1192  'pages.uid'
1193  )
1194  ->from('pages')
1195  ->from('sys_domain')
1196  ->where(
1197  $queryBuilder->expr()->eq('pages.uid', $queryBuilder->quoteIdentifier('sys_domain.pid')),
1198  $queryBuilder->expr()->eq(
1199  'sys_domain.hidden',
1200  $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)
1201  ),
1202  $queryBuilder->expr()->orX(
1203  $queryBuilder->expr()->eq(
1204  'sys_domain.domainName',
1205  $queryBuilder->createNamedParameter($domain, \PDO::PARAM_STR)
1206  ),
1207  $queryBuilder->expr()->eq(
1208  'sys_domain.domainName',
1209  $queryBuilder->createNamedParameter($domain . '/', \PDO::PARAM_STR)
1210  )
1211  ),
1212  ‪QueryHelper::stripLogicalOperatorPrefix($this->where_hid_del),
1213  ‪QueryHelper::stripLogicalOperatorPrefix($this->where_groupAccess)
1214  )
1215  ->setMaxResults(1)
1216  ->execute()
1217  ->fetch();
1218 
1219  if (!$row) {
1220  return '';
1221  }
1222  return $row['uid'];
1223  }
1224 
1246  public function ‪getRootLine($uid, $MP = '', $ignoreMPerrors = null)
1247  {
1248  trigger_error('Calling PageRepository->getRootLine() will be removed in TYPO3 v10.0. Use RootlineUtility directly.', E_USER_DEPRECATED);
1249  $rootline = GeneralUtility::makeInstance(RootlineUtility::class, $uid, $MP, $this->context);
1250  try {
1251  return $rootline->get();
1252  } catch (\RuntimeException $ex) {
1253  if ($ignoreMPerrors) {
1254  $this->error_getRootLine = $ex->getMessage();
1255  if (substr($this->error_getRootLine, -7) === 'uid -1.') {
1256  $this->error_getRootLine_failPid = -1;
1257  }
1258  return [];
1259  }
1260  if ($ex->getCode() === 1343589451) {
1262  return [];
1263  }
1264  throw $ex;
1265  }
1266  }
1267 
1275  public function ‪getExtURL($pagerow)
1276  {
1277  if ((int)$pagerow['doktype'] === self::DOKTYPE_LINK) {
1278  $redirectTo = $pagerow['url'];
1279  $uI = parse_url($redirectTo);
1280  // If relative path, prefix Site URL
1281  // If it's a valid email without protocol, add "mailto:"
1282  if (!($uI['scheme'] ?? false)) {
1283  if (GeneralUtility::validEmail($redirectTo)) {
1284  $redirectTo = 'mailto:' . $redirectTo;
1285  } elseif ($redirectTo[0] !== '/') {
1286  $redirectTo = GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . $redirectTo;
1287  }
1288  }
1289  return $redirectTo;
1290  }
1291  return false;
1292  }
1293 
1326  public function ‪getMountPointInfo($pageId, $pageRec = false, $prevMountPids = [], $firstPageUid = 0)
1327  {
1328  if (!‪$GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) {
1329  return false;
1330  }
1331  $cacheIdentifier = 'PageRepository_getMountPointInfo_' . $pageId;
1332  $cache = $this->‪getRuntimeCache();
1333  if ($cache->has($cacheIdentifier)) {
1334  return $cache->get($cacheIdentifier);
1335  }
1336  $result = false;
1337  // Get pageRec if not supplied:
1338  if (!is_array($pageRec)) {
1339  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
1340  $queryBuilder->getRestrictions()
1341  ->removeAll()
1342  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1343 
1344  $pageRec = $queryBuilder->select('uid', 'pid', 'doktype', 'mount_pid', 'mount_pid_ol', 't3ver_state')
1345  ->from('pages')
1346  ->where(
1347  $queryBuilder->expr()->eq(
1348  'uid',
1349  $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
1350  ),
1351  $queryBuilder->expr()->neq(
1352  'doktype',
1353  $queryBuilder->createNamedParameter(255, \PDO::PARAM_INT)
1354  )
1355  )
1356  ->execute()
1357  ->fetch();
1358 
1359  // Only look for version overlay if page record is not supplied; This assumes
1360  // that the input record is overlaid with preview version, if any!
1361  $this->‪versionOL('pages', $pageRec);
1362  }
1363  // Set first Page uid:
1364  if (!$firstPageUid) {
1365  $firstPageUid = $pageRec['uid'];
1366  }
1367  // Look for mount pid value plus other required circumstances:
1368  $mount_pid = (int)$pageRec['mount_pid'];
1369  if (is_array($pageRec) && (int)$pageRec['doktype'] === self::DOKTYPE_MOUNTPOINT && $mount_pid > 0 && !in_array($mount_pid, $prevMountPids, true)) {
1370  // Get the mount point record (to verify its general existence):
1371  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages');
1372  $queryBuilder->getRestrictions()
1373  ->removeAll()
1374  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1375 
1376  $mountRec = $queryBuilder->select('uid', 'pid', 'doktype', 'mount_pid', 'mount_pid_ol', 't3ver_state')
1377  ->from('pages')
1378  ->where(
1379  $queryBuilder->expr()->eq(
1380  'uid',
1381  $queryBuilder->createNamedParameter($mount_pid, \PDO::PARAM_INT)
1382  ),
1383  $queryBuilder->expr()->neq(
1384  'doktype',
1385  $queryBuilder->createNamedParameter(255, \PDO::PARAM_INT)
1386  )
1387  )
1388  ->execute()
1389  ->fetch();
1390 
1391  $this->‪versionOL('pages', $mountRec);
1392  if (is_array($mountRec)) {
1393  // Look for recursive mount point:
1394  $prevMountPids[] = $mount_pid;
1395  $recursiveMountPid = $this->‪getMountPointInfo($mount_pid, $mountRec, $prevMountPids, $firstPageUid);
1396  // Return mount point information:
1397  $result = $recursiveMountPid ?: [
1398  'mount_pid' => $mount_pid,
1399  'overlay' => $pageRec['mount_pid_ol'],
1400  'MPvar' => $mount_pid . '-' . $firstPageUid,
1401  'mount_point_rec' => $pageRec,
1402  'mount_pid_rec' => $mountRec
1403  ];
1404  } else {
1405  // Means, there SHOULD have been a mount point, but there was none!
1406  $result = -1;
1407  }
1408  }
1409  $cache->set($cacheIdentifier, $result);
1410  return $result;
1411  }
1413  /********************************
1414  *
1415  * Selecting records in general
1416  *
1417  ********************************/
1418 
1428  public function ‪checkRecord($table, $uid, $checkPage = 0)
1429  {
1430  $uid = (int)$uid;
1431  if (is_array(‪$GLOBALS['TCA'][$table]) && $uid > 0) {
1432  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1433  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context));
1434  $row = $queryBuilder->select('*')
1435  ->from($table)
1436  ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)))
1437  ->execute()
1438  ->fetch();
1439 
1440  if ($row) {
1441  $this->‪versionOL($table, $row);
1442  if (is_array($row)) {
1443  if ($checkPage) {
1444  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1445  ->getQueryBuilderForTable('pages');
1446  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context));
1447  $numRows = (int)$queryBuilder->count('*')
1448  ->from('pages')
1449  ->where(
1450  $queryBuilder->expr()->eq(
1451  'uid',
1452  $queryBuilder->createNamedParameter($row['pid'], \PDO::PARAM_INT)
1453  )
1454  )
1455  ->execute()
1456  ->fetchColumn();
1457  if ($numRows > 0) {
1458  return $row;
1459  }
1460  return 0;
1461  }
1462  return $row;
1463  }
1464  }
1465  }
1466  return 0;
1467  }
1468 
1479  public function ‪getRawRecord($table, $uid, ‪$fields = '*', $noWSOL = null)
1480  {
1481  $uid = (int)$uid;
1482  if (isset(‪$GLOBALS['TCA'][$table]) && is_array(‪$GLOBALS['TCA'][$table]) && $uid > 0) {
1483  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1484  $queryBuilder->getRestrictions()
1485  ->removeAll()
1486  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1487  $row = $queryBuilder->select(...GeneralUtility::trimExplode(',', ‪$fields, true))
1488  ->from($table)
1489  ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)))
1490  ->execute()
1491  ->fetch();
1492 
1493  if ($row) {
1494  if ($noWSOL !== null) {
1495  trigger_error('The fourth parameter of PageRepository->getRawRecord() will be removed in TYPO3 v10.0. Use a SQL statement directly.', E_USER_DEPRECATED);
1496  }
1497  // @deprecated - remove this if-clause in TYPO3 v10.0
1498  if (!$noWSOL) {
1499  $this->‪versionOL($table, $row);
1500  }
1501  if (is_array($row)) {
1502  return $row;
1503  }
1504  }
1505  }
1506  return 0;
1507  }
1508 
1522  public function ‪getRecordsByField($theTable, $theField, $theValue, $whereClause = '', $groupBy = '', $orderBy = '', $limit = '')
1523  {
1524  trigger_error('PageRepository->getRecordsByField() should not be used any longer, this method will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
1525  if (is_array(‪$GLOBALS['TCA'][$theTable])) {
1526  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($theTable);
1527  $queryBuilder->getRestrictions()
1528  ->removeAll()
1529  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1530 
1531  $queryBuilder->select('*')
1532  ->from($theTable)
1533  ->where($queryBuilder->expr()->eq($theField, $queryBuilder->createNamedParameter($theValue)));
1534 
1535  if ($whereClause !== '') {
1536  $queryBuilder->andWhere(‪QueryHelper::stripLogicalOperatorPrefix($whereClause));
1537  }
1538 
1539  if ($groupBy !== '') {
1540  $queryBuilder->groupBy(‪QueryHelper::parseGroupBy($groupBy));
1541  }
1542 
1543  if ($orderBy !== '') {
1544  foreach (‪QueryHelper::parseOrderBy($orderBy) as $orderPair) {
1545  [$fieldName, $order] = $orderPair;
1546  $queryBuilder->addOrderBy($fieldName, $order);
1547  }
1548  }
1549 
1550  if ($limit !== '') {
1551  if (strpos($limit, ',')) {
1552  $limitOffsetAndMax = GeneralUtility::intExplode(',', $limit);
1553  $queryBuilder->setFirstResult((int)$limitOffsetAndMax[0]);
1554  $queryBuilder->setMaxResults((int)$limitOffsetAndMax[1]);
1555  } else {
1556  $queryBuilder->setMaxResults((int)$limit);
1557  }
1558  }
1559 
1560  $rows = $queryBuilder->execute()->fetchAll();
1561 
1562  if (!empty($rows)) {
1563  return $rows;
1564  }
1565  }
1566  return null;
1567  }
1569  /********************************
1570  *
1571  * Standard clauses
1572  *
1573  ********************************/
1574 
1584  public function ‪deleteClause($table)
1585  {
1586  trigger_error('PageRepository->deleteClause() will be removed in TYPO3 v10.0. The delete clause can be applied via the DeletedRestrictions via QueryBuilder.', E_USER_DEPRECATED);
1587  return ‪$GLOBALS['TCA'][$table]['ctrl']['delete'] ? ' AND ' . $table . '.' . ‪$GLOBALS['TCA'][$table]['ctrl']['delete'] . '=0' : '';
1588  }
1589 
1607  public function ‪enableFields($table, $show_hidden = -1, $ignore_array = [], $noVersionPreview = false)
1608  {
1609  if ($show_hidden === -1) {
1610  // If show_hidden was not set from outside, use the current context
1611  $show_hidden = (int)$this->context->getPropertyFromAspect('visibility', $table === 'pages' ? 'includeHiddenPages' : 'includeHiddenContent', false);
1612  }
1613  // If show_hidden was not changed during the previous evaluation, do it here.
1614  $ctrl = ‪$GLOBALS['TCA'][$table]['ctrl'] ?? null;
1615  $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1616  ->getQueryBuilderForTable($table)
1617  ->expr();
1618  $constraints = [];
1619  if (is_array($ctrl)) {
1620  // Delete field check:
1621  if ($ctrl['delete']) {
1622  $constraints[] = $expressionBuilder->eq($table . '.' . $ctrl['delete'], 0);
1623  }
1624  if ($ctrl['versioningWS'] ?? false) {
1625  if (!$this->versioningWorkspaceId > 0) {
1626  // Filter out placeholder records (new/moved/deleted items)
1627  // in case we are NOT in a versioning preview (that means we are online!)
1628  $constraints[] = $expressionBuilder->lte(
1629  $table . '.t3ver_state',
1630  new VersionState(‪VersionState::DEFAULT_STATE)
1631  );
1632  } elseif ($table !== 'pages') {
1633  // show only records of live and of the current workspace
1634  // in case we are in a versioning preview
1635  $constraints[] = $expressionBuilder->orX(
1636  $expressionBuilder->eq($table . '.t3ver_wsid', 0),
1637  $expressionBuilder->eq($table . '.t3ver_wsid', (int)$this->versioningWorkspaceId)
1638  );
1639  }
1640 
1641  // Filter out versioned records
1642  if (!$noVersionPreview && empty($ignore_array['pid'])) {
1643  $constraints[] = $expressionBuilder->neq($table . '.pid', -1);
1644  }
1645  }
1646 
1647  // Enable fields:
1648  if (is_array($ctrl['enablecolumns'])) {
1649  // In case of versioning-preview, enableFields are ignored (checked in
1650  // versionOL())
1651  if ($this->versioningWorkspaceId <= 0 || !$ctrl['versioningWS'] || $noVersionPreview) {
1652  if (($ctrl['enablecolumns']['disabled'] ?? false) && !$show_hidden && !($ignore_array['disabled'] ?? false)) {
1653  $field = $table . '.' . $ctrl['enablecolumns']['disabled'];
1654  $constraints[] = $expressionBuilder->eq($field, 0);
1655  }
1656  if (($ctrl['enablecolumns']['starttime'] ?? false) && !($ignore_array['starttime'] ?? false)) {
1657  $field = $table . '.' . $ctrl['enablecolumns']['starttime'];
1658  $constraints[] = $expressionBuilder->lte(
1659  $field,
1660  $this->context->getPropertyFromAspect('date', 'accessTime', 0)
1661  );
1662  }
1663  if (($ctrl['enablecolumns']['endtime'] ?? false) && !($ignore_array['endtime'] ?? false)) {
1664  $field = $table . '.' . $ctrl['enablecolumns']['endtime'];
1665  $constraints[] = $expressionBuilder->orX(
1666  $expressionBuilder->eq($field, 0),
1667  $expressionBuilder->gt(
1668  $field,
1669  $this->context->getPropertyFromAspect('date', 'accessTime', 0)
1670  )
1671  );
1672  }
1673  if (($ctrl['enablecolumns']['fe_group'] ?? false) && !($ignore_array['fe_group'] ?? false)) {
1674  $field = $table . '.' . $ctrl['enablecolumns']['fe_group'];
1676  $this->‪getMultipleGroupsWhereClause($field, $table)
1677  );
1678  }
1679  // Call hook functions for additional enableColumns
1680  // It is used by the extension ingmar_accessctrl which enables assigning more
1681  // than one usergroup to content and page records
1682  $_params = [
1683  'table' => $table,
1684  'show_hidden' => $show_hidden,
1685  'ignore_array' => $ignore_array,
1686  'ctrl' => $ctrl
1687  ];
1688  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['addEnableColumns'] ?? [] as $_funcRef) {
1690  GeneralUtility::callUserFunction($_funcRef, $_params, $this)
1691  );
1692  }
1693  }
1694  }
1695  } else {
1696  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);
1697  }
1698 
1699  return empty($constraints) ? '' : ' AND ' . $expressionBuilder->andX(...$constraints);
1700  }
1701 
1711  public function ‪getMultipleGroupsWhereClause($field, $table)
1712  {
1713  if (!$this->context->hasAspect('frontend.user')) {
1714  return '';
1715  }
1717  $userAspect = $this->context->getAspect('frontend.user');
1718  $memberGroups = $userAspect->getGroupIds();
1719  $cache = $this->‪getRuntimeCache();
1720  $cacheIdentifier = 'PageRepository_groupAccessWhere_' . md5($field . '_' . $table . '_' . implode('_', $memberGroups));
1721  $cacheEntry = $cache->get($cacheIdentifier);
1722  if ($cacheEntry) {
1723  return $cacheEntry;
1724  }
1725  $expressionBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
1726  ->getQueryBuilderForTable($table)
1727  ->expr();
1728  $orChecks = [];
1729  // If the field is empty, then OK
1730  $orChecks[] = $expressionBuilder->eq($field, $expressionBuilder->literal(''));
1731  // If the field is NULL, then OK
1732  $orChecks[] = $expressionBuilder->isNull($field);
1733  // If the field contains zero, then OK
1734  $orChecks[] = $expressionBuilder->eq($field, $expressionBuilder->literal('0'));
1735  foreach ($memberGroups as $value) {
1736  $orChecks[] = $expressionBuilder->inSet($field, $expressionBuilder->literal($value));
1737  }
1738 
1739  $accessGroupWhere = ' AND (' . $expressionBuilder->orX(...$orChecks) . ')';
1740  $cache->set($cacheIdentifier, $accessGroupWhere);
1741  return $accessGroupWhere;
1742  }
1743 
1744  /**********************
1745  *
1746  * Versioning Preview
1747  *
1748  **********************/
1749 
1768  public function ‪fixVersioningPid($table, &$rr)
1769  {
1770  if ($this->versioningWorkspaceId > 0 && is_array($rr) && (int)$rr['pid'] === -1 && ‪$GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
1771  $oid = 0;
1772  $wsid = 0;
1773  // Check values for t3ver_oid and t3ver_wsid:
1774  if (isset($rr['t3ver_oid']) && isset($rr['t3ver_wsid'])) {
1775  // If "t3ver_oid" is already a field, just set this:
1776  $oid = $rr['t3ver_oid'];
1777  $wsid = $rr['t3ver_wsid'];
1778  } else {
1779  // Otherwise we have to expect "uid" to be in the record and look up based
1780  // on this:
1781  $uid = (int)$rr['uid'];
1782  if ($uid > 0) {
1783  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1784  $queryBuilder->getRestrictions()
1785  ->removeAll()
1786  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1787  $newPidRec = $queryBuilder->select('t3ver_oid', 't3ver_wsid')
1788  ->from($table)
1789  ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)))
1790  ->execute()
1791  ->fetch();
1792 
1793  if (is_array($newPidRec)) {
1794  $oid = $newPidRec['t3ver_oid'];
1795  $wsid = $newPidRec['t3ver_wsid'];
1796  }
1797  }
1798  }
1799  // If workspace ids matches and ID of current online version is found, look up
1800  // the PID value of that:
1801  if ($oid && (int)$wsid === (int)$this->versioningWorkspaceId) {
1802  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1803  $queryBuilder->getRestrictions()
1804  ->removeAll()
1805  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1806  $oidRec = $queryBuilder->select('pid')
1807  ->from($table)
1808  ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($oid, \PDO::PARAM_INT)))
1809  ->execute()
1810  ->fetch();
1811 
1812  if (is_array($oidRec)) {
1813  // SWAP uid as well? Well no, because when fixing a versioning PID happens it is
1814  // assumed that this is a "branch" type page and therefore the uid should be
1815  // kept (like in versionOL()). However if the page is NOT a branch version it
1816  // should not happen - but then again, direct access to that uid should not
1817  // happen!
1818  $rr['_ORIG_pid'] = $rr['pid'];
1819  $rr['pid'] = $oidRec['pid'];
1820  }
1821  }
1822  }
1823  // Changing PID in case of moving pointer:
1824  if ($movePlhRec = $this->‪getMovePlaceholder($table, $rr['uid'], 'pid')) {
1825  $rr['pid'] = $movePlhRec['pid'];
1826  }
1827  }
1828 
1848  public function ‪versionOL($table, &$row, $unsetMovePointers = false, $bypassEnableFieldsCheck = false)
1849  {
1850  if ($this->versioningWorkspaceId > 0 && is_array($row)) {
1851  // will overlay any movePlhOL found with the real record, which in turn
1852  // will be overlaid with its workspace version if any.
1853  $movePldSwap = $this->‪movePlhOL($table, $row);
1854  // implode(',',array_keys($row)) = Using fields from original record to make
1855  // sure no additional fields are selected. This is best for eg. getPageOverlay()
1856  // Computed properties are excluded since those would lead to SQL errors.
1857  $fieldNames = implode(',', array_keys($this->‪purgeComputedProperties($row)));
1858  if ($wsAlt = $this->‪getWorkspaceVersionOfRecord($this->versioningWorkspaceId, $table, $row['uid'], $fieldNames, $bypassEnableFieldsCheck)) {
1859  if (is_array($wsAlt)) {
1860  // Always fix PID (like in fixVersioningPid() above). [This is usually not
1861  // the important factor for versioning OL]
1862  // Keep the old (-1) - indicates it was a version...
1863  $wsAlt['_ORIG_pid'] = $wsAlt['pid'];
1864  // Set in the online versions PID.
1865  $wsAlt['pid'] = $row['pid'];
1866  // For versions of single elements or page+content, preserve online UID and PID
1867  // (this will produce true "overlay" of element _content_, not any references)
1868  // For page+content the "_ORIG_uid" should actually be used as PID for selection.
1869  $wsAlt['_ORIG_uid'] = $wsAlt['uid'];
1870  $wsAlt['uid'] = $row['uid'];
1871  // Translate page alias as well so links are pointing to the _online_ page:
1872  if ($table === 'pages') {
1873  $wsAlt['alias'] = $row['alias'];
1874  }
1875  // Changing input record to the workspace version alternative:
1876  $row = $wsAlt;
1877  // Check if it is deleted/new
1878  $rowVersionState = ‪VersionState::cast($row['t3ver_state'] ?? null);
1879  if (
1880  $rowVersionState->equals(‪VersionState::NEW_PLACEHOLDER)
1881  || $rowVersionState->equals(‪VersionState::DELETE_PLACEHOLDER)
1882  ) {
1883  // Unset record if it turned out to be deleted in workspace
1884  $row = false;
1885  }
1886  // Check if move-pointer in workspace (unless if a move-placeholder is the
1887  // reason why it appears!):
1888  // You have to specifically set $unsetMovePointers in order to clear these
1889  // because it is normally a display issue if it should be shown or not.
1890  if (
1891  (
1892  $rowVersionState->equals(‪VersionState::MOVE_POINTER)
1893  && !$movePldSwap
1894  ) && $unsetMovePointers
1895  ) {
1896  // Unset record if it turned out to be deleted in workspace
1897  $row = false;
1898  }
1899  } else {
1900  // No version found, then check if t3ver_state = VersionState::NEW_PLACEHOLDER
1901  // (online version is dummy-representation)
1902  // Notice, that unless $bypassEnableFieldsCheck is TRUE, the $row is unset if
1903  // enablefields for BOTH the version AND the online record deselects it. See
1904  // note for $bypassEnableFieldsCheck
1906  $versionState = ‪VersionState::cast($row['t3ver_state']);
1907  if ($wsAlt <= -1 || $versionState->indicatesPlaceholder()) {
1908  // Unset record if it turned out to be "hidden"
1909  $row = false;
1910  }
1911  }
1912  }
1913  }
1914  }
1915 
1926  protected function ‪movePlhOL($table, &$row)
1927  {
1928  if (!empty(‪$GLOBALS['TCA'][$table]['ctrl']['versioningWS'])
1929  && (int)‪VersionState::cast($row['t3ver_state'])->equals(‪VersionState::MOVE_PLACEHOLDER)
1930  ) {
1931  $moveID = 0;
1932  // If t3ver_move_id is not found, then find it (but we like best if it is here)
1933  if (!isset($row['t3ver_move_id'])) {
1934  if ((int)$row['uid'] > 0) {
1935  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1936  $queryBuilder->getRestrictions()
1937  ->removeAll()
1938  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1939  $moveIDRec = $queryBuilder->select('t3ver_move_id')
1940  ->from($table)
1941  ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($row['uid'], \PDO::PARAM_INT)))
1942  ->execute()
1943  ->fetch();
1944 
1945  if (is_array($moveIDRec)) {
1946  $moveID = $moveIDRec['t3ver_move_id'];
1947  }
1948  }
1949  } else {
1950  $moveID = $row['t3ver_move_id'];
1951  }
1952  // Find pointed-to record.
1953  if ($moveID) {
1954  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1955  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context));
1956  $queryBuilder->getRestrictions()->removeByType(HiddenRestriction::class);
1957  $origRow = $queryBuilder->select(...array_keys($this->‪purgeComputedProperties($row)))
1958  ->from($table)
1959  ->where(
1960  $queryBuilder->expr()->eq(
1961  'uid',
1962  $queryBuilder->createNamedParameter($moveID, \PDO::PARAM_INT)
1963  )
1964  )
1965  ->setMaxResults(1)
1966  ->execute()
1967  ->fetch();
1968 
1969  if ($origRow) {
1970  $row = $origRow;
1971  return true;
1972  }
1973  }
1974  }
1975  return false;
1976  }
1977 
1987  protected function ‪getMovePlaceholder($table, $uid, ‪$fields = '*')
1988  {
1989  $workspace = (int)$this->versioningWorkspaceId;
1990  if (!empty(‪$GLOBALS['TCA'][$table]['ctrl']['versioningWS']) && $workspace > 0) {
1991  // Select workspace version of record:
1992  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
1993  $queryBuilder->getRestrictions()
1994  ->removeAll()
1995  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
1996 
1997  $row = $queryBuilder->select(...GeneralUtility::trimExplode(',', ‪$fields, true))
1998  ->from($table)
1999  ->where(
2000  $queryBuilder->expr()->neq('pid', $queryBuilder->createNamedParameter(-1, \PDO::PARAM_INT)),
2001  $queryBuilder->expr()->eq(
2002  't3ver_state',
2003  $queryBuilder->createNamedParameter(
2005  \PDO::PARAM_INT
2006  )
2007  ),
2008  $queryBuilder->expr()->eq(
2009  't3ver_move_id',
2010  $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
2011  ),
2012  $queryBuilder->expr()->eq(
2013  't3ver_wsid',
2014  $queryBuilder->createNamedParameter($workspace, \PDO::PARAM_INT)
2015  )
2016  )
2017  ->setMaxResults(1)
2018  ->execute()
2019  ->fetch();
2020 
2021  if (is_array($row)) {
2022  return $row;
2023  }
2024  }
2025  return false;
2026  }
2027 
2039  public function ‪getWorkspaceVersionOfRecord($workspace, $table, $uid, ‪$fields = '*', $bypassEnableFieldsCheck = false)
2040  {
2041  if ($workspace !== 0 && !empty(‪$GLOBALS['TCA'][$table]['ctrl']['versioningWS'])) {
2042  $workspace = (int)$workspace;
2043  $uid = (int)$uid;
2044  // Select workspace version of record, only testing for deleted.
2045  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
2046  $queryBuilder->getRestrictions()
2047  ->removeAll()
2048  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
2049 
2050  $newrow = $queryBuilder->select(...GeneralUtility::trimExplode(',', ‪$fields, true))
2051  ->from($table)
2052  ->where(
2053  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter(-1, \PDO::PARAM_INT)),
2054  $queryBuilder->expr()->eq(
2055  't3ver_oid',
2056  $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
2057  ),
2058  $queryBuilder->expr()->eq(
2059  't3ver_wsid',
2060  $queryBuilder->createNamedParameter($workspace, \PDO::PARAM_INT)
2061  )
2062  )
2063  ->setMaxResults(1)
2064  ->execute()
2065  ->fetch();
2066 
2067  // If version found, check if it could have been selected with enableFields on
2068  // as well:
2069  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
2070  $queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class, $this->context));
2071  // Remove the frontend workspace restriction because we are testing a version record
2072  $queryBuilder->getRestrictions()->removeByType(FrontendWorkspaceRestriction::class);
2073  $queryBuilder->select('uid')
2074  ->from($table)
2075  ->setMaxResults(1);
2076 
2077  if (is_array($newrow)) {
2078  $queryBuilder->where(
2079  $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter(-1, \PDO::PARAM_INT)),
2080  $queryBuilder->expr()->eq(
2081  't3ver_oid',
2082  $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)
2083  ),
2084  $queryBuilder->expr()->eq(
2085  't3ver_wsid',
2086  $queryBuilder->createNamedParameter($workspace, \PDO::PARAM_INT)
2087  )
2088  );
2089  if ($bypassEnableFieldsCheck || $queryBuilder->execute()->fetchColumn()) {
2090  // Return offline version, tested for its enableFields.
2091  return $newrow;
2092  }
2093  // Return -1 because offline version was de-selected due to its enableFields.
2094  return -1;
2095  }
2096  // OK, so no workspace version was found. Then check if online version can be
2097  // selected with full enable fields and if so, return 1:
2098  $queryBuilder->where(
2099  $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT))
2100  );
2101  if ($bypassEnableFieldsCheck || $queryBuilder->execute()->fetchColumn()) {
2102  // Means search was done, but no version found.
2103  return 1;
2104  }
2105  // Return -2 because the online record was de-selected due to its enableFields.
2106  return -2;
2107  }
2108  // No look up in database because versioning not enabled / or workspace not
2109  // offline
2110  return false;
2111  }
2112 
2120  public function ‪checkWorkspaceAccess($wsid)
2121  {
2122  trigger_error('PageRepository->checkWorkspaceAccess() will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
2123  if (!$this->‪getBackendUser() || !‪ExtensionManagementUtility::isLoaded('workspaces')) {
2124  return false;
2125  }
2126  if (!isset($this->workspaceCache[$wsid])) {
2127  $this->workspaceCache[$wsid] = $this->‪getBackendUser()->checkWorkspace($wsid);
2128  }
2129  return (string)$this->workspaceCache[$wsid]['_ACCESS'] !== '';
2130  }
2131 
2141  public function ‪getFileReferences($tableName, $fieldName, array $element)
2142  {
2143  trigger_error('PageRepository->getFileReferences() should not be used any longer, this method will be removed in TYPO3 v10.0.', E_USER_DEPRECATED);
2145  $fileRepository = GeneralUtility::makeInstance(FileRepository::class);
2146  $currentId = !empty($element['uid']) ? $element['uid'] : 0;
2147 
2148  // Fetch the references of the default element
2149  try {
2150  $references = $fileRepository->findByRelation($tableName, $fieldName, $currentId);
2151  } catch (FileDoesNotExistException $e) {
2156  return [];
2157  } catch (\InvalidArgumentException $e) {
2162  $logMessage = $e->getMessage() . ' (table: "' . $tableName . '", fieldName: "' . $fieldName . '", currentId: ' . $currentId . ')';
2163  $this->logger->error($logMessage, ['exception' => $e]);
2164  return [];
2165  }
2166 
2167  $localizedId = null;
2168  if (isset($element['_LOCALIZED_UID'])) {
2169  $localizedId = $element['_LOCALIZED_UID'];
2170  } elseif (isset($element['_PAGES_OVERLAY_UID'])) {
2171  $localizedId = $element['_PAGES_OVERLAY_UID'];
2172  }
2173 
2174  $isTableLocalizable = (
2175  !empty(‪$GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
2176  && !empty(‪$GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
2177  );
2178  if ($isTableLocalizable && $localizedId !== null) {
2179  $localizedReferences = $fileRepository->findByRelation($tableName, $fieldName, $localizedId);
2180  $references = $localizedReferences;
2181  }
2182 
2183  return $references;
2184  }
2185 
2193  protected function ‪purgeComputedProperties(array $row)
2194  {
2195  foreach ($this->computedPropertyNames as $computedPropertyName) {
2196  if (array_key_exists($computedPropertyName, $row)) {
2197  unset($row[$computedPropertyName]);
2198  }
2199  }
2200  return $row;
2201  }
2202 
2209  protected function ‪getBackendUser()
2210  {
2211  return ‪$GLOBALS['BE_USER'];
2212  }
2213 
2217  protected function ‪getRuntimeCache(): VariableFrontend
2218  {
2219  return GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_runtime');
2220  }
2221 }
‪TYPO3\CMS\Frontend\Page\PageRepository\$context
‪Context $context
Definition: PageRepository.php:187
‪TYPO3\CMS\Frontend\Page\PageRepository\getMultipleGroupsWhereClause
‪string getMultipleGroupsWhereClause($field, $table)
Definition: PageRepository.php:1695
‪TYPO3\CMS\Frontend\Page\PageRepository\$computedPropertyNames
‪array $computedPropertyNames
Definition: PageRepository.php:154
‪TYPO3\CMS\Core\Database\Query\QueryHelper\parseOrderBy
‪static array array[] parseOrderBy(string $input)
Definition: QueryHelper.php:42
‪TYPO3\CMS\Frontend\Page\PageRepository\getRecordOverlay
‪mixed getRecordOverlay($table, $row, $sys_language_content, $OLmode='')
Definition: PageRepository.php:738
‪TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction
Definition: HiddenRestriction.php:25
‪TYPO3\CMS\Frontend\Page\PageRepository\DOKTYPE_MOUNTPOINT
‪const DOKTYPE_MOUNTPOINT
Definition: PageRepository.php:172
‪TYPO3\CMS\Frontend\Page\PageRepository\getPageOverlay
‪array getPageOverlay($pageInput, $languageUid=null)
Definition: PageRepository.php:529
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger($var)
Definition: MathUtility.php:73
‪TYPO3\CMS\Frontend\Page\PageRepository\$sys_language_uid
‪int $sys_language_uid
Definition: PageRepository.php:97
‪TYPO3\CMS\Frontend\Page\PageRepository\$error_getRootLine
‪string $error_getRootLine
Definition: PageRepository.php:126
‪TYPO3\CMS\Core\Versioning\VersionState\NEW_PLACEHOLDER
‪const NEW_PLACEHOLDER
Definition: VersionState.php:46
‪TYPO3\CMS\Frontend\Page\PageRepository\getRecordsByField
‪mixed getRecordsByField($theTable, $theField, $theValue, $whereClause='', $groupBy='', $orderBy='', $limit='')
Definition: PageRepository.php:1506
‪TYPO3\CMS\Frontend\Page\PageRepository\$cache_getPage
‪array $cache_getPage
Definition: PageRepository.php:136
‪TYPO3\CMS\Frontend\Page\PageRepository\DOKTYPE_SHORTCUT
‪const DOKTYPE_SHORTCUT
Definition: PageRepository.php:170
‪TYPO3\CMS\Frontend\Page\PageRepository\$where_hid_del
‪string $where_hid_del
Definition: PageRepository.php:85
‪TYPO3\CMS\Frontend\Page\PageRepository\getPagesOverlay
‪array getPagesOverlay(array $pagesInput, $languageUid=null)
Definition: PageRepository.php:551
‪TYPO3\CMS\Frontend\Page\PageRepository\getRuntimeCache
‪VariableFrontend getRuntimeCache()
Definition: PageRepository.php:2201
‪TYPO3\CMS\Core\Context\LanguageAspect\getId
‪int getId()
Definition: LanguageAspect.php:109
‪TYPO3\CMS\Frontend\Page\PageRepository\enableFields
‪string enableFields($table, $show_hidden=-1, $ignore_array=[], $noVersionPreview=false)
Definition: PageRepository.php:1591
‪TYPO3\CMS\Core\Database\Query\QueryHelper\parseGroupBy
‪static array string[] parseGroupBy(string $input)
Definition: QueryHelper.php:100
‪TYPO3\CMS\Frontend\Page\PageRepository\fixVersioningPid
‪fixVersioningPid($table, &$rr)
Definition: PageRepository.php:1752
‪TYPO3\CMS\Frontend\Page\PageRepository\$deprecatedPublicMethods
‪array $deprecatedPublicMethods
Definition: PageRepository.php:73
‪TYPO3\CMS\Frontend\Page\PageRepository\$deprecatedPublicProperties
‪array $deprecatedPublicProperties
Definition: PageRepository.php:61
‪TYPO3\CMS\Frontend\Page\PageRepository\DOKTYPE_SPACER
‪const DOKTYPE_SPACER
Definition: PageRepository.php:173
‪TYPO3\CMS\Core\Utility\RootlineUtility
Definition: RootlineUtility.php:36
‪TYPO3\CMS\Core\Database\Query\Restriction\FrontendWorkspaceRestriction
Definition: FrontendWorkspaceRestriction.php:28
‪TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException
Definition: FileDoesNotExistException.php:21
‪TYPO3\CMS\Core\Versioning\VersionState\DELETE_PLACEHOLDER
‪const DELETE_PLACEHOLDER
Definition: VersionState.php:54
‪TYPO3\CMS\Frontend\Page\PageRepository\getPage
‪array getPage($uid, $disableGroupAccessCheck=false)
Definition: PageRepository.php:312
‪TYPO3\CMS\Frontend\Page\PageRepository\getLanguageOverlay
‪array null getLanguageOverlay(string $table, array $row)
Definition: PageRepository.php:495
‪TYPO3\CMS\Core\Versioning\VersionState\MOVE_POINTER
‪const MOVE_POINTER
Definition: VersionState.php:72
‪TYPO3\CMS\Frontend\Page\PageRepository\getPageOverlaysForLanguageUids
‪array getPageOverlaysForLanguageUids(array $pageUids, array $languageUids)
Definition: PageRepository.php:667
‪$fields
‪$fields
Definition: pages.php:4
‪TYPO3\CMS\Core\Database\Query\Restriction\FrontendGroupRestriction
Definition: FrontendGroupRestriction.php:28
‪TYPO3\CMS\Core\Context\Context
Definition: Context.php:49
‪TYPO3\CMS\Frontend\Page\PageRepositoryGetRecordOverlayHookInterface
Definition: PageRepositoryGetRecordOverlayHookInterface.php:21
‪TYPO3\CMS\Frontend\Page\PageRepository\getMountPointInfo
‪mixed getMountPointInfo($pageId, $pageRec=false, $prevMountPids=[], $firstPageUid=0)
Definition: PageRepository.php:1310
‪TYPO3\CMS\Frontend\Page\PageRepositoryGetPageOverlayHookInterface
Definition: PageRepositoryGetPageOverlayHookInterface.php:21
‪TYPO3\CMS\Frontend\Page\PageRepository\SHORTCUT_MODE_RANDOM_SUBPAGE
‪const SHORTCUT_MODE_RANDOM_SUBPAGE
Definition: PageRepository.php:182
‪TYPO3\CMS\Frontend\Page\PageRepository\getMenu
‪array getMenu($pageId, $fields=' *', $sortField='sorting', $additionalWhereClause='', $checkShortcuts=true)
Definition: PageRepository.php:852
‪TYPO3\CMS\Frontend\Page\PageRepository\movePlhOL
‪bool movePlhOL($table, &$row)
Definition: PageRepository.php:1910
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility
Definition: ExtensionManagementUtility.php:36
‪TYPO3\CMS\Frontend\Page\PageRepository\$where_groupAccess
‪string $where_groupAccess
Definition: PageRepository.php:91
‪TYPO3\CMS\Frontend\Page\PageRepository\$versioningWorkspaceId
‪int $versioningWorkspaceId
Definition: PageRepository.php:116
‪TYPO3\CMS\Frontend\Page\PageRepository\$versioningPreview
‪bool $versioningPreview
Definition: PageRepository.php:106
‪TYPO3\CMS\Core\Type\Enumeration\cast
‪static static cast($value)
Definition: Enumeration.php:182
‪TYPO3\CMS\Frontend\Page\PageRepository\DOKTYPE_LINK
‪const DOKTYPE_LINK
Definition: PageRepository.php:169
‪TYPO3\CMS\Frontend\Page\PageRepository\versionOL
‪versionOL($table, &$row, $unsetMovePointers=false, $bypassEnableFieldsCheck=false)
Definition: PageRepository.php:1832
‪TYPO3\CMS\Frontend\Page\PageRepository\isPageSuitableForLanguage
‪bool isPageSuitableForLanguage(array $page, LanguageAspect $languageAspect)
Definition: PageRepository.php:621
‪TYPO3\CMS\Core\Context\LanguageAspect\getFallbackChain
‪getFallbackChain()
Definition: LanguageAspect.php:126
‪TYPO3\CMS\Frontend\Page\PageRepository\$error_getRootLine_failPid
‪int $error_getRootLine_failPid
Definition: PageRepository.php:132
‪TYPO3\CMS\Core\Database\Query\QueryHelper
Definition: QueryHelper.php:30
‪TYPO3\CMS\Frontend\Page\PageRepositoryGetPageHookInterface
Definition: PageRepositoryGetPageHookInterface.php:21
‪TYPO3\CMS\Core\Resource\FileRepository
Definition: FileRepository.php:32
‪TYPO3\CMS\Frontend\Page\PageRepository\getFirstWebPage
‪mixed getFirstWebPage($uid)
Definition: PageRepository.php:418
‪TYPO3\CMS\Frontend\Page\PageRepository\DOKTYPE_SYSFOLDER
‪const DOKTYPE_SYSFOLDER
Definition: PageRepository.php:174
‪TYPO3\CMS\Frontend\Page\PageRepository\checkWorkspaceAccess
‪bool checkWorkspaceAccess($wsid)
Definition: PageRepository.php:2104
‪TYPO3\CMS\Frontend\Page\PageRepository
Definition: PageRepository.php:53
‪TYPO3\CMS\Frontend\Page\PageRepository\getRawRecord
‪mixed getRawRecord($table, $uid, $fields=' *', $noWSOL=null)
Definition: PageRepository.php:1463
‪TYPO3\CMS\Frontend\Page\PageRepository\$cache_getMountPointInfo
‪array $cache_getMountPointInfo
Definition: PageRepository.php:148
‪TYPO3\CMS\Core\Cache\Frontend\VariableFrontend
Definition: VariableFrontend.php:24
‪TYPO3\CMS\Frontend\Page\PageRepository\getMovePlaceholder
‪array getMovePlaceholder($table, $uid, $fields=' *')
Definition: PageRepository.php:1971
‪TYPO3\CMS\Frontend\Page\PageRepository\getBackendUser
‪TYPO3 CMS Core Authentication BackendUserAuthentication getBackendUser()
Definition: PageRepository.php:2193
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\isLoaded
‪static bool isLoaded($key, $exitOnError=null)
Definition: ExtensionManagementUtility.php:115
‪TYPO3\CMS\Core\Cache\CacheManager
Definition: CacheManager.php:34
‪TYPO3\CMS\Frontend\Page\PageRepository\DOKTYPE_DEFAULT
‪const DOKTYPE_DEFAULT
Definition: PageRepository.php:168
‪TYPO3\CMS\Frontend\Page\PageRepository\getExtURL
‪string bool getExtURL($pagerow)
Definition: PageRepository.php:1259
‪TYPO3\CMS\Frontend\Page\PageRepository\getFileReferences
‪array getFileReferences($tableName, $fieldName, array $element)
Definition: PageRepository.php:2125
‪TYPO3\CMS\Core\Context\LanguageAspect
Definition: LanguageAspect.php:55
‪TYPO3\CMS\Frontend\Page
Definition: CacheHashCalculator.php:2
‪TYPO3\CMS\Core\Compatibility\PublicMethodDeprecationTrait
Definition: PublicMethodDeprecationTrait.php:68
‪TYPO3\CMS\Frontend\Page\PageRepository\__construct
‪__construct(Context $context=null)
Definition: PageRepository.php:195
‪TYPO3\CMS\Frontend\Page\PageRepository\SHORTCUT_MODE_FIRST_SUBPAGE
‪const SHORTCUT_MODE_FIRST_SUBPAGE
Definition: PageRepository.php:181
‪TYPO3\CMS\Core\Versioning\VersionState
Definition: VersionState.php:23
‪$output
‪$output
Definition: annotationChecker.php:113
‪TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
Definition: AspectNotFoundException.php:24
‪TYPO3\CMS\Frontend\Page\PageRepository\getPage_noCheck
‪array getPage_noCheck($uid)
Definition: PageRepository.php:380
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:31
‪TYPO3\CMS\Frontend\Page\PageRepository\getMenuForPages
‪array getMenuForPages(array $pageIds, $fields=' *', $sortField='sorting', $additionalWhereClause='', $checkShortcuts=true)
Definition: PageRepository.php:870
‪TYPO3\CMS\Frontend\Page\PageRepository\$workspaceCache
‪array $workspaceCache
Definition: PageRepository.php:120
‪TYPO3\CMS\Core\Error\Http\ShortcutTargetPageNotFoundException
Definition: ShortcutTargetPageNotFoundException.php:22
‪TYPO3\CMS\Frontend\Page\PageRepository\checkRecord
‪array int checkRecord($table, $uid, $checkPage=0)
Definition: PageRepository.php:1412
‪TYPO3\CMS\Frontend\Page\PageRepository\$cache_getPage_noCheck
‪array $cache_getPage_noCheck
Definition: PageRepository.php:140
‪TYPO3\CMS\Frontend\Page\PageRepository\$cache_getPageIdFromAlias
‪array $cache_getPageIdFromAlias
Definition: PageRepository.php:144
‪TYPO3\CMS\Frontend\Page\PageRepository\checkValidShortcutOfPage
‪array checkValidShortcutOfPage(array $page, $additionalWhereClause)
Definition: PageRepository.php:1024
‪TYPO3\CMS\Core\Database\Query\QueryHelper\stripLogicalOperatorPrefix
‪static string stripLogicalOperatorPrefix(string $constraint)
Definition: QueryHelper.php:163
‪TYPO3\CMS\Frontend\Page\PageRepositoryInitHookInterface
Definition: PageRepositoryInitHookInterface.php:21
‪TYPO3\CMS\Core\Versioning\VersionState\DEFAULT_STATE
‪const DEFAULT_STATE
Definition: VersionState.php:38
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:26
‪TYPO3\CMS\Frontend\Page\PageRepository\addMountPointParameterToPage
‪array addMountPointParameterToPage(array $page)
Definition: PageRepository.php:991
‪TYPO3\CMS\Frontend\Page\PageRepository\getSubpagesForPages
‪array getSubpagesForPages(array $pageIds, string $fields=' *', string $sortField='sorting', string $additionalWhereClause='', bool $checkShortcuts=true, bool $parentPages=true)
Definition: PageRepository.php:910
‪TYPO3\CMS\Frontend\Page\PageRepository\getDomainStartPage
‪mixed getDomainStartPage($domain, $path='', $request_uri='')
Definition: PageRepository.php:1162
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:21
‪TYPO3\CMS\Frontend\Page\PageRepository\DOKTYPE_RECYCLER
‪const DOKTYPE_RECYCLER
Definition: PageRepository.php:175
‪TYPO3\CMS\Frontend\Page\PageRepository\getRootLine
‪array getRootLine($uid, $MP='', $ignoreMPerrors=null)
Definition: PageRepository.php:1230
‪TYPO3\CMS\Frontend\Page\PageRepository\getPageShortcut
‪mixed getPageShortcut($shortcutFieldValue, $shortcutMode, $thisUid, $iteration=20, $pageLog=[], $disableGroupCheck=false)
Definition: PageRepository.php:1095
‪TYPO3\CMS\Frontend\Page\PageRepository\purgeComputedProperties
‪array purgeComputedProperties(array $row)
Definition: PageRepository.php:2177
‪TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait
Definition: PublicPropertyDeprecationTrait.php:66
‪TYPO3\CMS\Frontend\Page\PageRepository\init
‪init($show_hidden)
Definition: PageRepository.php:217
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:44
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Frontend\Page\PageRepository\SHORTCUT_MODE_NONE
‪const SHORTCUT_MODE_NONE
Definition: PageRepository.php:180
‪TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer
Definition: FrontendRestrictionContainer.php:29
‪TYPO3\CMS\Frontend\Page\PageRepository\SHORTCUT_MODE_PARENT_PAGE
‪const SHORTCUT_MODE_PARENT_PAGE
Definition: PageRepository.php:183
‪TYPO3\CMS\Frontend\Page\PageRepository\getLanguageFallbackChain
‪int[] getLanguageFallbackChain(?LanguageAspect $languageAspect)
Definition: PageRepository.php:646
‪TYPO3\CMS\Core\Context\UserAspect
Definition: UserAspect.php:36
‪TYPO3\CMS\Frontend\Page\PageRepository\getPageIdFromAlias
‪int getPageIdFromAlias($alias)
Definition: PageRepository.php:452
‪TYPO3\CMS\Frontend\Page\PageRepository\getWorkspaceVersionOfRecord
‪mixed getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields=' *', $bypassEnableFieldsCheck=false)
Definition: PageRepository.php:2023
‪TYPO3\CMS\Frontend\Page\PageRepository\deleteClause
‪string deleteClause($table)
Definition: PageRepository.php:1568
‪TYPO3\CMS\Core\Versioning\VersionState\MOVE_PLACEHOLDER
‪const MOVE_PLACEHOLDER
Definition: VersionState.php:71
‪TYPO3\CMS\Frontend\Page\PageRepository\DOKTYPE_BE_USER_SECTION
‪const DOKTYPE_BE_USER_SECTION
Definition: PageRepository.php:171