vendor/contao/core-bundle/src/Routing/Page/PageRegistry.php line 72

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\Page;
  11. use Contao\PageModel;
  12. use Doctrine\DBAL\Connection;
  13. class PageRegistry
  14. {
  15.     private const DISABLE_CONTENT_COMPOSITION = ['redirect''forward''logout'];
  16.     private Connection $connection;
  17.     private ?array $urlPrefixes null;
  18.     private ?array $urlSuffixes null;
  19.     /**
  20.      * @var array<RouteConfig>
  21.      */
  22.     private array $routeConfigs = [];
  23.     /**
  24.      * @var array<DynamicRouteInterface>
  25.      */
  26.     private array $routeEnhancers = [];
  27.     /**
  28.      * @var array<ContentCompositionInterface|bool>
  29.      */
  30.     private array $contentComposition = [];
  31.     public function __construct(Connection $connection)
  32.     {
  33.         $this->connection $connection;
  34.     }
  35.     /**
  36.      * Returns the route for a page.
  37.      *
  38.      * If no path is configured (is null), the route will accept
  39.      * any parameters after the page alias (e.g. "en/page-alias/foo/bar.html").
  40.      *
  41.      * A route enhancer might enhance the route for a specific page.
  42.      */
  43.     public function getRoute(PageModel $pageModel): PageRoute
  44.     {
  45.         $type $pageModel->type;
  46.         $config $this->routeConfigs[$type] ?? new RouteConfig();
  47.         $defaults $config->getDefaults();
  48.         $requirements $config->getRequirements();
  49.         $options $config->getOptions();
  50.         $path $config->getPath();
  51.         if (false === $path) {
  52.             $path '';
  53.             $options['compiler_class'] = UnroutablePageRouteCompiler::class;
  54.         } elseif (null === $path) {
  55.             $path '/'.($pageModel->alias ?: $pageModel->id).'{!parameters}';
  56.             $defaults['parameters'] = '';
  57.             $requirements['parameters'] = $pageModel->requireItem '/.+?' '(/.+?)?';
  58.         }
  59.         $route = new PageRoute($pageModel$path$defaults$requirements$options$config->getMethods());
  60.         if (null !== $config->getUrlSuffix()) {
  61.             $route->setUrlSuffix($config->getUrlSuffix());
  62.         }
  63.         if (!isset($this->routeEnhancers[$type])) {
  64.             return $route;
  65.         }
  66.         /** @var DynamicRouteInterface $enhancer */
  67.         $enhancer $this->routeEnhancers[$type];
  68.         $enhancer->configurePageRoute($route);
  69.         return $route;
  70.     }
  71.     public function getPathRegex(): array
  72.     {
  73.         $prefixes = [];
  74.         foreach ($this->routeConfigs as $type => $config) {
  75.             $regex $config->getPathRegex();
  76.             if (null !== $regex) {
  77.                 $prefixes[$type] = $regex;
  78.             }
  79.         }
  80.         return $prefixes;
  81.     }
  82.     public function supportsContentComposition(PageModel $pageModel): bool
  83.     {
  84.         if (!isset($this->contentComposition[$pageModel->type])) {
  85.             return !\in_array($pageModel->typeself::DISABLE_CONTENT_COMPOSITIONtrue);
  86.         }
  87.         $service $this->contentComposition[$pageModel->type];
  88.         if ($service instanceof ContentCompositionInterface) {
  89.             return $service->supportsContentComposition($pageModel);
  90.         }
  91.         return (bool) $service;
  92.     }
  93.     /**
  94.      * @return array<string>
  95.      */
  96.     public function getUrlPrefixes(): array
  97.     {
  98.         $this->initializePrefixAndSuffix();
  99.         return $this->urlPrefixes;
  100.     }
  101.     /**
  102.      * @return array<string>
  103.      */
  104.     public function getUrlSuffixes(): array
  105.     {
  106.         $this->initializePrefixAndSuffix();
  107.         return $this->urlSuffixes;
  108.     }
  109.     /**
  110.      * @param ContentCompositionInterface|bool $contentComposition
  111.      */
  112.     public function add(string $typeRouteConfig $configDynamicRouteInterface $routeEnhancer null$contentComposition true): self
  113.     {
  114.         // Override existing pages with the same identifier
  115.         $this->routeConfigs[$type] = $config;
  116.         if (null !== $routeEnhancer) {
  117.             $this->routeEnhancers[$type] = $routeEnhancer;
  118.         }
  119.         if (null !== $contentComposition) {
  120.             $this->contentComposition[$type] = $contentComposition;
  121.         }
  122.         $this->urlPrefixes $this->urlSuffixes null;
  123.         return $this;
  124.     }
  125.     public function remove(string $type): self
  126.     {
  127.         unset(
  128.             $this->routeConfigs[$type],
  129.             $this->routeEnhancers[$type],
  130.             $this->contentComposition[$type]
  131.         );
  132.         $this->urlPrefixes $this->urlSuffixes null;
  133.         return $this;
  134.     }
  135.     public function keys(): array
  136.     {
  137.         return array_keys($this->routeConfigs);
  138.     }
  139.     /**
  140.      * Checks whether this is a routable page type (see #3415).
  141.      */
  142.     public function isRoutable(PageModel $page): bool
  143.     {
  144.         $type $page->type;
  145.         // Any legacy page without route config is routable by default
  146.         if (!isset($this->routeConfigs[$type])) {
  147.             return true;
  148.         }
  149.         // Check if page controller is routable
  150.         return false !== $this->routeConfigs[$type]->getPath();
  151.     }
  152.     /**
  153.      * @return array<string>
  154.      */
  155.     public function getUnroutableTypes(): array
  156.     {
  157.         $types = [];
  158.         foreach ($this->routeConfigs as $type => $config) {
  159.             if (false === $config->getPath()) {
  160.                 $types[] = $type;
  161.             }
  162.         }
  163.         return $types;
  164.     }
  165.     private function initializePrefixAndSuffix(): void
  166.     {
  167.         if (null !== $this->urlPrefixes || null !== $this->urlSuffixes) {
  168.             return;
  169.         }
  170.         $results $this->connection->fetchAllAssociative("SELECT urlPrefix, urlSuffix FROM tl_page WHERE type='root'");
  171.         $urlSuffixes = [
  172.             array_column($results'urlSuffix'),
  173.             array_filter(array_map(
  174.                 static fn (RouteConfig $config) => $config->getUrlSuffix(),
  175.                 $this->routeConfigs
  176.             )),
  177.         ];
  178.         foreach ($this->routeConfigs as $config) {
  179.             if (null !== ($suffix $config->getUrlSuffix())) {
  180.                 $urlSuffixes[] = [$suffix];
  181.             }
  182.         }
  183.         foreach ($this->routeEnhancers as $enhancer) {
  184.             $urlSuffixes[] = $enhancer->getUrlSuffixes();
  185.         }
  186.         $this->urlSuffixes array_values(array_unique(array_merge(...$urlSuffixes)));
  187.         $this->urlPrefixes array_values(array_unique(array_column($results'urlPrefix')));
  188.     }
  189. }