The use of routing in Laravel framework (source code analysis)

01-28-2024

What this article brings to you is about the use of routing under Laravel framework (source code analysis), which has certain reference value. Friends who need it can refer to it and hope to help you. Foreword My analytical article is not a deep and multi-field analytical strategy. However, reading such articles with reference to the development documents will make you by going up one flight of stairs in your daily development.

Without further ado, let's start this chapter.

After the portal Laravel is started, the service provider, middleware and other components will be loaded first. Before finding the Route, because we use the facade, we must first find the entity class of the route.

The first step of registration is, of course, through the service provider, because this is the key to laravel's startup, and the routing file is loaded in the RouteServiceProvider.

protected function mapApiRoutes() { Route::prefix('api') ->middleware('api') -> namespace ($ this-> namespace)//Set the namespace. ->group(base_path('routes/api.php')); //Absolute path of the obtained routing file }

First of all, require is indispensable. Because there is no namespace in the routing file. Method under Illuminate\Routing\Router

protected function loadRoutes($routes) { if ($routes instanceof Closure) { $routes($this); } else { $router = $this; require $routes; } }

Then find the specified method through routing, and all the routing related methods you use, such as get, post, put, patch, etc., are still in Illuminate\Routing\Router, and they all call the unified method addRoute.

public function addRoute($methods, $uri, $action) { return $this->routes->add($this->createRoute($methods, $uri, $action)); }

Then it is added to the collection by illuminating \ routing \ route collection addtocollections method.

protected function addToCollections($route) { $domainAndUri = $route->getDomain().$route->uri(); foreach ($route->methods() as $method) { $this->routes

Call the logic that starts running routing instantiation through the Illuminate\Routing\Router method.

protected function runRoute(Request $request, Route $route) { $request->setRouteResolver(function () use ($route) { return $route; }); $this->events->dispatch(new Events\RouteMatched($route, $request)); return $this->prepareResponse($request, $this->runRouteWithinStack($route, $request) ); } .... protected function runRouteWithinStack(Route $route, Request $request) { $shouldSkipMiddleware = $this->container->bound('middleware.disable') && $this->container->make('middleware.disable') === true; $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route); return (new Pipeline($this->container)) ->send($request) ->through($middleware) ->then(function ($request) use ($route) { return $this->prepareResponse( $request, $route->run() // The run method is called here. ); }); }

The method used by the run party to execute the controller under Illuminate\Routing\Route.

public function run() { $this->container = $this->container ? : new Container; try { if ($this->isControllerAction()) { return $this->runController(); //Run a route and respond. } return $this->runCallable(); } catch (HttpResponseException $e) { return $e->getResponse(); } }

From the above method, we can see that the runController is the key to running the route, and a dispatcher runs in the method, and the controller $this->getController () and the controller method $this->getControllerMethod () are passed into the dispatch scheduling method.

protected function runController() { return $this->controllerDispatcher()->dispatch( $this, $this->getController(), $this->getControllerMethod() ); }

Note here that getController () is the real way to instantiate the controller.

public function getController() { if (! $this->controller) { $class = $this->parseControllerCallback()[0]; // 0= > controller xxController 1= > method name index $this->controller = $this->container->make(ltrim($class, '\\')); //Give it to the container for reflection. } return $this->controller; }

Instantiation still loads the controller specified by the route through reflection. At this time, the parameter of build is $ concrete = app \ API \ controllers \ xxxcontroller.

public function build($concrete) { // If the concrete type is actually a Closure, we will just execute it and // hand back the results of the functions, which allows functions to be // used as resolvers for more fine-tuned resolution of these objects. if ($concrete instanceof Closure) { return $concrete($this, $this->getLastParameterOverride()); } $reflector = new ReflectionClass($concrete); // If the type is not instantiable, the developer is attempting to resolve // an abstract type such as an Interface of Abstract Class and there is // no binding registered for the abstractions so we need to bail out. if (! $reflector->isInstantiable()) { return $this->notInstantiable($concrete); } $this->buildStack[] = $concrete; $constructor = $reflector->getConstructor(); // If there are no constructors, that means there are no dependencies then // we can just resolve the instances of the objects right away, without // resolving any other types or dependencies out of these containers. if (is_null($constructor)) { array_pop($this->buildStack); return new $concrete; } $dependencies = $constructor->getParameters(); // Once we have all the constructor's parameters we can create each of the // dependency instances and then use the reflection instances to make a // new instance of this class, injecting the created dependencies in. $instances = $this->resolveDependencies( $dependencies ); array_pop($this->buildStack); return $reflector->newInstanceArgs($instances); }

At this time, the instance of the controller will be returned, and the specified method will be accessed through the url below. Generally, the controller will inherit the parent class Illuminate \ Routing \ Controller, and Laravel has set the alias BaseController for it.

public function dispatch(Route $route, $controller, $method) { $parameters = $this->resolveClassMethodDependencies( $route->parametersWithoutNulls(), $controller, $method ); if (method_exists($controller, 'callAction')) { return $controller->callAction($method, $parameters); } return $controller->{$method}(...array_values($parameters)); }

Laravel calls the specified method of the subclass through callAction inherited by the controller, which is the custom method we want to call.

public function callAction($method, $parameters) { return call_user_func_array([$this, $method], $parameters); }

Copyright Description:No reproduction without permission。

Knowledge sharing community for developers。

Let more developers benefit from it。

Help developers share knowledge through the Internet。

Follow us