Il pattern pipeline è un design pattern che fa passare un oggetto da elaborare (passable) attraverso una serie ordinata di pipe (step). Ogni pipe riceve l’output dello step precedente, aggiunge la propria elaborazione e passa al successivo.In Laravel il pattern è implementato dalla classe Illuminate\Pipeline\Pipeline; è esattamente il meccanismo che regge l’elaborazione dei middleware.
La pipeline è usata in modo diffuso nel cuore di Laravel.
Middleware HTTP — in Illuminate\Foundation\Http\Kernel la richiesta passa attraverso la pipeline dei middleware
Comandi console — pre e post elaborazione dei comandi Artisan
Middleware del Router — applicazione dei middleware ai gruppi di rotte
Osserviamo il punto in cui l’HTTP kernel usa la pipeline.
// da Illuminate\Foundation\Http\Kernelprotected function sendRequestThroughRouter($request){ return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter());}
$pipeline = app(Pipeline::class) ->send($data) ->through([FirstPipe::class]);// inserisci pipe aggiuntivi in base a una condizioneif ($needsExtra) { $pipeline->pipe(ExtraPipe::class);}$result = $pipeline->thenReturn();
Il metodo carry() è il cuore della pipeline. Con array_reduce piega le pipe da destra a sinistra e costruisce la catena di closure.
// interno di Pipeline::then()protected function carry(){ return function ($stack, $pipe) { return function ($passable) use ($stack, $pipe) { if (is_callable($pipe)) { return $pipe($passable, $stack); } elseif (! is_object($pipe)) { [$name, $parameters] = $this->parsePipeString($pipe); $pipe = $this->getContainer()->make($name); $parameters = array_merge([$passable, $stack], $parameters); } else { $parameters = [$passable, $stack]; } return $pipe->{$this->method}(...$parameters); }; };}
Passando le pipe in ordine inverso ad array_reduce con array_reverse si mantiene l’ordine corretto di invocazione. Lo stack di closure viene costruito dall’interno verso l’esterno, così che la prima pipe venga eseguita per prima.
La pipeline è chiamata anche architettura “a cipolla”. La richiesta attraversa gli strati dall’esterno (la prima pipe) verso l’interno, e la risposta torna indietro dall’interno verso l’esterno. È per questo che ogni middleware può aggiungere logica prima e dopo la chiamata a $next().