Interpretation of Laravel Controller

Source: Internet
Author: User
Tags reflector
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!

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.