master

laravel/framework

Last updated at: 29/12/2023 09:25

RouteCollection.php

TLDR

This file, RouteCollection.php, is a part of the Illuminate Routing component of the Laravel framework. It defines a class RouteCollection that manages a collection of routes. The class provides methods for adding routes, retrieving routes based on various criteria, and performing lookups based on route names or controller actions.

Methods

add

This method adds a Route instance to the collection. It adds the route to the internal arrays used for method-based and all routes lookup.

addToCollections

This method adds the given route to the arrays of routes. It adds the route to the method-based routing array and the all routes array.

addLookups

This method adds the route to the lookup tables if necessary. If the route has a name, it adds it to the name lookup table. If the route is routed to a controller, it adds the action and route pair to the action lookup table.

addToActionList

This method adds a route to the controller action dictionary. It adds the specified action and route pair to the action lookup table.

refreshNameLookups

This method refreshes the name lookup table. It clears the existing name lookup table and rebuilds it by iterating through all the routes in the collection.

refreshActionLookups

This method refreshes the action lookup table. It clears the existing action lookup table and rebuilds it by iterating through all the routes in the collection.

match

This method finds the first route that matches the given request. It gets the routes for the specified request method and then matches the request against those routes. It returns the matched route or throws exceptions if no matching route is found.

get

This method retrieves routes from the collection based on the specified method. If no method is provided, it returns all routes. Otherwise, it returns the routes for the specified method.

hasNamedRoute

This method determines if the route collection contains a route with the specified name. It returns true if a matching named route is found; otherwise, returns false.

getByName

This method retrieves a route instance by its name. It returns the route corresponding to the specified name or null if no matching named route is found.

getByAction

This method retrieves a route instance by its controller action. It returns the route corresponding to the specified action or null if no matching route is found.

getRoutes

This method retrieves all routes in the collection. It returns an array of Route instances.

getRoutesByMethod

This method retrieves all routes in the collection and organizes them by their HTTP verb or method. It returns an array where the keys are the methods and the values are arrays of routes.

getRoutesByName

This method retrieves all routes in the collection and organizes them by their name. It returns an array where the keys are the names and the values are routes.

toSymfonyRouteCollection

This method converts the collection to an instance of the Symfony RouteCollection class. It first calls the parent class's toSymfonyRouteCollection method to get the Symfony routes and then refreshes the name lookup table. It returns the Symfony route collection.

toCompiledRouteCollection

This method converts the collection to an instance of the CompiledRouteCollection class. It compiles the routes using the compile method, creates a new CompiledRouteCollection instance with the compiled routes and their attributes, and sets the router and container on the new instance. It returns the compiled route collection.

Class

This file defines a single class, RouteCollection, which manages a collection of routes. The class extends the AbstractRouteCollection class and provides methods for adding and retrieving routes, as well as performing various lookups.

<?php

namespace Illuminate\Routing;

use Illuminate\Container\Container;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;

class RouteCollection extends AbstractRouteCollection
{
    /**
     * An array of the routes keyed by method.
     *
     * @var array
     */
    protected $routes = [];

    /**
     * A flattened array of all of the routes.
     *
     * @var \Illuminate\Routing\Route[]
     */
    protected $allRoutes = [];

    /**
     * A look-up table of routes by their names.
     *
     * @var \Illuminate\Routing\Route[]
     */
    protected $nameList = [];

    /**
     * A look-up table of routes by controller action.
     *
     * @var \Illuminate\Routing\Route[]
     */
    protected $actionList = [];

    /**
     * Add a Route instance to the collection.
     *
     * @param  \Illuminate\Routing\Route  $route
     * @return \Illuminate\Routing\Route
     */
    public function add(Route $route)
    {
        $this->addToCollections($route);

        $this->addLookups($route);

        return $route;
    }

    /**
     * Add the given route to the arrays of routes.
     *
     * @param  \Illuminate\Routing\Route  $route
     * @return void
     */
    protected function addToCollections($route)
    {
        $domainAndUri = $route->getDomain().$route->uri();

        foreach ($route->methods() as $method) {
            $this->routes[$method][$domainAndUri] = $route;
        }

        $this->allRoutes[$method.$domainAndUri] = $route;
    }

