"Fossies" - the Fresh Open Source Software Archive

Member "framework-8.65.0/src/Illuminate/Routing/AbstractRouteCollection.php" (19 Oct 2021, 7950 Bytes) of package /linux/www/laravel-framework-8.65.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) PHP source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "AbstractRouteCollection.php" see the Fossies "Dox" file reference documentation.

    1 <?php
    2 
    3 namespace Illuminate\Routing;
    4 
    5 use ArrayIterator;
    6 use Countable;
    7 use Illuminate\Http\Request;
    8 use Illuminate\Http\Response;
    9 use Illuminate\Support\Str;
   10 use IteratorAggregate;
   11 use LogicException;
   12 use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
   13 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
   14 use Symfony\Component\Routing\Matcher\Dumper\CompiledUrlMatcherDumper;
   15 use Symfony\Component\Routing\RouteCollection as SymfonyRouteCollection;
   16 
   17 abstract class AbstractRouteCollection implements Countable, IteratorAggregate, RouteCollectionInterface
   18 {
   19     /**
   20      * Handle the matched route.
   21      *
   22      * @param  \Illuminate\Http\Request  $request
   23      * @param  \Illuminate\Routing\Route|null  $route
   24      * @return \Illuminate\Routing\Route
   25      *
   26      * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
   27      */
   28     protected function handleMatchedRoute(Request $request, $route)
   29     {
   30         if (! is_null($route)) {
   31             return $route->bind($request);
   32         }
   33 
   34         // If no route was found we will now check if a matching route is specified by
   35         // another HTTP verb. If it is we will need to throw a MethodNotAllowed and
   36         // inform the user agent of which HTTP verb it should use for this route.
   37         $others = $this->checkForAlternateVerbs($request);
   38 
   39         if (count($others) > 0) {
   40             return $this->getRouteForMethods($request, $others);
   41         }
   42 
   43         throw new NotFoundHttpException;
   44     }
   45 
   46     /**
   47      * Determine if any routes match on another HTTP verb.
   48      *
   49      * @param  \Illuminate\Http\Request  $request
   50      * @return array
   51      */
   52     protected function checkForAlternateVerbs($request)
   53     {
   54         $methods = array_diff(Router::$verbs, [$request->getMethod()]);
   55 
   56         // Here we will spin through all verbs except for the current request verb and
   57         // check to see if any routes respond to them. If they do, we will return a
   58         // proper error response with the correct headers on the response string.
   59         return array_values(array_filter(
   60             $methods,
   61             function ($method) use ($request) {
   62                 return ! is_null($this->matchAgainstRoutes($this->get($method), $request, false));
   63             }
   64         ));
   65     }
   66 
   67     /**
   68      * Determine if a route in the array matches the request.
   69      *
   70      * @param  \Illuminate\Routing\Route[]  $routes
   71      * @param  \Illuminate\Http\Request  $request
   72      * @param  bool  $includingMethod
   73      * @return \Illuminate\Routing\Route|null
   74      */
   75     protected function matchAgainstRoutes(array $routes, $request, $includingMethod = true)
   76     {
   77         [$fallbacks, $routes] = collect($routes)->partition(function ($route) {
   78             return $route->isFallback;
   79         });
   80 
   81         return $routes->merge($fallbacks)->first(function (Route $route) use ($request, $includingMethod) {
   82             return $route->matches($request, $includingMethod);
   83         });
   84     }
   85 
   86     /**
   87      * Get a route (if necessary) that responds when other available methods are present.
   88      *
   89      * @param  \Illuminate\Http\Request  $request
   90      * @param  string[]  $methods
   91      * @return \Illuminate\Routing\Route
   92      *
   93      * @throws \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
   94      */
   95     protected function getRouteForMethods($request, array $methods)
   96     {
   97         if ($request->method() === 'OPTIONS') {
   98             return (new Route('OPTIONS', $request->path(), function () use ($methods) {
   99                 return new Response('', 200, ['Allow' => implode(',', $methods)]);
  100             }))->bind($request);
  101         }
  102 
  103         $this->methodNotAllowed($methods, $request->method());
  104     }
  105 
  106     /**
  107      * Throw a method not allowed HTTP exception.
  108      *
  109      * @param  array  $others
  110      * @param  string  $method
  111      * @return void
  112      *
  113      * @throws \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
  114      */
  115     protected function methodNotAllowed(array $others, $method)
  116     {
  117         throw new MethodNotAllowedHttpException(
  118             $others,
  119             sprintf(
  120                 'The %s method is not supported for this route. Supported methods: %s.',
  121                 $method,
  122                 implode(', ', $others)
  123             )
  124         );
  125     }
  126 
  127     /**
  128      * Compile the routes for caching.
  129      *
  130      * @return array
  131      */
  132     public function compile()
  133     {
  134         $compiled = $this->dumper()->getCompiledRoutes();
  135 
  136         $attributes = [];
  137 
  138         foreach ($this->getRoutes() as $route) {
  139             $attributes[$route->getName()] = [
  140                 'methods' => $route->methods(),
  141                 'uri' => $route->uri(),
  142                 'action' => $route->getAction(),
  143                 'fallback' => $route->isFallback,
  144                 'defaults' => $route->defaults,
  145                 'wheres' => $route->wheres,
  146                 'bindingFields' => $route->bindingFields(),
  147                 'lockSeconds' => $route->locksFor(),
  148                 'waitSeconds' => $route->waitsFor(),
  149                 'withTrashed' => $route->allowsTrashedBindings(),
  150             ];
  151         }
  152 
  153         return compact('compiled', 'attributes');
  154     }
  155 
  156     /**
  157      * Return the CompiledUrlMatcherDumper instance for the route collection.
  158      *
  159      * @return \Symfony\Component\Routing\Matcher\Dumper\CompiledUrlMatcherDumper
  160      */
  161     public function dumper()
  162     {
  163         return new CompiledUrlMatcherDumper($this->toSymfonyRouteCollection());
  164     }
  165 
  166     /**
  167      * Convert the collection to a Symfony RouteCollection instance.
  168      *
  169      * @return \Symfony\Component\Routing\RouteCollection
  170      */
  171     public function toSymfonyRouteCollection()
  172     {
  173         $symfonyRoutes = new SymfonyRouteCollection;
  174 
  175         $routes = $this->getRoutes();
  176 
  177         foreach ($routes as $route) {
  178             if (! $route->isFallback) {
  179                 $symfonyRoutes = $this->addToSymfonyRoutesCollection($symfonyRoutes, $route);
  180             }
  181         }
  182 
  183         foreach ($routes as $route) {
  184             if ($route->isFallback) {
  185                 $symfonyRoutes = $this->addToSymfonyRoutesCollection($symfonyRoutes, $route);
  186             }
  187         }
  188 
  189         return $symfonyRoutes;
  190     }
  191 
  192     /**
  193      * Add a route to the SymfonyRouteCollection instance.
  194      *
  195      * @param  \Symfony\Component\Routing\RouteCollection  $symfonyRoutes
  196      * @param  \Illuminate\Routing\Route  $route
  197      * @return \Symfony\Component\Routing\RouteCollection
  198      *
  199      * @throws \LogicException
  200      */
  201     protected function addToSymfonyRoutesCollection(SymfonyRouteCollection $symfonyRoutes, Route $route)
  202     {
  203         $name = $route->getName();
  204 
  205         if (
  206             ! is_null($name)
  207             && Str::endsWith($name, '.')
  208             && ! is_null($symfonyRoutes->get($name))
  209         ) {
  210             $name = null;
  211         }
  212 
  213         if (! $name) {
  214             $route->name($name = $this->generateRouteName());
  215 
  216             $this->add($route);
  217         } elseif (! is_null($symfonyRoutes->get($name))) {
  218             throw new LogicException("Unable to prepare route [{$route->uri}] for serialization. Another route has already been assigned name [{$name}].");
  219         }
  220 
  221         $symfonyRoutes->add($route->getName(), $route->toSymfonyRoute());
  222 
  223         return $symfonyRoutes;
  224     }
  225 
  226     /**
  227      * Get a randomly generated route name.
  228      *
  229      * @return string
  230      */
  231     protected function generateRouteName()
  232     {
  233         return 'generated::'.Str::random();
  234     }
  235 
  236     /**
  237      * Get an iterator for the items.
  238      *
  239      * @return \ArrayIterator
  240      */
  241     #[\ReturnTypeWillChange]
  242     public function getIterator()
  243     {
  244         return new ArrayIterator($this->getRoutes());
  245     }
  246 
  247     /**
  248      * Count the number of items in the collection.
  249      *
  250      * @return int
  251      */
  252     #[\ReturnTypeWillChange]
  253     public function count()
  254     {
  255         return count($this->getRoutes());
  256     }
  257 }