vendor/symfony-cmf/routing/src/NestedMatcher/NestedMatcher.php line 95

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Symfony CMF package.
  4.  *
  5.  * (c) Symfony CMF
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Symfony\Cmf\Component\Routing\NestedMatcher;
  11. use Symfony\Cmf\Component\Routing\RouteProviderInterface;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\Routing\Exception\ResourceNotFoundException;
  14. use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
  15. /**
  16.  * A more flexible approach to matching. The route collection to match against
  17.  * can be dynamically determined based on the request and users can inject
  18.  * their own filters or use a custom final matching strategy.
  19.  *
  20.  * The nested matcher splits matching into three configurable steps:
  21.  *
  22.  * 1) Get potential matches from a RouteProviderInterface
  23.  * 2) Apply any RouteFilterInterface to reduce the route collection
  24.  * 3) Have FinalMatcherInterface select the best match of the remaining routes
  25.  *
  26.  * @author Larry Garfield
  27.  * @author David Buchmann
  28.  */
  29. final class NestedMatcher implements RequestMatcherInterface
  30. {
  31.     /**
  32.      * The route provider responsible for the first-pass match.
  33.      */
  34.     private RouteProviderInterface $routeProvider;
  35.     private FinalMatcherInterface $finalMatcher;
  36.     /**
  37.      * @var RouteFilterInterface[]
  38.      */
  39.     private array $filters = [];
  40.     /**
  41.      * For caching the sorted $filters.
  42.      *
  43.      * @var RouteFilterInterface[]
  44.      */
  45.     private array $sortedFilters = [];
  46.     public function __construct(RouteProviderInterface $providerFinalMatcherInterface $final)
  47.     {
  48.         $this->setRouteProvider($provider);
  49.         $this->setFinalMatcher($final);
  50.     }
  51.     public function setRouteProvider(RouteProviderInterface $provider): static
  52.     {
  53.         $this->routeProvider $provider;
  54.         return $this;
  55.     }
  56.     /**
  57.      * Adds a partial matcher to the matching plan.
  58.      *
  59.      * Partial matchers will be run in the order in which they are added.
  60.      *
  61.      * @param int $priority (optional) The priority of the
  62.      *                      filter. Higher number filters will
  63.      *                      be used first. Defaults to 0
  64.      */
  65.     public function addRouteFilter(RouteFilterInterface $filterint $priority 0): static
  66.     {
  67.         if (!\array_key_exists($priority$this->filters)) {
  68.             $this->filters[$priority] = [];
  69.         }
  70.         $this->filters[$priority][] = $filter;
  71.         $this->sortedFilters = [];
  72.         return $this;
  73.     }
  74.     public function setFinalMatcher(FinalMatcherInterface $final): static
  75.     {
  76.         $this->finalMatcher $final;
  77.         return $this;
  78.     }
  79.     public function matchRequest(Request $request): array
  80.     {
  81.         $collection $this->routeProvider->getRouteCollectionForRequest($request);
  82.         if (!count($collection)) {
  83.             throw new ResourceNotFoundException();
  84.         }
  85.         // Route filters are expected to throw an exception themselves if they
  86.         // end up filtering the list down to 0.
  87.         foreach ($this->getRouteFilters() as $filter) {
  88.             $collection $filter->filter($collection$request);
  89.         }
  90.         return $this->finalMatcher->finalMatch($collection$request);
  91.     }
  92.     /**
  93.      * Sorts the filters and flattens them.
  94.      *
  95.      * @return RouteFilterInterface[] the filters ordered by priority
  96.      */
  97.     public function getRouteFilters(): array
  98.     {
  99.         if (=== count($this->sortedFilters)) {
  100.             $this->sortedFilters $this->sortFilters();
  101.         }
  102.         return $this->sortedFilters;
  103.     }
  104.     /**
  105.      * Sort filters by priority.
  106.      *
  107.      * The highest priority number is the highest priority (reverse sorting).
  108.      *
  109.      * @return RouteFilterInterface[] the sorted filters
  110.      */
  111.     private function sortFilters(): array
  112.     {
  113.         if (=== count($this->filters)) {
  114.             return [];
  115.         }
  116.         krsort($this->filters);
  117.         return call_user_func_array('array_merge'$this->filters);
  118.     }
  119. }