    /**
     * Add the route to any look-up tables if necessary.
     *
     * @param  \Illuminate\Routing\Route  $route
     * @return void
     */
    protected function addLookups($route)
    {
        // If the route has a name, we will add it to the name look-up table so that we
        // will quickly be able to find any route associate with a name and not have
        // to iterate through every route every time we need to perform a look-up.
        if ($name = $route->getName()) {
            $this->nameList[$name] = $route;
        }

        // When the route is routing to a controller we will also store the action that
        // is used by the route. This will let us reverse route to controllers while
        // processing a request and easily generate URLs to the given controllers.
        $action = $route->getAction();

        if (isset($action['controller'])) {
            $this->addToActionList($action, $route);
        }
    }

    /**
     * Add a route to the controller action dictionary.
     *
     * @param  array  $action
     * @param  \Illuminate\Routing\Route  $route
     * @return void
     */
    protected function addToActionList($action, $route)
    {
        $this->actionList[trim($action['controller'], '\\')] = $route;
    }

    /**
     * Refresh the name look-up table.
     *
     * This is done in case any names are fluently defined or if routes are overwritten.
     *
     * @return void
     */
    public function refreshNameLookups()
    {
        $this->nameList = [];

        foreach ($this->allRoutes as $route) {
            if ($route->getName()) {
                $this->nameList[$route->getName()] = $route;
            }
        }
    }

    /**
     * Refresh the action look-up table.
     *
     * This is done in case any actions are overwritten with new controllers.
     *
     * @return void
     */
    public function refreshActionLookups()
    {
        $this->actionList = [];

        foreach ($this->allRoutes as $route) {
            if (isset($route->getAction()['controller'])) {
                $this->addToActionList($route->getAction(), $route);
            }
        }
    }

    /**
     * Find the first route matching a given request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Routing\Route
     *
     * @throws \Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
     * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
     */
    public function match(Request $request)
    {
        $routes = $this->get($request->getMethod());

        // First, we will see if we can find a matching route for this current request
        // method. If we can, great, we can just return it so that it can be called
        // by the consumer. Otherwise we will check for routes with another verb.
        $route = $this->matchAgainstRoutes($routes, $request);

        return $this->handleMatchedRoute($request, $route);
    }

    /**
     * Get routes from the collection by method.
     *
     * @param  string|null  $method
     * @return \Illuminate\Routing\Route[]
     */
    public function get($method = null)
    {
        return is_null($method) ? $this->getRoutes() : Arr::get($this->routes, $method, []);
    }

    /**
     * Determine if the route collection contains a given named route.
     *
     * @param  string  $name
     * @return bool
     */
    public function hasNamedRoute($name)
    {
        return ! is_null($this->getByName($name));
    }

    /**
     * Get a route instance by its name.
     *
     * @param  string  $name
     * @return \Illuminate\Routing\Route|null
     */
    public function getByName($name)
    {
        return $this->nameList[$name] ?? null;
    }

    /**
     * Get a route instance by its controller action.
     *
     * @param  string  $action
     * @return \Illuminate\Routing\Route|null
     */
    public function getByAction($action)
    {
        return $this->actionList[$action] ?? null;
    }

    /**
     * Get all of the routes in the collection.
     *
     * @return \Illuminate\Routing\Route[]
     */
    public function getRoutes()
    {
        return array_values($this->allRoutes);
    }

    /**
     * Get all of the routes keyed by their HTTP verb / method.
     *
     * @return array
     */
    public function getRoutesByMethod()
    {
        return $this->routes;
    }

    /**
     * Get all of the routes keyed by their name.
     *
     * @return \Illuminate\Routing\Route[]
     */
    public function getRoutesByName()
    {
        return $this->nameList;
    }

    /**
     * Convert the collection to a Symfony RouteCollection instance.
     *
     * @return \Symfony\Component\Routing\RouteCollection
     */
    public function toSymfonyRouteCollection()
    {
        $symfonyRoutes = parent::toSymfonyRouteCollection();

        $this->refreshNameLookups();

        return $symfonyRoutes;
    }

    /**
     * Convert the collection to a CompiledRouteCollection instance.
     *
     * @param  \Illuminate\Routing\Router  $router
     * @param  \Illuminate\Container\Container  $container
     * @return \Illuminate\Routing\CompiledRouteCollection
     */
    public function toCompiledRouteCollection(Router $router, Container $container)
    {
        ['compiled' => $compiled, 'attributes' => $attributes] = $this->compile();

        return (new CompiledRouteCollection($compiled, $attributes))
            ->setRouter($router)
            ->setContainer($container);
    }
}