TYPO3 CMS  TYPO3_7-6
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 
25 
35 {
39  public $urltypes = ['', 'http://', 'ftp://', 'mailto:', 'https://'];
40 
48  public $where_hid_del = ' AND pages.deleted=0';
49 
55  public $where_groupAccess = '';
56 
60  public $sys_language_uid = 0;
61 
69  public $versioningPreview = false;
70 
75 
82 
86  public $workspaceCache = [];
87 
93  public $error_getRootLine = '';
94 
101 
105  protected $cache_getRootLine = [];
106 
110  protected $cache_getPage = [];
111 
115  protected $cache_getPage_noCheck = [];
116 
121 
125  protected $cache_getMountPointInfo = [];
126 
131  'sys_file_metadata',
132  'sys_category',
133  ];
134 
141  '_LOCALIZED_UID',
142  '_MP_PARAM',
143  '_ORIG_uid',
144  '_ORIG_pid',
145  '_PAGES_OVERLAY',
146  '_PAGES_OVERLAY_UID',
147  '_PAGES_OVERLAY_LANGUAGE',
148  ];
149 
153  const DOKTYPE_DEFAULT = 1;
154  const DOKTYPE_LINK = 3;
155  const DOKTYPE_SHORTCUT = 4;
158  const DOKTYPE_SPACER = 199;
159  const DOKTYPE_SYSFOLDER = 254;
160  const DOKTYPE_RECYCLER = 255;
161 
169 
180  public function init($show_hidden)
181  {
182  $this->where_groupAccess = '';
183 
184  if ($this->versioningPreview) {
185  // For version previewing, make sure that enable-fields are not
186  // de-selecting hidden pages - we need versionOL() to unset them only
187  // if the overlay record instructs us to.
188  // Clear where_hid_del and restrict to live and current workspaces
189  $this->where_hid_del = ' AND pages.deleted=0 AND (pages.t3ver_wsid=0 OR pages.t3ver_wsid=' . (int)$this->versioningWorkspaceId . ')';
190  } else {
191  // add starttime / endtime, and check for hidden/deleted
192  // Filter out new/deleted place-holder pages in case we are NOT in a
193  // versioning preview (that means we are online!)
194  $this->where_hid_del = $this->enableFields('pages', $show_hidden, ['fe_group' => true], true);
195  }
196  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class]['init'])) {
197  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][self::class]['init'] as $classRef) {
198  $hookObject = GeneralUtility::makeInstance($classRef);
199  if (!$hookObject instanceof PageRepositoryInitHookInterface) {
200  throw new \UnexpectedValueException($hookObject . ' must implement interface ' . PageRepositoryInitHookInterface::class, 1379579812);
201  }
202  $hookObject->init_postProcess($this);
203  }
204  }
205  }
206 
207  /**************************
208  *
209  * Selecting page records
210  *
211  **************************/
212 
224  public function getPage($uid, $disableGroupAccessCheck = false)
225  {
226  // Hook to manipulate the page uid for special overlay handling
227  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPage'])) {
228  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPage'] as $classRef) {
229  $hookObject = GeneralUtility::getUserObj($classRef);
230  if (!$hookObject instanceof PageRepositoryGetPageHookInterface) {
231  throw new \UnexpectedValueException($classRef . ' must implement interface ' . PageRepositoryGetPageHookInterface::class, 1251476766);
232  }
233  $hookObject->getPage_preProcess($uid, $disableGroupAccessCheck, $this);
234  }
235  }
236  $accessCheck = $disableGroupAccessCheck ? '' : $this->where_groupAccess;
237  $cacheKey = md5($accessCheck . '-' . $this->where_hid_del . '-' . $this->sys_language_uid);
238  if (is_array($this->cache_getPage[$uid][$cacheKey])) {
239  return $this->cache_getPage[$uid][$cacheKey];
240  }
241  $result = [];
242  $row = $this->getDatabaseConnection()->exec_SELECTgetSingleRow('*', 'pages', 'uid=' . (int)$uid . $this->where_hid_del . $accessCheck);
243  if ($row) {
244  $this->versionOL('pages', $row);
245  if (is_array($row)) {
246  $result = $this->getPageOverlay($row);
247  }
248  }
249  $this->cache_getPage[$uid][$cacheKey] = $result;
250  return $result;
251  }
252 
261  public function getPage_noCheck($uid)
262  {
263  if ($this->cache_getPage_noCheck[$uid]) {
264  return $this->cache_getPage_noCheck[$uid];
265  }
266  $res = $this->getDatabaseConnection()->exec_SELECTquery('*', 'pages', 'uid=' . (int)$uid . $this->deleteClause('pages'));
267  $row = $this->getDatabaseConnection()->sql_fetch_assoc($res);
268  $this->getDatabaseConnection()->sql_free_result($res);
269  $result = [];
270  if ($row) {
271  $this->versionOL('pages', $row);
272  if (is_array($row)) {
273  $result = $this->getPageOverlay($row);
274  }
275  }
276  $this->cache_getPage_noCheck[$uid] = $result;
277  return $result;
278  }
279 
287  public function getFirstWebPage($uid)
288  {
289  $output = '';
290  $res = $this->getDatabaseConnection()->exec_SELECTquery('*', 'pages', 'pid=' . (int)$uid . $this->where_hid_del . $this->where_groupAccess, '', 'sorting', '1');
291  $row = $this->getDatabaseConnection()->sql_fetch_assoc($res);
292  $this->getDatabaseConnection()->sql_free_result($res);
293  if ($row) {
294  $this->versionOL('pages', $row);
295  if (is_array($row)) {
296  $output = $this->getPageOverlay($row);
297  }
298  }
299  return $output;
300  }
301 
309  public function getPageIdFromAlias($alias)
310  {
311  $alias = strtolower($alias);
312  if ($this->cache_getPageIdFromAlias[$alias]) {
313  return $this->cache_getPageIdFromAlias[$alias];
314  }
315  $db = $this->getDatabaseConnection();
316  $row = $db->exec_SELECTgetSingleRow('uid', 'pages', 'alias=' . $db->fullQuoteStr($alias, 'pages') . ' AND pid>=0 AND pages.deleted=0');
317  // "AND pid>=0" because of versioning (means that aliases sent MUST be online!)
318  if ($row) {
319  $this->cache_getPageIdFromAlias[$alias] = $row['uid'];
320  return $row['uid'];
321  }
322  $this->cache_getPageIdFromAlias[$alias] = 0;
323  return 0;
324  }
325 
334  public function getPageOverlay($pageInput, $lUid = -1)
335  {
336  $rows = $this->getPagesOverlay([$pageInput], $lUid);
337  // Always an array in return
338  return isset($rows[0]) ? $rows[0] : [];
339  }
340 
352  public function getPagesOverlay(array $pagesInput, $lUid = -1)
353  {
354  if (empty($pagesInput)) {
355  return [];
356  }
357  // Initialize:
358  if ($lUid < 0) {
359  $lUid = $this->sys_language_uid;
360  }
361  $row = null;
362  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPageOverlay'])) {
363  foreach ($pagesInput as &$origPage) {
364  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getPageOverlay'] as $classRef) {
365  $hookObject = GeneralUtility::getUserObj($classRef);
366  if (!$hookObject instanceof PageRepositoryGetPageOverlayHookInterface) {
367  throw new \UnexpectedValueException($classRef . ' must implement interface ' . PageRepositoryGetPageOverlayHookInterface::class, 1269878881);
368  }
369  $hookObject->getPageOverlay_preProcess($origPage, $lUid, $this);
370  }
371  }
372  unset($origPage);
373  }
374  // If language UID is different from zero, do overlay:
375  if ($lUid) {
376  $fieldArr = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['FE']['pageOverlayFields'], true);
377  $page_ids = [];
378 
379  $origPage = reset($pagesInput);
380  if (is_array($origPage)) {
381  // Make sure that only fields which exist in the first incoming record are overlaid!
382  $fieldArr = array_intersect($fieldArr, array_keys($this->purgeComputedProperties($origPage)));
383  }
384  foreach ($pagesInput as $origPage) {
385  if (is_array($origPage)) {
386  // Was the whole record
387  $page_ids[] = $origPage['uid'];
388  } else {
389  // Was the id
390  $page_ids[] = $origPage;
391  }
392  }
393  if (!empty($fieldArr)) {
394  if (!in_array('pid', $fieldArr, true)) {
395  $fieldArr[] = 'pid';
396  }
397  // NOTE to enabledFields('pages_language_overlay'):
398  // Currently the showHiddenRecords of TSFE set will allow
399  // pages_language_overlay records to be selected as they are
400  // child-records of a page.
401  // However you may argue that the showHiddenField flag should
402  // determine this. But that's not how it's done right now.
403  // Selecting overlay record:
404  $db = $this->getDatabaseConnection();
405  $res = $db->exec_SELECTquery(
406  implode(',', $fieldArr),
407  'pages_language_overlay',
408  'pid IN(' . implode(',', $db->cleanIntArray($page_ids)) . ')'
409  . ' AND sys_language_uid=' . (int)$lUid . $this->enableFields('pages_language_overlay')
410  );
411  $overlays = [];
412  while ($row = $db->sql_fetch_assoc($res)) {
413  $this->versionOL('pages_language_overlay', $row);
414  if (is_array($row)) {
415  $row['_PAGES_OVERLAY'] = true;
416  $row['_PAGES_OVERLAY_UID'] = $row['uid'];
417  $row['_PAGES_OVERLAY_LANGUAGE'] = $lUid;
418  $origUid = $row['pid'];
419  // Unset vital fields that are NOT allowed to be overlaid:
420  unset($row['uid']);
421  unset($row['pid']);
422  $overlays[$origUid] = $row;
423  }
424  }
425  $db->sql_free_result($res);
426  }
427  }
428  // Create output:
429  $pagesOutput = [];
430  foreach ($pagesInput as $key => $origPage) {
431  if (is_array($origPage)) {
432  $pagesOutput[$key] = $origPage;
433  if (isset($overlays[$origPage['uid']])) {
434  // Overwrite the original field with the overlay
435  foreach ($overlays[$origPage['uid']] as $fieldName => $fieldValue) {
436  if ($fieldName !== 'uid' && $fieldName !== 'pid') {
437  if ($this->shouldFieldBeOverlaid('pages_language_overlay', $fieldName, $fieldValue)) {
438  $pagesOutput[$key][$fieldName] = $fieldValue;
439  }
440  }
441  }
442  }
443  } else {
444  if (isset($overlays[$origPage])) {
445  $pagesOutput[$key] = $overlays[$origPage];
446  }
447  }
448  }
449  return $pagesOutput;
450  }
451 
463  public function getRecordOverlay($table, $row, $sys_language_content, $OLmode = '')
464  {
465  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'])) {
466  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'] as $classRef) {
467  $hookObject = GeneralUtility::getUserObj($classRef);
468  if (!$hookObject instanceof PageRepositoryGetRecordOverlayHookInterface) {
469  throw new \UnexpectedValueException($classRef . ' must implement interface ' . PageRepositoryGetRecordOverlayHookInterface::class, 1269881658);
470  }
471  $hookObject->getRecordOverlay_preProcess($table, $row, $sys_language_content, $OLmode, $this);
472  }
473  }
474  if ($row['uid'] > 0 && ($row['pid'] > 0 || in_array($table, $this->tableNamesAllowedOnRootLevel, true))) {
475  if ($GLOBALS['TCA'][$table] && $GLOBALS['TCA'][$table]['ctrl']['languageField'] && $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']) {
476  // Return record for ALL languages untouched
477  // TODO: Fix call stack to prevent this situation in the first place
478  if (!$GLOBALS['TCA'][$table]['ctrl']['transOrigPointerTable'] && (int)$row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] !== -1) {
479  // Will not be able to work with other tables (Just didn't implement it yet;
480  // Requires a scan over all tables [ctrl] part for first FIND the table that
481  // carries localization information for this table (which could even be more
482  // than a single table) and then use that. Could be implemented, but obviously
483  // takes a little more....) Will try to overlay a record only if the
484  // sys_language_content value is larger than zero.
485  if ($sys_language_content > 0) {
486  // Must be default language, otherwise no overlaying
487  if ((int)$row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] === 0) {
488  // Select overlay record:
489  $res = $this->getDatabaseConnection()->exec_SELECTquery('*', $table, 'pid=' . (int)$row['pid'] . ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['languageField'] . '=' . (int)$sys_language_content . ' AND ' . $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField'] . '=' . (int)$row['uid'] . $this->enableFields($table), '', '', '1');
490  $olrow = $this->getDatabaseConnection()->sql_fetch_assoc($res);
491  $this->getDatabaseConnection()->sql_free_result($res);
492  $this->versionOL($table, $olrow);
493  // Merge record content by traversing all fields:
494  if (is_array($olrow)) {
495  if (isset($olrow['_ORIG_uid'])) {
496  $row['_ORIG_uid'] = $olrow['_ORIG_uid'];
497  }
498  if (isset($olrow['_ORIG_pid'])) {
499  $row['_ORIG_pid'] = $olrow['_ORIG_pid'];
500  }
501  foreach ($row as $fN => $fV) {
502  if ($fN !== 'uid' && $fN !== 'pid' && isset($olrow[$fN])) {
503  if ($this->shouldFieldBeOverlaid($table, $fN, $olrow[$fN])) {
504  $row[$fN] = $olrow[$fN];
505  }
506  } elseif ($fN === 'uid') {
507  $row['_LOCALIZED_UID'] = $olrow['uid'];
508  }
509  }
510  } elseif ($OLmode === 'hideNonTranslated' && (int)$row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] === 0) {
511  // Unset, if non-translated records should be hidden. ONLY done if the source
512  // record really is default language and not [All] in which case it is allowed.
513  unset($row);
514  }
515  } elseif ($sys_language_content != $row[$GLOBALS['TCA'][$table]['ctrl']['languageField']]) {
516  unset($row);
517  }
518  } else {
519  // When default language is displayed, we never want to return a record carrying
520  // another language!
521  if ($row[$GLOBALS['TCA'][$table]['ctrl']['languageField']] > 0) {
522  unset($row);
523  }
524  }
525  }
526  }
527  }
528  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'])) {
529  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['getRecordOverlay'] as $classRef) {
530  $hookObject = GeneralUtility::getUserObj($classRef);
531  if (!$hookObject instanceof PageRepositoryGetRecordOverlayHookInterface) {
532  throw new \UnexpectedValueException($classRef . ' must implement interface ' . PageRepositoryGetRecordOverlayHookInterface::class, 1269881659);
533  }
534  $hookObject->getRecordOverlay_postProcess($table, $row, $sys_language_content, $OLmode, $this);
535  }
536  }
537  return $row;
538  }
539 
540  /************************************************
541  *
542  * Page related: Menu, Domain record, Root line
543  *
544  ************************************************/
545 
562  public function getMenu($pageId, $fields = '*', $sortField = 'sorting', $additionalWhereClause = '', $checkShortcuts = true)
563  {
564  return $this->getSubpagesForPages((array)$pageId, $fields, $sortField, $additionalWhereClause, $checkShortcuts);
565  }
566 
580  public function getMenuForPages(array $pageIds, $fields = '*', $sortField = 'sorting', $additionalWhereClause = '', $checkShortcuts = true)
581  {
582  return $this->getSubpagesForPages($pageIds, $fields, $sortField, $additionalWhereClause, $checkShortcuts, false);
583  }
584 
604  protected function getSubpagesForPages(array $pageIds, $fields = '*', $sortField = 'sorting', $additionalWhereClause = '', $checkShortcuts = true, $parentPages = true)
605  {
606  $pages = [];
607  $relationField = $parentPages ? 'pid' : 'uid';
608  $db = $this->getDatabaseConnection();
609 
610  $whereStatement = $relationField . ' IN ('
611  . implode(',', $db->cleanIntArray($pageIds)) . ')'
612  . $this->where_hid_del
613  . $this->where_groupAccess
614  . ' '
615  . $additionalWhereClause;
616 
617  $databaseResource = $db->exec_SELECTquery(
618  $fields,
619  'pages',
620  $whereStatement,
621  '',
622  $sortField
623  );
624 
625  while (($page = $db->sql_fetch_assoc($databaseResource))) {
626  $originalUid = $page['uid'];
627 
628  // Versioning Preview Overlay
629  $this->versionOL('pages', $page, true);
630  // Skip if page got disabled due to version overlay
631  // (might be delete or move placeholder)
632  if (empty($page)) {
633  continue;
634  }
635 
636  // Add a mount point parameter if needed
637  $page = $this->addMountPointParameterToPage((array)$page);
638 
639  // If shortcut, look up if the target exists and is currently visible
640  if ($checkShortcuts) {
641  $page = $this->checkValidShortcutOfPage((array)$page, $additionalWhereClause);
642  }
643 
644  // If the page still is there, we add it to the output
645  if (!empty($page)) {
646  $pages[$originalUid] = $page;
647  }
648  }
649 
650  $db->sql_free_result($databaseResource);
651 
652  // Finally load language overlays
653  return $this->getPagesOverlay($pages);
654  }
655 
662  protected function addMountPointParameterToPage(array $page)
663  {
664  if (empty($page)) {
665  return [];
666  }
667 
668  // $page MUST have "uid", "pid", "doktype", "mount_pid", "mount_pid_ol" fields in it
669  $mountPointInfo = $this->getMountPointInfo($page['uid'], $page);
670 
671  // There is a valid mount point.
672  if (is_array($mountPointInfo) && $mountPointInfo['overlay']) {
673 
674  // Using "getPage" is OK since we need the check for enableFields AND for type 2
675  // of mount pids we DO require a doktype < 200!
676  $mountPointPage = $this->getPage($mountPointInfo['mount_pid']);
677 
678  if (!empty($mountPointPage)) {
679  $page = $mountPointPage;
680  $page['_MP_PARAM'] = $mountPointInfo['MPvar'];
681  } else {
682  $page = [];
683  }
684  }
685  return $page;
686  }
687 
695  protected function checkValidShortcutOfPage(array $page, $additionalWhereClause)
696  {
697  if (empty($page)) {
698  return [];
699  }
700 
701  $dokType = (int)$page['doktype'];
702  $shortcutMode = (int)$page['shortcut_mode'];
703 
704  if ($dokType === self::DOKTYPE_SHORTCUT && ($page['shortcut'] || $shortcutMode)) {
705  if ($shortcutMode === self::SHORTCUT_MODE_NONE) {
706  // No shortcut_mode set, so target is directly set in $page['shortcut']
707  $searchField = 'uid';
708  $searchUid = (int)$page['shortcut'];
709  } elseif ($shortcutMode === self::SHORTCUT_MODE_FIRST_SUBPAGE || $shortcutMode === self::SHORTCUT_MODE_RANDOM_SUBPAGE) {
710  // Check subpages - first subpage or random subpage
711  $searchField = 'pid';
712  // If a shortcut mode is set and no valid page is given to select subpags
713  // from use the actual page.
714  $searchUid = (int)$page['shortcut'] ?: $page['uid'];
715  } elseif ($shortcutMode === self::SHORTCUT_MODE_PARENT_PAGE) {
716  // Shortcut to parent page
717  $searchField = 'uid';
718  $searchUid = $page['pid'];
719  } else {
720  $searchField = '';
721  $searchUid = 0;
722  }
723 
724  $whereStatement = $searchField . '=' . $searchUid
725  . $this->where_hid_del
726  . $this->where_groupAccess
727  . ' ' . $additionalWhereClause;
728 
729  $count = $this->getDatabaseConnection()->exec_SELECTcountRows(
730  'uid',
731  'pages',
732  $whereStatement
733  );
734 
735  if (!$count) {
736  $page = [];
737  }
738  } elseif ($dokType === self::DOKTYPE_SHORTCUT) {
739  // Neither shortcut target nor mode is set. Remove the page from the menu.
740  $page = [];
741  }
742  return $page;
743  }
755  public function getDomainStartPage($domain, $path = '', $request_uri = '')
756  {
757  $domain = explode(':', $domain);
758  $domain = strtolower(preg_replace('/\\.$/', '', $domain[0]));
759  // Removing extra trailing slashes
760  $path = trim(preg_replace('/\\/[^\\/]*$/', '', $path));
761  // Appending to domain string
762  $domain .= $path;
763  $domain = preg_replace('/\\/*$/', '', $domain);
764  $res = $this->getDatabaseConnection()->exec_SELECTquery('pages.uid,sys_domain.redirectTo,sys_domain.redirectHttpStatusCode,sys_domain.prepend_params', 'pages,sys_domain', 'pages.uid=sys_domain.pid
765  AND sys_domain.hidden=0
766  AND (sys_domain.domainName=' . $this->getDatabaseConnection()->fullQuoteStr($domain, 'sys_domain') . ' OR sys_domain.domainName=' . $this->getDatabaseConnection()->fullQuoteStr(($domain . '/'), 'sys_domain') . ') ' . $this->where_hid_del . $this->where_groupAccess, '', '', 1);
767  $row = $this->getDatabaseConnection()->sql_fetch_assoc($res);
768  $this->getDatabaseConnection()->sql_free_result($res);
769  if ($row) {
770  if ($row['redirectTo']) {
771  $redirectUrl = $row['redirectTo'];
772  if ($row['prepend_params']) {
773  $redirectUrl = rtrim($redirectUrl, '/');
774  $prependStr = ltrim(substr($request_uri, strlen($path)), '/');
775  $redirectUrl .= '/' . $prependStr;
776  }
777  $statusCode = (int)$row['redirectHttpStatusCode'];
778  if ($statusCode && defined(HttpUtility::class . '::HTTP_STATUS_' . $statusCode)) {
779  HttpUtility::redirect($redirectUrl, constant(HttpUtility::class . '::HTTP_STATUS_' . $statusCode));
780  } else {
782  }
783  die;
784  } else {
785  return $row['uid'];
786  }
787  }
788  return '';
789  }
790 
811  public function getRootLine($uid, $MP = '', $ignoreMPerrors = false)
812  {
813  $rootline = GeneralUtility::makeInstance(RootlineUtility::class, $uid, $MP, $this);
814  try {
815  return $rootline->get();
816  } catch (\RuntimeException $ex) {
817  if ($ignoreMPerrors) {
818  $this->error_getRootLine = $ex->getMessage();
819  if (substr($this->error_getRootLine, -7) === 'uid -1.') {
820  $this->error_getRootLine_failPid = -1;
821  }
822  return [];
824  } elseif ($ex->getCode() === 1343589451) {
825  return [];
826  }
827  throw $ex;
828  }
829  }
830 
840  public function getPathFromRootline($rl, $len = 20)
841  {
842  $path = '';
843  if (is_array($rl)) {
844  $c = count($rl);
845  for ($a = 0; $a < $c; $a++) {
846  if ($rl[$a]['uid']) {
847  $path .= '/' . GeneralUtility::fixed_lgd_cs(strip_tags($rl[$a]['title']), $len);
848  }
849  }
850  }
851  return $path;
852  }
853 
863  public function getExtURL($pagerow, $disable = false)
864  {
865  if ($disable !== false) {
866  GeneralUtility::deprecationLog('The disable option of PageRepository::getExtUrl() is deprecated since TYPO3 CMS 7, will be removed with TYPO3 CMS 8.');
867  return false;
868  }
869  if ((int)$pagerow['doktype'] === self::DOKTYPE_LINK) {
870  $redirectTo = $this->urltypes[$pagerow['urltype']] . $pagerow['url'];
871  // If relative path, prefix Site URL:
872  $uI = parse_url($redirectTo);
873  // Relative path assumed now.
874  if (!$uI['scheme'] && $redirectTo[0] !== '/') {
875  $redirectTo = GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . $redirectTo;
876  }
877  return $redirectTo;
878  }
879  return false;
880  }
881 
895  public function getMountPointInfo($pageId, $pageRec = false, $prevMountPids = [], $firstPageUid = 0)
896  {
897  $result = false;
898  if ($GLOBALS['TYPO3_CONF_VARS']['FE']['enable_mount_pids']) {
899  if (isset($this->cache_getMountPointInfo[$pageId])) {
900  return $this->cache_getMountPointInfo[$pageId];
901  }
902  // Get pageRec if not supplied:
903  if (!is_array($pageRec)) {
904  $res = $this->getDatabaseConnection()->exec_SELECTquery('uid,pid,doktype,mount_pid,mount_pid_ol,t3ver_state', 'pages', 'uid=' . (int)$pageId . ' AND pages.deleted=0 AND pages.doktype<>255');
905  $pageRec = $this->getDatabaseConnection()->sql_fetch_assoc($res);
906  $this->getDatabaseConnection()->sql_free_result($res);
907  // Only look for version overlay if page record is not supplied; This assumes
908  // that the input record is overlaid with preview version, if any!
909  $this->versionOL('pages', $pageRec);
910  }
911  // Set first Page uid:
912  if (!$firstPageUid) {
913  $firstPageUid = $pageRec['uid'];
914  }
915  // Look for mount pid value plus other required circumstances:
916  $mount_pid = (int)$pageRec['mount_pid'];
917  if (is_array($pageRec) && (int)$pageRec['doktype'] === self::DOKTYPE_MOUNTPOINT && $mount_pid > 0 && !in_array($mount_pid, $prevMountPids, true)) {
918  // Get the mount point record (to verify its general existence):
919  $res = $this->getDatabaseConnection()->exec_SELECTquery('uid,pid,doktype,mount_pid,mount_pid_ol,t3ver_state', 'pages', 'uid=' . $mount_pid . ' AND pages.deleted=0 AND pages.doktype<>255');
920  $mountRec = $this->getDatabaseConnection()->sql_fetch_assoc($res);
921  $this->getDatabaseConnection()->sql_free_result($res);
922  $this->versionOL('pages', $mountRec);
923  if (is_array($mountRec)) {
924  // Look for recursive mount point:
925  $prevMountPids[] = $mount_pid;
926  $recursiveMountPid = $this->getMountPointInfo($mount_pid, $mountRec, $prevMountPids, $firstPageUid);
927  // Return mount point information:
928  $result = $recursiveMountPid ?: [
929  'mount_pid' => $mount_pid,
930  'overlay' => $pageRec['mount_pid_ol'],
931  'MPvar' => $mount_pid . '-' . $firstPageUid,
932  'mount_point_rec' => $pageRec,
933  'mount_pid_rec' => $mountRec
934  ];
935  } else {
936  // Means, there SHOULD have been a mount point, but there was none!
937  $result = -1;
938  }
939  }
940  }
941  $this->cache_getMountPointInfo[$pageId] = $result;
942  return $result;
943  }
944 
945  /********************************
946  *
947  * Selecting records in general
948  *
949  ********************************/
950 
960  public function checkRecord($table, $uid, $checkPage = 0)
961  {
962  $uid = (int)$uid;
963  if (is_array($GLOBALS['TCA'][$table]) && $uid > 0) {
964  $res = $this->getDatabaseConnection()->exec_SELECTquery('*', $table, 'uid = ' . $uid . $this->enableFields($table));
965  $row = $this->getDatabaseConnection()->sql_fetch_assoc($res);
966  $this->getDatabaseConnection()->sql_free_result($res);
967  if ($row) {
968  $this->versionOL($table, $row);
969  if (is_array($row)) {
970  if ($checkPage) {
971  $res = $this->getDatabaseConnection()->exec_SELECTquery('uid', 'pages', 'uid=' . (int)$row['pid'] . $this->enableFields('pages'));
972  $numRows = $this->getDatabaseConnection()->sql_num_rows($res);
973  $this->getDatabaseConnection()->sql_free_result($res);
974  if ($numRows > 0) {
975  return $row;
976  } else {
977  return 0;
978  }
979  } else {
980  return $row;
981  }
982  }
983  }
984  }
985  return 0;
986  }
987 
998  public function getRawRecord($table, $uid, $fields = '*', $noWSOL = false)
999  {
1000  $uid = (int)$uid;
1001  if (isset($GLOBALS['TCA'][$table]) && is_array($GLOBALS['TCA'][$table]) && $uid > 0) {
1002  $res = $this->getDatabaseConnection()->exec_SELECTquery($fields, $table, 'uid = ' . $uid . $this->deleteClause($table));
1003  $row = $this->getDatabaseConnection()->sql_fetch_assoc($res);
1004  $this->getDatabaseConnection()->sql_free_result($res);
1005  if ($row) {
1006  if (!$noWSOL) {
1007  $this->versionOL($table, $row);
1008  }
1009  if (is_array($row)) {
1010  return $row;
1011  }
1012  }
1013  }
1014  return 0;
1015  }
1016 
1029  public function getRecordsByField($theTable, $theField, $theValue, $whereClause = '', $groupBy = '', $orderBy = '', $limit = '')
1030  {
1031  if (is_array($GLOBALS['TCA'][$theTable])) {
1032  $res = $this->getDatabaseConnection()->exec_SELECTquery('*', $theTable, $theField . '=' . $this->getDatabaseConnection()->fullQuoteStr($theValue, $theTable) . $this->deleteClause($theTable) . ' ' . $whereClause, $groupBy, $orderBy, $limit);
1033  $rows = [];
1034  while ($row = $this->getDatabaseConnection()->sql_fetch_assoc($res)) {
1035  if (is_array($row)) {
1036  $rows[] = $row;
1037  }
1038  }
1039  $this->getDatabaseConnection()->sql_free_result($res);
1040  if (!empty($rows)) {
1041  return $rows;
1042  }
1043  }
1044  return null;
1045  }
1046 
1047  /********************************
1048  *
1049  * Caching and standard clauses
1050  *
1051  ********************************/
1052 
1064  public static function getHash($hash)
1065  {
1066  $hashContent = null;
1068  $contentHashCache = GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_hash');
1069  $cacheEntry = $contentHashCache->get($hash);
1070  if ($cacheEntry) {
1071  $hashContent = $cacheEntry;
1072  }
1073  return $hashContent;
1074  }
1075 
1090  public static function storeHash($hash, $data, $ident, $lifetime = 0)
1091  {
1092  GeneralUtility::makeInstance(CacheManager::class)->getCache('cache_hash')->set($hash, $data, ['ident_' . $ident], (int)$lifetime);
1093  }
1094 
1103  public function deleteClause($table)
1104  {
1105  return $GLOBALS['TCA'][$table]['ctrl']['delete'] ? ' AND ' . $table . '.' . $GLOBALS['TCA'][$table]['ctrl']['delete'] . '=0' : '';
1106  }
1107 
1125  public function enableFields($table, $show_hidden = -1, $ignore_array = [], $noVersionPreview = false)
1126  {
1127  if ($show_hidden === -1 && is_object($this->getTypoScriptFrontendController())) {
1128  // If show_hidden was not set from outside and if TSFE is an object, set it
1129  // based on showHiddenPage and showHiddenRecords from TSFE
1130  $show_hidden = $table === 'pages' || $table === 'pages_language_overlay'
1131  ? $this->getTypoScriptFrontendController()->showHiddenPage
1132  : $this->getTypoScriptFrontendController()->showHiddenRecords;
1133  }
1134  if ($show_hidden === -1) {
1135  $show_hidden = 0;
1136  }
1137  // If show_hidden was not changed during the previous evaluation, do it here.
1138  $ctrl = $GLOBALS['TCA'][$table]['ctrl'];
1139  $query = '';
1140  if (is_array($ctrl)) {
1141  // Delete field check:
1142  if ($ctrl['delete']) {
1143  $query .= ' AND ' . $table . '.' . $ctrl['delete'] . '=0';
1144  }
1145  if ($ctrl['versioningWS']) {
1146  if (!$this->versioningPreview) {
1147  // Filter out placeholder records (new/moved/deleted items)
1148  // in case we are NOT in a versioning preview (that means we are online!)
1149  $query .= ' AND ' . $table . '.t3ver_state<=' . new VersionState(VersionState::DEFAULT_STATE);
1150  } elseif ($table !== 'pages') {
1151  // show only records of live and of the current workspace
1152  // in case we are in a versioning preview
1153  $query .= ' AND (' .
1154  $table . '.t3ver_wsid=0 OR ' .
1155  $table . '.t3ver_wsid=' . (int)$this->versioningWorkspaceId .
1156  ')';
1157  }
1158 
1159  // Filter out versioned records
1160  if (!$noVersionPreview && empty($ignore_array['pid'])) {
1161  $query .= ' AND ' . $table . '.pid<>-1';
1162  }
1163  }
1164 
1165  // Enable fields:
1166  if (is_array($ctrl['enablecolumns'])) {
1167  // In case of versioning-preview, enableFields are ignored (checked in
1168  // versionOL())
1169  if (!$this->versioningPreview || !$ctrl['versioningWS'] || $noVersionPreview) {
1170  if ($ctrl['enablecolumns']['disabled'] && !$show_hidden && !$ignore_array['disabled']) {
1171  $field = $table . '.' . $ctrl['enablecolumns']['disabled'];
1172  $query .= ' AND ' . $field . '=0';
1173  }
1174  if ($ctrl['enablecolumns']['starttime'] && !$ignore_array['starttime']) {
1175  $field = $table . '.' . $ctrl['enablecolumns']['starttime'];
1176  $query .= ' AND ' . $field . '<=' . $GLOBALS['SIM_ACCESS_TIME'];
1177  }
1178  if ($ctrl['enablecolumns']['endtime'] && !$ignore_array['endtime']) {
1179  $field = $table . '.' . $ctrl['enablecolumns']['endtime'];
1180  $query .= ' AND (' . $field . '=0 OR ' . $field . '>' . $GLOBALS['SIM_ACCESS_TIME'] . ')';
1181  }
1182  if ($ctrl['enablecolumns']['fe_group'] && !$ignore_array['fe_group']) {
1183  $field = $table . '.' . $ctrl['enablecolumns']['fe_group'];
1184  $query .= $this->getMultipleGroupsWhereClause($field, $table);
1185  }
1186  // Call hook functions for additional enableColumns
1187  // It is used by the extension ingmar_accessctrl which enables assigning more
1188  // than one usergroup to content and page records
1189  if (is_array($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['addEnableColumns'])) {
1190  $_params = [
1191  'table' => $table,
1192  'show_hidden' => $show_hidden,
1193  'ignore_array' => $ignore_array,
1194  'ctrl' => $ctrl
1195  ];
1196  foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_page.php']['addEnableColumns'] as $_funcRef) {
1197  $query .= GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1198  }
1199  }
1200  }
1201  }
1202  } else {
1203  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);
1204  }
1205  return $query;
1206  }
1207 
1217  public function getMultipleGroupsWhereClause($field, $table)
1218  {
1219  $memberGroups = GeneralUtility::intExplode(',', $this->getTypoScriptFrontendController()->gr_list);
1220  $orChecks = [];
1221  // If the field is empty, then OK
1222  $orChecks[] = $field . '=\'\'';
1223  // If the field is NULL, then OK
1224  $orChecks[] = $field . ' IS NULL';
1225  // If the field contsains zero, then OK
1226  $orChecks[] = $field . '=\'0\'';
1227  foreach ($memberGroups as $value) {
1228  $orChecks[] = $this->getDatabaseConnection()->listQuery($field, $value, $table);
1229  }
1230  return ' AND (' . implode(' OR ', $orChecks) . ')';
1231  }
1232 
1233  /**********************
1234  *
1235  * Versioning Preview
1236  *
1237  **********************/
1238 
1258  public function fixVersioningPid($table, &$rr)
1259  {
1260  if ($this->versioningPreview && is_array($rr) && (int)$rr['pid'] === -1 && $GLOBALS['TCA'][$table]['ctrl']['versioningWS']) {
1261  $oid = 0;
1262  $wsid = 0;
1263  // Have to hardcode it for "pages" table since TCA is not loaded at this moment!
1264  // Check values for t3ver_oid and t3ver_wsid:
1265  if (isset($rr['t3ver_oid']) && isset($rr['t3ver_wsid'])) {
1266  // If "t3ver_oid" is already a field, just set this:
1267  $oid = $rr['t3ver_oid'];
1268  $wsid = $rr['t3ver_wsid'];
1269  } else {
1270  // Otherwise we have to expect "uid" to be in the record and look up based
1271  // on this:
1272  $newPidRec = $this->getRawRecord($table, $rr['uid'], 't3ver_oid,t3ver_wsid', true);
1273  if (is_array($newPidRec)) {
1274  $oid = $newPidRec['t3ver_oid'];
1275  $wsid = $newPidRec['t3ver_wsid'];
1276  }
1277  }
1278  // If workspace ids matches and ID of current online version is found, look up
1279  // the PID value of that:
1280  if ($oid && ((int)$this->versioningWorkspaceId === 0 && $this->checkWorkspaceAccess($wsid) || (int)$wsid === (int)$this->versioningWorkspaceId)) {
1281  $oidRec = $this->getRawRecord($table, $oid, 'pid', true);
1282  if (is_array($oidRec)) {
1283  // SWAP uid as well? Well no, because when fixing a versioning PID happens it is
1284  // assumed that this is a "branch" type page and therefore the uid should be
1285  // kept (like in versionOL()). However if the page is NOT a branch version it
1286  // should not happen - but then again, direct access to that uid should not
1287  // happen!
1288  $rr['_ORIG_pid'] = $rr['pid'];
1289  $rr['pid'] = $oidRec['pid'];
1290  }
1291  }
1292  }
1293  // Changing PID in case of moving pointer:
1294  if ($movePlhRec = $this->getMovePlaceholder($table, $rr['uid'], 'pid')) {
1295  $rr['pid'] = $movePlhRec['pid'];
1296  }
1297  }
1298 
1319  public function versionOL($table, &$row, $unsetMovePointers = false, $bypassEnableFieldsCheck = false)
1320  {
1321  if ($this->versioningPreview && is_array($row)) {
1322  // will overlay any movePlhOL found with the real record, which in turn
1323  // will be overlaid with its workspace version if any.
1324  $movePldSwap = $this->movePlhOL($table, $row);
1325  // implode(',',array_keys($row)) = Using fields from original record to make
1326  // sure no additional fields are selected. This is best for eg. getPageOverlay()
1327  // Computed properties are excluded since those would lead to SQL errors.
1328  $fieldNames = implode(',', array_keys($this->purgeComputedProperties($row)));
1329  if ($wsAlt = $this->getWorkspaceVersionOfRecord($this->versioningWorkspaceId, $table, $row['uid'], $fieldNames, $bypassEnableFieldsCheck)) {
1330  if (is_array($wsAlt)) {
1331  // Always fix PID (like in fixVersioningPid() above). [This is usually not
1332  // the important factor for versioning OL]
1333  // Keep the old (-1) - indicates it was a version...
1334  $wsAlt['_ORIG_pid'] = $wsAlt['pid'];
1335  // Set in the online versions PID.
1336  $wsAlt['pid'] = $row['pid'];
1337  // For versions of single elements or page+content, preserve online UID and PID
1338  // (this will produce true "overlay" of element _content_, not any references)
1339  // For page+content the "_ORIG_uid" should actually be used as PID for selection
1340  // of tables with "versioning_followPages" enabled.
1341  $wsAlt['_ORIG_uid'] = $wsAlt['uid'];
1342  $wsAlt['uid'] = $row['uid'];
1343  // Translate page alias as well so links are pointing to the _online_ page:
1344  if ($table === 'pages') {
1345  $wsAlt['alias'] = $row['alias'];
1346  }
1347  // Changing input record to the workspace version alternative:
1348  $row = $wsAlt;
1349  // Check if it is deleted/new
1350  $rowVersionState = VersionState::cast($row['t3ver_state']);
1351  if (
1352  $rowVersionState->equals(VersionState::NEW_PLACEHOLDER)
1353  || $rowVersionState->equals(VersionState::DELETE_PLACEHOLDER)
1354  ) {
1355  // Unset record if it turned out to be deleted in workspace
1356  $row = false;
1357  }
1358  // Check if move-pointer in workspace (unless if a move-placeholder is the
1359  // reason why it appears!):
1360  // You have to specifically set $unsetMovePointers in order to clear these
1361  // because it is normally a display issue if it should be shown or not.
1362  if (
1363  ($rowVersionState->equals(VersionState::MOVE_POINTER)
1364  && !$movePldSwap
1365  ) && $unsetMovePointers
1366  ) {
1367  // Unset record if it turned out to be deleted in workspace
1368  $row = false;
1369  }
1370  } else {
1371  // No version found, then check if t3ver_state = VersionState::NEW_PLACEHOLDER
1372  // (online version is dummy-representation)
1373  // Notice, that unless $bypassEnableFieldsCheck is TRUE, the $row is unset if
1374  // enablefields for BOTH the version AND the online record deselects it. See
1375  // note for $bypassEnableFieldsCheck
1377  $versionState = VersionState::cast($row['t3ver_state']);
1378  if ($wsAlt <= -1 || $versionState->indicatesPlaceholder()) {
1379  // Unset record if it turned out to be "hidden"
1380  $row = false;
1381  }
1382  }
1383  }
1384  }
1385  }
1386 
1397  public function movePlhOL($table, &$row)
1398  {
1399  if (!empty($GLOBALS['TCA'][$table]['ctrl']['versioningWS'])
1400  && (int)VersionState::cast($row['t3ver_state'])->equals(VersionState::MOVE_PLACEHOLDER)
1401  ) {
1402  // Only for WS ver 2... (moving) - enabled by default with CMS7
1403  // If t3ver_move_id is not found, then find it (but we like best if it is here)
1404  if (!isset($row['t3ver_move_id'])) {
1405  $moveIDRec = $this->getRawRecord($table, $row['uid'], 't3ver_move_id', true);
1406  $moveID = $moveIDRec['t3ver_move_id'];
1407  } else {
1408  $moveID = $row['t3ver_move_id'];
1409  }
1410  // Find pointed-to record.
1411  if ($moveID) {
1412  $res = $this->getDatabaseConnection()->exec_SELECTquery(implode(',', array_keys($this->purgeComputedProperties($row))), $table, 'uid=' . (int)$moveID . $this->enableFields($table));
1413  $origRow = $this->getDatabaseConnection()->sql_fetch_assoc($res);
1414  $this->getDatabaseConnection()->sql_free_result($res);
1415  if ($origRow) {
1416  $row = $origRow;
1417  return true;
1418  }
1419  }
1420  }
1421  return false;
1422  }
1423 
1433  public function getMovePlaceholder($table, $uid, $fields = '*')
1434  {
1435  if ($this->versioningPreview) {
1436  $workspace = (int)$this->versioningWorkspaceId;
1437  if (!empty($GLOBALS['TCA'][$table]['ctrl']['versioningWS']) && $workspace !== 0) {
1438  // Select workspace version of record:
1439  $row = $this->getDatabaseConnection()->exec_SELECTgetSingleRow($fields, $table, 'pid<>-1 AND
1440  t3ver_state=' . new VersionState(VersionState::MOVE_PLACEHOLDER) . ' AND
1441  t3ver_move_id=' . (int)$uid . ' AND
1442  t3ver_wsid=' . (int)$workspace . $this->deleteClause($table));
1443  if (is_array($row)) {
1444  return $row;
1445  }
1446  }
1447  }
1448  return false;
1449  }
1450 
1462  public function getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields = '*', $bypassEnableFieldsCheck = false)
1463  {
1464  if ($workspace !== 0 && !empty($GLOBALS['TCA'][$table]['ctrl']['versioningWS'])) {
1465  $workspace = (int)$workspace;
1466  $uid = (int)$uid;
1467  // Setting up enableFields for version record
1468  $enFields = $this->enableFields($table, -1, [], true);
1469  // Select workspace version of record, only testing for deleted.
1470  $newrow = $this->getDatabaseConnection()->exec_SELECTgetSingleRow($fields, $table, 'pid=-1 AND
1471  t3ver_oid=' . $uid . ' AND
1472  t3ver_wsid=' . $workspace . $this->deleteClause($table));
1473  // If version found, check if it could have been selected with enableFields on
1474  // as well:
1475  if (is_array($newrow)) {
1476  if ($bypassEnableFieldsCheck || $this->getDatabaseConnection()->exec_SELECTgetSingleRow('uid', $table, 'pid=-1 AND
1477  t3ver_oid=' . $uid . ' AND
1478  t3ver_wsid=' . $workspace . $enFields)) {
1479  // Return offline version, tested for its enableFields.
1480  return $newrow;
1481  } else {
1482  // Return -1 because offline version was de-selected due to its enableFields.
1483  return -1;
1484  }
1485  } else {
1486  // OK, so no workspace version was found. Then check if online version can be
1487  // selected with full enable fields and if so, return 1:
1488  if ($bypassEnableFieldsCheck || $this->getDatabaseConnection()->exec_SELECTgetSingleRow('uid', $table, 'uid=' . $uid . $enFields)) {
1489  // Means search was done, but no version found.
1490  return 1;
1491  } else {
1492  // Return -2 because the online record was de-selected due to its enableFields.
1493  return -2;
1494  }
1495  }
1496  }
1497  // No look up in database because versioning not enabled / or workspace not
1498  // offline
1499  return false;
1500  }
1501 
1508  public function checkWorkspaceAccess($wsid)
1509  {
1510  if (!$this->getBackendUser() || !ExtensionManagementUtility::isLoaded('workspaces')) {
1511  return false;
1512  }
1513  if (isset($this->workspaceCache[$wsid])) {
1514  $ws = $this->workspaceCache[$wsid];
1515  } else {
1516  if ($wsid > 0) {
1517  // No $GLOBALS['TCA'] yet!
1518  $ws = $this->getDatabaseConnection()->exec_SELECTgetSingleRow('*', 'sys_workspace', 'uid=' . (int)$wsid . ' AND deleted=0');
1519  if (!is_array($ws)) {
1520  return false;
1521  }
1522  } else {
1523  $ws = $wsid;
1524  }
1525  $ws = $this->getBackendUser()->checkWorkspace($ws);
1526  $this->workspaceCache[$wsid] = $ws;
1527  }
1528  return (string)$ws['_ACCESS'] !== '';
1529  }
1530 
1539  public function getFileReferences($tableName, $fieldName, array $element)
1540  {
1542  $fileRepository = GeneralUtility::makeInstance(FileRepository::class);
1543  $currentId = !empty($element['uid']) ? $element['uid'] : 0;
1544 
1545  // Fetch the references of the default element
1546  try {
1547  $references = $fileRepository->findByRelation($tableName, $fieldName, $currentId);
1548  } catch (FileDoesNotExistException $e) {
1553  return [];
1554  } catch (\InvalidArgumentException $e) {
1559  $logMessage = $e->getMessage() . ' (table: "' . $tableName . '", fieldName: "' . $fieldName . '", currentId: ' . $currentId . ')';
1560  GeneralUtility::sysLog($logMessage, 'core', GeneralUtility::SYSLOG_SEVERITY_ERROR);
1561  return [];
1562  }
1563 
1564  $localizedId = null;
1565  if (isset($element['_LOCALIZED_UID'])) {
1566  $localizedId = $element['_LOCALIZED_UID'];
1567  } elseif (isset($element['_PAGES_OVERLAY_UID'])) {
1568  $localizedId = $element['_PAGES_OVERLAY_UID'];
1569  }
1570 
1571  if (!empty($GLOBALS['TCA'][$tableName]['ctrl']['transForeignTable'])) {
1572  $tableName = $GLOBALS['TCA'][$tableName]['ctrl']['transForeignTable'];
1573  }
1574 
1575  $isTableLocalizable = (
1576  !empty($GLOBALS['TCA'][$tableName]['ctrl']['languageField'])
1577  && !empty($GLOBALS['TCA'][$tableName]['ctrl']['transOrigPointerField'])
1578  );
1579  if ($isTableLocalizable && $localizedId !== null) {
1580  $localizedReferences = $fileRepository->findByRelation($tableName, $fieldName, $localizedId);
1581  $localizedReferencesValue = $localizedReferences ?: '';
1582  if ($this->shouldFieldBeOverlaid($tableName, $fieldName, $localizedReferencesValue)) {
1583  $references = $localizedReferences;
1584  }
1585  }
1586 
1587  return $references;
1588  }
1589 
1597  protected function purgeComputedProperties(array $row)
1598  {
1599  foreach ($this->computedPropertyNames as $computedPropertyName) {
1600  if (array_key_exists($computedPropertyName, $row)) {
1601  unset($row[$computedPropertyName]);
1602  }
1603  }
1604  return $row;
1605  }
1606 
1615  protected function shouldFieldBeOverlaid($table, $field, $value)
1616  {
1617  $l10n_mode = isset($GLOBALS['TCA'][$table]['columns'][$field]['l10n_mode'])
1618  ? $GLOBALS['TCA'][$table]['columns'][$field]['l10n_mode']
1619  : '';
1620 
1621  $shouldFieldBeOverlaid = true;
1622 
1623  if ($l10n_mode === 'exclude') {
1624  $shouldFieldBeOverlaid = false;
1625  } elseif ($l10n_mode === 'mergeIfNotBlank') {
1626  $checkValue = $value;
1627 
1628  // 0 values are considered blank when coming from a group field
1629  if (empty($value) && $GLOBALS['TCA'][$table]['columns'][$field]['config']['type'] === 'group') {
1630  $checkValue = '';
1631  }
1632 
1633  if ($checkValue === [] || !is_array($checkValue) && trim($checkValue) === '') {
1634  $shouldFieldBeOverlaid = false;
1635  }
1636  }
1637 
1638  return $shouldFieldBeOverlaid;
1639  }
1640 
1646  protected function getDatabaseConnection()
1647  {
1648  return $GLOBALS['TYPO3_DB'];
1649  }
1650 
1654  protected function getTypoScriptFrontendController()
1655  {
1656  return $GLOBALS['TSFE'];
1657  }
1658 
1664  protected function getBackendUser()
1665  {
1666  return $GLOBALS['BE_USER'];
1667  }
1668 }
getRecordOverlay($table, $row, $sys_language_content, $OLmode='')
static intExplode($delimiter, $string, $removeEmptyValues=false, $limit=0)
getRecordsByField($theTable, $theField, $theValue, $whereClause='', $groupBy='', $orderBy='', $limit='')
getRawRecord($table, $uid, $fields=' *', $noWSOL=false)
getRootLine($uid, $MP='', $ignoreMPerrors=false)
getMenu($pageId, $fields=' *', $sortField='sorting', $additionalWhereClause='', $checkShortcuts=true)
getWorkspaceVersionOfRecord($workspace, $table, $uid, $fields=' *', $bypassEnableFieldsCheck=false)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
getDomainStartPage($domain, $path='', $request_uri='')
static callUserFunction($funcName, &$params, &$ref, $checkPrefix='', $errorMode=0)
getExtURL($pagerow, $disable=false)
getSubpagesForPages(array $pageIds, $fields=' *', $sortField='sorting', $additionalWhereClause='', $checkShortcuts=true, $parentPages=true)
static storeHash($hash, $data, $ident, $lifetime=0)
shouldFieldBeOverlaid($table, $field, $value)
getMovePlaceholder($table, $uid, $fields=' *')
getPagesOverlay(array $pagesInput, $lUid=-1)
checkRecord($table, $uid, $checkPage=0)
getMenuForPages(array $pageIds, $fields=' *', $sortField='sorting', $additionalWhereClause='', $checkShortcuts=true)
static redirect($url, $httpStatus=self::HTTP_STATUS_303)
Definition: HttpUtility.php:76
static fixed_lgd_cs($string, $chars, $appendString='...')
$uid
Definition: server.php:38
checkValidShortcutOfPage(array $page, $additionalWhereClause)
getPage($uid, $disableGroupAccessCheck=false)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
enableFields($table, $show_hidden=-1, $ignore_array=[], $noVersionPreview=false)
getMountPointInfo($pageId, $pageRec=false, $prevMountPids=[], $firstPageUid=0)