vendor/contao/core-bundle/src/Routing/AbstractPageRouteProvider.php line 46

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4.  * This file is part of Contao.
  5.  *
  6.  * (c) Leo Feyer
  7.  *
  8.  * @license LGPL-3.0-or-later
  9.  */
  10. namespace Contao\CoreBundle\Routing;
  11. use Contao\CoreBundle\Framework\ContaoFramework;
  12. use Contao\CoreBundle\Routing\Page\PageRoute;
  13. use Contao\CoreBundle\Util\LocaleUtil;
  14. use Contao\Model\Collection;
  15. use Contao\PageModel;
  16. use Symfony\Cmf\Component\Routing\Candidates\CandidatesInterface;
  17. use Symfony\Cmf\Component\Routing\RouteProviderInterface;
  18. use Symfony\Component\HttpFoundation\Request;
  19. use Symfony\Component\Routing\Route;
  20. abstract class AbstractPageRouteProvider implements RouteProviderInterface
  21. {
  22.     /**
  23.      * @var ContaoFramework
  24.      */
  25.     protected $framework;
  26.     /**
  27.      * @var CandidatesInterface
  28.      */
  29.     protected $candidates;
  30.     public function __construct(ContaoFramework $frameworkCandidatesInterface $candidates)
  31.     {
  32.         $this->framework $framework;
  33.         $this->candidates $candidates;
  34.     }
  35.     /**
  36.      * @return array<PageModel>
  37.      */
  38.     protected function findCandidatePages(Request $request): array
  39.     {
  40.         $candidates array_map('strval'$this->candidates->getCandidates($request));
  41.         if (empty($candidates)) {
  42.             return [];
  43.         }
  44.         $ids = [];
  45.         $aliases = [];
  46.         foreach ($candidates as $candidate) {
  47.             if (preg_match('/^[1-9]\d*$/'$candidate)) {
  48.                 $ids[] = (int) $candidate;
  49.             } else {
  50.                 $aliases[] = $candidate;
  51.             }
  52.         }
  53.         $conditions = [];
  54.         if (!empty($ids)) {
  55.             $conditions[] = 'tl_page.id IN ('.implode(','$ids).')';
  56.         }
  57.         if (!empty($aliases)) {
  58.             $conditions[] = 'tl_page.alias IN ('.implode(','array_fill(0, \count($aliases), '?')).')';
  59.         }
  60.         /** @var PageModel $pageModel */
  61.         $pageModel $this->framework->getAdapter(PageModel::class);
  62.         $pages $pageModel->findBy([implode(' OR '$conditions)], $aliases);
  63.         if (!$pages instanceof Collection) {
  64.             return [];
  65.         }
  66.         /** @var array<PageModel> */
  67.         return $pages->getModels();
  68.     }
  69.     /**
  70.      * @return array<int>
  71.      */
  72.     protected function getPageIdsFromNames(array $names): array
  73.     {
  74.         $ids = [];
  75.         foreach ($names as $name) {
  76.             if (!== strncmp($name'tl_page.'8)) {
  77.                 continue;
  78.             }
  79.             [, $id] = explode('.'$name);
  80.             if (!preg_match('/^[1-9]\d*$/'$id)) {
  81.                 continue;
  82.             }
  83.             $ids[] = (int) $id;
  84.         }
  85.         return array_unique($ids);
  86.     }
  87.     protected function compareRoutes(Route $aRoute $b, array $languages null): int
  88.     {
  89.         if ('' !== $a->getHost() && '' === $b->getHost()) {
  90.             return -1;
  91.         }
  92.         if ('' === $a->getHost() && '' !== $b->getHost()) {
  93.             return 1;
  94.         }
  95.         /** @var PageModel|null $pageA */
  96.         $pageA $a->getDefault('pageModel');
  97.         /** @var PageModel|null $pageB */
  98.         $pageB $b->getDefault('pageModel');
  99.         // Check if the page models are valid (should always be the case, as routes are generated from pages)
  100.         if (!$pageA instanceof PageModel || !$pageB instanceof PageModel) {
  101.             return 0;
  102.         }
  103.         $langA null;
  104.         $langB null;
  105.         if (null !== $languages && $pageA->rootLanguage !== $pageB->rootLanguage) {
  106.             $fallbackA LocaleUtil::getFallbacks($pageA->rootLanguage);
  107.             $fallbackB LocaleUtil::getFallbacks($pageB->rootLanguage);
  108.             $langA $this->getLocalePriority($fallbackA$fallbackB$languages);
  109.             $langB $this->getLocalePriority($fallbackB$fallbackA$languages);
  110.             if (null === $langA && null === $langB && LocaleUtil::getPrimaryLanguage($pageA->rootLanguage) === \Locale::getPrimaryLanguage($pageB->rootLanguage)) {
  111.                 // If both pages have the same language without region and neither region has a priority,
  112.                 // (e.g. user prefers "de" but we have "de-CH" and "de-DE"), sort by their root page order.
  113.                 $langA $pageA->rootSorting;
  114.                 $langB $pageB->rootSorting;
  115.             }
  116.         }
  117.         if (null === $langA && null === $langB) {
  118.             if ($pageA->rootIsFallback && !$pageB->rootIsFallback) {
  119.                 return -1;
  120.             }
  121.             if ($pageB->rootIsFallback && !$pageA->rootIsFallback) {
  122.                 return 1;
  123.             }
  124.         } else {
  125.             if (null === $langA && null !== $langB) {
  126.                 return 1;
  127.             }
  128.             if (null !== $langA && null === $langB) {
  129.                 return -1;
  130.             }
  131.             if ($langA $langB) {
  132.                 return -1;
  133.             }
  134.             if ($langA $langB) {
  135.                 return 1;
  136.             }
  137.         }
  138.         if ('root' !== $pageA->type && 'root' === $pageB->type) {
  139.             return -1;
  140.         }
  141.         if ('root' === $pageA->type && 'root' !== $pageB->type) {
  142.             return 1;
  143.         }
  144.         $pathA $a instanceof PageRoute && $a->getUrlSuffix() ? substr($a->getPath(), 0, -\strlen($a->getUrlSuffix())) : $a->getPath();
  145.         $pathB $b instanceof PageRoute && $b->getUrlSuffix() ? substr($b->getPath(), 0, -\strlen($b->getUrlSuffix())) : $b->getPath();
  146.         $countA = \count(explode('/'$pathA));
  147.         $countB = \count(explode('/'$pathB));
  148.         if ($countA $countB) {
  149.             return -1;
  150.         }
  151.         if ($countB $countA) {
  152.             return 1;
  153.         }
  154.         return strnatcasecmp($pathA$pathB);
  155.     }
  156.     protected function convertLanguagesForSorting(array $languages): array
  157.     {
  158.         $result = [];
  159.         foreach ($languages as $language) {
  160.             if (!$locales LocaleUtil::getFallbacks($language)) {
  161.                 continue;
  162.             }
  163.             $language array_pop($locales);
  164.             $result[] = $language;
  165.             foreach (array_reverse($locales) as $locale) {
  166.                 if (!\in_array($locale$resulttrue)) {
  167.                     $result[] = $locale;
  168.                 }
  169.             }
  170.         }
  171.         return array_flip($result);
  172.     }
  173.     private function getLocalePriority(array $locales, array $notIn, array $languagePriority): ?int
  174.     {
  175.         foreach (array_reverse($locales) as $locale) {
  176.             if (isset($languagePriority[$locale]) && !\in_array($locale$notIntrue)) {
  177.                 return $languagePriority[$locale];
  178.             }
  179.         }
  180.         return null;
  181.     }
  182. }