> made for typo3 v9.5 * * @param int $pageId * @return array|int[] */ private function getAllSubpagesUidFor(int $pageId) { $subpages = [$pageId]; $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('pages'); $queryBuilder ->getRestrictions() ->removeAll() ->add(GeneralUtility::makeInstance(DeletedRestriction::class)); $queryBuilder ->select('uid') ->from('pages') ->where( $queryBuilder->expr()->eq('pid', (int)$pageId) ); $statement = $queryBuilder->execute(); while ($row = $statement->fetch()) { $subpages = array_merge($subpages, $this->getAllSubpagesUidFor($row['uid'])); } return $subpages; } /** * -- Override the original method from the typo3 PageRouter -- * Check for records in the database which matches one of the slug candidates. * * @param array $slugCandidates * @param int $languageId * @param array $excludeUids when called recursively this is the mountpoint parameter of the original prefix * @return array */ protected function getPagesFromDatabaseForCandidates(array $slugCandidates, int $languageId, array $excludeUids = []): array { $context = GeneralUtility::makeInstance(Context::class); $searchLiveRecordsOnly = $context->getPropertyFromAspect('workspace', 'isLive'); $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class) ->getQueryBuilderForTable('pages'); $queryBuilder ->getRestrictions() ->removeAll() ->add(GeneralUtility::makeInstance(DeletedRestriction::class)) ->add(GeneralUtility::makeInstance(FrontendWorkspaceRestriction::class, null, null, $searchLiveRecordsOnly)); $statement = $queryBuilder ->select('uid', 'l10n_parent', 'pid', 'slug', 'mount_pid', 'mount_pid_ol', 't3ver_state', 'doktype', 't3ver_wsid', 't3ver_oid') ->from('pages') ->where( $queryBuilder->expr()->eq( 'sys_language_uid', $queryBuilder->createNamedParameter($languageId, \PDO::PARAM_INT) ), $queryBuilder->expr()->in( 'slug', $queryBuilder->createNamedParameter( $slugCandidates, Connection::PARAM_STR_ARRAY ) ) ) // Exact match will be first, that's important ->orderBy('slug', 'desc') // Sort pages that are not MountPoint pages before mount points ->addOrderBy('mount_pid_ol', 'asc') ->addOrderBy('mount_pid', 'asc') ->execute(); $isRecursiveCall = !empty($excludeUids); $pages = []; $siteMatcher = GeneralUtility::makeInstance(SiteMatcher::class); $pageRepository = GeneralUtility::makeInstance(PageRepository::class, $context); // <---- // special: patch 2020-09-22 by Opentalent, for performances reason // >> made for typo3 v10.4.8 $siteRootPageUid = $this->site->getRootPageId(); $sitePages = $this->getAllSubpagesUidFor($siteRootPageUid); // ----> while ($row = $statement->fetch()) { $mountPageInformation = null; $pageRepository->fixVersioningPid('pages', $row); $pageIdInDefaultLanguage = (int)($languageId > 0 ? $row['l10n_parent'] : $row['uid']); // When this page was added before via recursion, this page should be skipped if (in_array($pageIdInDefaultLanguage, $excludeUids, true)) { continue; } // <---- // special: patch 2020-09-22 by Opentalent, for performances reason // >> made for typo3 v10.4.8 if (!in_array($pageIdInDefaultLanguage, $sitePages)) { continue; } // ----> try { $isOnSameSite = $siteMatcher->matchByPageId($pageIdInDefaultLanguage)->getRootPageId() === $this->site->getRootPageId(); } catch (SiteNotFoundException $e) { // Page is not in a site, so it's not considered $isOnSameSite = false; } // If a MountPoint is found on the current site, and it hasn't been added yet by some other iteration // (see below "findPageCandidatesOfMountPoint"), then let's resolve the MountPoint information now if (!$isOnSameSite && $isRecursiveCall) { // Not in the same site, and called recursive, should be skipped continue; } $mountPageInformation = $pageRepository->getMountPointInfo($pageIdInDefaultLanguage, $row); // Mount Point Pages which are not on the same site (when not called on the first level) should be skipped // As they just clutter up the queries. if (!$isOnSameSite && !$isRecursiveCall && $mountPageInformation) { continue; } $mountedPage = null; if ($mountPageInformation) { // Add the MPvar to the row, so it can be used later-on in the PageRouter / PageArguments $row['MPvar'] = $mountPageInformation['MPvar']; $mountedPage = $pageRepository->getPage_noCheck($mountPageInformation['mount_pid_rec']['uid']); // Ensure to fetch the slug in the translated page $mountedPage = $pageRepository->getPageOverlay($mountedPage, $languageId); // Mount wasn't connected properly, so it is skipped if (!$mountedPage) { continue; } // If the page is a MountPoint which should be overlaid with the contents of the mounted page, // it must never be accessible directly, but only in the MountPoint context. Therefore we change // the current ID and slug. // This needs to happen before the regular case, as the $pageToAdd contains the MPvar information if (PageRepository::DOKTYPE_MOUNTPOINT === (int)$row['doktype'] && $row['mount_pid_ol']) { // If the mounted page was already added from above, this should not be added again (to include // the mount point parameter). if (in_array((int)$mountedPage['uid'], $excludeUids, true)) { continue; } $pageToAdd = $mountedPage; // Make sure target page "/about-us" is replaced by "/global-site/about-us" so router works $pageToAdd['MPvar'] = $mountPageInformation['MPvar']; $pageToAdd['slug'] = $row['slug']; $pages[] = $pageToAdd; $excludeUids[] = (int)$pageToAdd['uid']; $excludeUids[] = $pageIdInDefaultLanguage; } } // This is the regular "non-MountPoint page" case (must happen after the if condition so MountPoint // pages that have been replaced by the Mounted Page will not be added again. if ($isOnSameSite && !in_array($pageIdInDefaultLanguage, $excludeUids, true)) { $pages[] = $row; $excludeUids[] = $pageIdInDefaultLanguage; } // Add possible sub-pages prepended with the MountPoint page slug if ($mountPageInformation) { $siteOfMountedPage = $siteMatcher->matchByPageId((int)$mountedPage['uid']); if ($siteOfMountedPage instanceof Site) { $morePageCandidates = $this->findPageCandidatesOfMountPoint( $row, $mountedPage, $siteOfMountedPage, $languageId, $slugCandidates, $context ); foreach ($morePageCandidates as $candidate) { // When called previously this MountPoint page should be skipped if (in_array((int)$candidate['uid'], $excludeUids, true)) { continue; } $pages[] = $candidate; } } } } return $pages; } }