vendor/contao/core-bundle/src/Routing/Matcher/LegacyMatcher.php line 59

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\Matcher;
  11. use Contao\Config;
  12. use Contao\CoreBundle\Framework\ContaoFramework;
  13. use Contao\Input;
  14. use Contao\PageModel;
  15. use Contao\System;
  16. use Symfony\Component\HttpFoundation\Request;
  17. use Symfony\Component\Routing\Exception\ResourceNotFoundException;
  18. use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
  19. class LegacyMatcher implements RequestMatcherInterface
  20. {
  21.     /**
  22.      * @var ContaoFramework
  23.      */
  24.     private $framework;
  25.     /**
  26.      * @var RequestMatcherInterface
  27.      */
  28.     private $requestMatcher;
  29.     /**
  30.      * @var string
  31.      */
  32.     private $urlSuffix;
  33.     /**
  34.      * @var bool
  35.      */
  36.     private $prependLocale;
  37.     /**
  38.      * @internal Do not inherit from this class; decorate the "contao.routing.legacy_matcher" service instead
  39.      */
  40.     public function __construct(ContaoFramework $frameworkRequestMatcherInterface $requestMatcherstring $urlSuffixbool $prependLocale)
  41.     {
  42.         $this->framework $framework;
  43.         $this->requestMatcher $requestMatcher;
  44.         $this->urlSuffix $urlSuffix;
  45.         $this->prependLocale $prependLocale;
  46.     }
  47.     public function matchRequest(Request $request): array
  48.     {
  49.         $this->framework->initialize(true);
  50.         $pathInfo rawurldecode($request->getPathInfo());
  51.         if (
  52.             '/' === $pathInfo
  53.             || empty($GLOBALS['TL_HOOKS']['getPageIdFromUrl'])
  54.             || !\is_array($GLOBALS['TL_HOOKS']['getPageIdFromUrl'])
  55.             || ($this->prependLocale && preg_match('@^/([a-z]{2}(-[A-Z]{2})?)/$@'$pathInfo))
  56.         ) {
  57.             return $this->requestMatcher->matchRequest($request);
  58.         }
  59.         $locale null;
  60.         $fragments null;
  61.         /** @var Config $config */
  62.         $config $this->framework->getAdapter(Config::class);
  63.         if ($config->get('folderUrl')) {
  64.             try {
  65.                 $match $this->requestMatcher->matchRequest($request);
  66.                 $fragments $this->createFragmentsFromMatch($match);
  67.                 $locale $match['_locale'] ?? null;
  68.             } catch (ResourceNotFoundException $e) {
  69.                 // Continue and parse fragments from path
  70.             }
  71.         }
  72.         if (null === $fragments) {
  73.             $pathInfo $this->parseSuffixAndLanguage($pathInfo$locale);
  74.             $fragments $this->createFragmentsFromPath($pathInfo);
  75.         }
  76.         if ($this->prependLocale) {
  77.             if (null === $locale) {
  78.                 throw new ResourceNotFoundException('Locale is missing');
  79.             }
  80.             /** @var Input $input */
  81.             $input $this->framework->getAdapter(Input::class);
  82.             $input->setGet('language'$locale);
  83.         }
  84.         @trigger_error('Using the "getPageIdFromUrl" hook has been deprecated and will no longer work in Contao 5.0.'E_USER_DEPRECATED);
  85.         $fragments $this->executeLegacyHook($fragments);
  86.         $pathInfo $this->createPathFromFragments($fragments$locale);
  87.         return $this->requestMatcher->matchRequest($this->rebuildRequest($pathInfo$request));
  88.     }
  89.     private function createFragmentsFromMatch(array $match): array
  90.     {
  91.         $page $match['pageModel'] ?? null;
  92.         $parameters $match['parameters'] ?? '';
  93.         if (!$page instanceof PageModel) {
  94.             throw new ResourceNotFoundException('Resource not found');
  95.         }
  96.         if ('' === $parameters) {
  97.             return [$page->alias];
  98.         }
  99.         /** @var Config $config */
  100.         $config $this->framework->getAdapter(Config::class);
  101.         $fragments array_merge([$page->alias], explode('/'substr($parameters1)));
  102.         // Add the second fragment as auto_item if the number of fragments is even
  103.         if ($config->get('useAutoItem') && === \count($fragments) % 2) {
  104.             array_splice($fragments10, ['auto_item']);
  105.         }
  106.         return $fragments;
  107.     }
  108.     private function createFragmentsFromPath(string $pathInfo): array
  109.     {
  110.         /** @var Config $config */
  111.         $config $this->framework->getAdapter(Config::class);
  112.         $fragments explode('/'$pathInfo);
  113.         // Add the second fragment as auto_item if the number of fragments is even
  114.         if ($config->get('useAutoItem') && === \count($fragments) % 2) {
  115.             array_splice($fragments10, ['auto_item']);
  116.         }
  117.         return $fragments;
  118.     }
  119.     private function executeLegacyHook(array $fragments): array
  120.     {
  121.         /** @var System $system */
  122.         $system $this->framework->getAdapter(System::class);
  123.         foreach ($GLOBALS['TL_HOOKS']['getPageIdFromUrl'] as $callback) {
  124.             $fragments $system->importStatic($callback[0])->{$callback[1]}($fragments);
  125.         }
  126.         // Return if the alias is empty (see #4702 and #4972)
  127.         if ('' === $fragments[0]) {
  128.             throw new ResourceNotFoundException('Page alias is empty');
  129.         }
  130.         return $fragments;
  131.     }
  132.     private function createPathFromFragments(array $fragments, ?string $locale): string
  133.     {
  134.         /** @var Config $config */
  135.         $config $this->framework->getAdapter(Config::class);
  136.         if (isset($fragments[1]) && 'auto_item' === $fragments[1] && $config->get('useAutoItem')) {
  137.             unset($fragments[1]);
  138.         }
  139.         $pathInfo implode('/'$fragments).$this->urlSuffix;
  140.         if ($this->prependLocale) {
  141.             $pathInfo $locale.'/'.$pathInfo;
  142.         }
  143.         return '/'.$pathInfo;
  144.     }
  145.     private function parseSuffixAndLanguage(string $pathInfo, ?string &$locale): string
  146.     {
  147.         $suffixLength = \strlen($this->urlSuffix);
  148.         if (!== $suffixLength) {
  149.             if (substr($pathInfo, -$suffixLength) !== $this->urlSuffix) {
  150.                 throw new ResourceNotFoundException('URL suffix does not match');
  151.             }
  152.             $pathInfo substr($pathInfo0, -$suffixLength);
  153.         }
  154.         if (=== strncmp($pathInfo'/'1)) {
  155.             $pathInfo substr($pathInfo1);
  156.         }
  157.         if ($this->prependLocale) {
  158.             $matches = [];
  159.             if (!preg_match('@^([a-z]{2}(-[A-Z]{2})?)/(.+)$@'$pathInfo$matches)) {
  160.                 throw new ResourceNotFoundException('Locale does not match');
  161.             }
  162.             [, $locale,, $pathInfo] = $matches;
  163.         }
  164.         return $pathInfo;
  165.     }
  166.     /**
  167.      * @see ChainRouter::rebuildRequest()
  168.      */
  169.     private function rebuildRequest(string $pathinfoRequest $request): Request
  170.     {
  171.         $uri $pathinfo;
  172.         $server = [];
  173.         if ($request->getBaseUrl()) {
  174.             $uri $request->getBaseUrl().$pathinfo;
  175.             $server['SCRIPT_FILENAME'] = $request->getBaseUrl();
  176.             $server['PHP_SELF'] = $request->getBaseUrl();
  177.         }
  178.         $host $request->getHttpHost() ?: 'localhost';
  179.         $scheme $request->getScheme() ?: 'http';
  180.         $uri $scheme.'://'.$host.$uri.'?'.$request->getQueryString();
  181.         return Request::create($uri$request->getMethod(), [], [], [], $server);
  182.     }
  183. }