This article mainly introduces the interpretation of the Laravel controller, has a certain reference value, now share to everyone, the need for friends can refer to
Controller
The controller is able to compose the related request processing logic into a separate class, through the preceding routing and middleware two chapters we have repeatedly emphasized that the Laravel application request will be the base middleware defined in HTTP kernel in the first place after entering the application
protected $middleware = [ \illuminate\foundation\http\middleware\checkformaintenancemode::class, \ Illuminate\foundation\http\middleware\validatepostsize::class, \app\http\middleware\trimstrings::class, \illuminate\foundation\http\middleware\convertemptystringstonull::class, \app\http\middleware\ Trustproxies::class,];
The HTTP kernel is then dispatchToRoute
processed by handing over the request object to the routing object, and the routing object collects the middleware bound on the route and then uses a pipeline pipe object to transmit the request through these intermediate keys bound by these routes, as in the HTTP kernel above. When the destination is reached, the route-bound controller method is executed and the execution result is encapsulated as a response object, and the response object is returned to the client at once through the post-middleware.
Here is the core code for the steps that you just said:
Namespace Illuminate\foundation\http;class Kernel implements kernelcontract{protected function Dispatchtorouter () { return function ($request) {$this->app->instance (' request ', $request); return $this->router->dispatch ($request); }; }}namespace Illuminate\routing;class Router implements Registrarcontract, bindingregistrar{public function DISPATC H (Request $request) {$this->currentrequest = $request; return $this->dispatchtoroute ($request); The Public Function Dispatchtoroute (Request $request) {return $this->runroute ($request, $this->findr Oute ($request)); } 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 (' Middlewa Re.disable ') = = = true; Collects middleware $middleware for routing and controller applications = $shouldSkipMiddleware? []: $this->gatherroutemiddleware ($route); Return (new Pipeline ($this->container))->send ($request)->through ($middlew IS)->then (function ($request) use ($route) {return $this->preparerespon Se ($request, $route->run ()); }); }}namespace illuminate\routing;class route{Public Function run () {$this->container = $this->container ?: New Container; try {if ($this->iscontrolleractioN ()) {return $this->runcontroller (); } return $this->runcallable (); } catch (Httpresponseexception $e) {return $e->getresponse (); } }}
We have explained in detail the principles of pipeline, middleware, and routing in the previous article, and then look at how Laravel injects the correct parameters for the Controller method and invokes the Controller method after the request finally finds the corresponding controller method for the route.
Resolving controller and method names
The operation of the routing controller Method runController
will now resolve the controller name and the method name in the outlet. We said in the chapter on routing that the Action property of a routed object is similar to the following:
[ ' uses ' = ' app\http\controllers\somecontroller@someaction ', ' controller ' = ' app\http\controllers\ ' Somecontroller@someaction ', ' middleware ' = ...]
Class route{protected function iscontrolleraction () {return is_string ($this->action[' uses ']); } protected function Runcontroller () {return (new Controllerdispatcher ($this->container))->dispatch ( $this, $this->getcontroller (), $this->getcontrollermethod ()); Public Function Getcontroller () {if (! $this->controller) {$class = $this->parsecont Rollercallback () [0]; $this->controller = $this->container->make (LTrim ($class, ' \ \ ')); } return $this->controller; } protected function Getcontrollermethod () {return $this->parsecontrollercallback () [1]; } protected function Parsecontrollercallback () {return Str::p arsecallback ($this->action[' uses ']); }}class str{//resolves the Controller method string that is bound in the route, returns the array public static function Parsecallback ($callback, $default = null) of the controller and method name strings {return Static::contains ($callbAck, ' @ ')? Explode (' @ ', $callback, 2): [$callback, $default]; }}
Therefore, the route through the parseCallback
method of the controller string in the uses configuration item to parse the array returned, the first item of the list is the controller name, the second item is the method name. After getting the name string for the controller and method, the routing object passes itself, the controller, and the method name to the Illuminate\Routing\ControllerDispatcher
class, which ControllerDispatcher
completes the call to the final controller method. Let's take a closer look at ControllerDispatcher
how the controller method is called.
Class controllerdispatcher{use routedependencyresolvertrait; 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))} }
As can be clearly seen above, the controller in the Controllerdispatcher is divided into two steps: To solve the parameter dependence of method resolveClassMethodDependencies
, call the controller methods.
Resolve Method Parameter Dependency
The parameter of the workaround is dependent through routedependencyresolvertrait
This trait
is responsible for:
Trait routedependencyresolvertrait{protected function resolveclassmethoddependencies (array $parameters, $instance, $ method) {if (! method_exists ($instance, $method)) {return $parameters; } return $this->resolvemethoddependencies ($parameters, New Reflectionmethod ($instanc E, $method)); }//parameter is an array of route parameters $parameters (nullable array) and the reflection object of the Controller method public function resolvemethoddependencies (array $parameters, Reflectio Nfunctionabstract $reflector) {$instanceCount = 0; $values = Array_values ($parameters); foreach ($reflector->getparameters () as $key = = $parameter) {$instance = $this->transformdependency ( $parameter, $parameters); if (! Is_null ($instance)) {$instanceCount + +; $this->spliceintoparameters ($parameters, $key, $instance); } elseif (! isset ($values [$key-$instanceCount]) && $parameter->isdefaultvalueavailable ()) {$this->spliceintoparameters ($parameters, $key, $parameter->getdefaultvalue ()); }} return $parameters; } }
When a solution's parameter dependency is applied to a class of PHP reflection to ReflectionMethod
direction the controller method, a reflection object gets to the parameter to determine whether the type hint (type hint) of the existing parameter is a class object parameter. If it is a class object parameter and does not have an object of the same class in the existing parameter, the class object is out of the service container make
.
protected function transformdependency (Reflectionparameter $parameter, $parameters) { $class = $parameter- >getclass (); if ($class &&! $this->alreadyinparameters ($class->name, $parameters)) { return $parameter Isdefaultvalueavailable () ? $parameter->getdefaultvalue () : $this->container->make ($class, name); } } protected function Alreadyinparameters ($class, array $parameters) { return! Is_null (Arr::first ($ Parameters, function ($value) use ($class) { return $value instanceof $class; })
The class object needs to be inserted into the parameter list after parsing out the class object.
protected function Spliceintoparameters (array & $parameters, $offset, $value) { Array_splice ( $ Parameters, $offset, 0, [$value] ); }
Before we talked about service containers, the service parsing solution inside is the parameter dependency of the class construction method, and here Resolveclassmethoddependencies solves the parameter dependence of a specific method, it laravel to method dependency Implementation of the injection concept.
When the parameter array of a route and the number of class objects constructed by the service container are not sufficient to cover the number of controller method parameters, it is necessary to determine whether the parameter has a default parameter, that is, the resolveMethodDependencies
foreach
branch in the method block else if
inserts the default parameters of the parameter into the parameter list $parameters
of the method. to the.
} elseif (! isset ($values [$key-$instanceCount]) && $parameter->isdefaultvalueavailable ()) { $ This->spliceintoparameters ($parameters, $key, $parameter->getdefaultvalue ());}
Calling the Controller method
The method is called after solving the parameter dependency, this is very simple, if the controller has Callaction method will call the Callaction method, otherwise it will call the method directly.
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)); }
After the execution of the results, according to runRouteWithinStack
the logic above, the result will be converted to the response object. The response object then sequentially passes through the post-operation of all the middleware that was previously applied, and is returned to the client.
The above is the whole content of this article, I hope that everyone's learning has helped, more relevant content please pay attention to topic.alibabacloud.com!