The concept is easy to understand,but the code is so confused. Every pipe will be run in order . Also they will get the data given by the previous pipe.
let’s see how Laravel get the job done .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Illuminate\Foundation\Http\Kernel protected function sendRequestThroughRouter($request) { $this->app->instance('request', $request); Facade::clearResolvedInstance('request'); $this->bootstrap(); return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter()); } |
Before dispatching the request to router , Laravel will go through all the middleware first. The request object will be passed through all the middleware. middleware array is in the App\Http\Kernel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
Illuminate\Pipeline\Pipeline class Pipeline { //... public function then(Closure $destination) { $pipeline = array_reduce( array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination) ); return $pipeline($this->passable); } protected function carry() { return function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { if (is_callable($pipe)) { // If the pipe is an instance of a Closure, we will just call it directly but // otherwise we'll resolve the pipes out of the container and call it with // the appropriate method and arguments, returning the results back out. return $pipe($passable, $stack); } elseif (! is_object($pipe)) { list($name, $parameters) = $this->parsePipeString($pipe); // If the pipe is a string we will parse the string and resolve the class out // of the dependency injection container. We can then build a callable and // execute the pipe function giving in the parameters that are required. $pipe = $this->getContainer()->make($name); $parameters = array_merge([$passable, $stack], $parameters); } else { // If the pipe is already an object we'll just make a callable and pass it to // the pipe as-is. There is no need to do any extra parsing and formatting // since the object we're given was already a fully instantiated object. $parameters = [$passable, $stack]; } return method_exists($pipe, $this->method) ? $pipe->{$this->method}(...$parameters) : $pipe(...$parameters); }; }; } } |
reference: array_reduce
array_reduce(callable,
this->carry() will return a closure . two parameters (
pipe) will be provided into this closure function .
item is the current pipe. And
stack, it’s a closure function too.
=====>
1 2 3 |
$callable = return function($passable) use($stack,$pipe) { //... } |
The following is how the pipe iterations work.
——————————————————–
let’s say pipe array,so
stack = dispatchToRouter
passable) use (dispatchToRouter ,middleware2) { //….}
Let’s look into detail. u can see the stack will pass into the middleware as parameters.
it’s time to find out how a middleware looks like.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
<?php namespace Illuminate\Foundation\Http\Middleware; use Closure; use Illuminate\Contracts\Foundation\Application; use Illuminate\Foundation\Http\Exceptions\MaintenanceModeException; class CheckForMaintenanceMode { /** * The application implementation. * * @var \Illuminate\Contracts\Foundation\Application */ protected $app; /** * Create a new middleware instance. * * @param \Illuminate\Contracts\Foundation\Application $app * @return void */ public function __construct(Application $app) { $this->app = $app; } /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed * * @throws \Symfony\Component\HttpKernel\Exception\HttpException */ public function handle($request, Closure $next) { if ($this->app->isDownForMaintenance()) { $data = json_decode(file_get_contents($this->app->storagePath().'/framework/down'), true); throw new MaintenanceModeException($data['time'], $data['retry'], $data['message']); } return $next($request); } } |
it will run the next is equal to
stack at the end.
so the execute order looks like this :
dispatchToRouter <- -call– middleware2
=================second iteration=====================
pipe = middleware1
the same as first iteration, the return value will be a closure.
and the execute order will be :
dispatchToRouter <–call–middleware2 <–call– middleware1
========================done=======================
u may be confuse ,they are all closure. when will all these closure get called?
look carefully into the then() function.
the last iteration will return a closure. and the then() function invoke the closure and pass the request object as a parameter.
that’s it!