Understanding Laravel Pipelines

Photo by Samuel Zeller on Unsplash

Basically, using laravel pipelines you can pass an object between several classes in a fluid way to perform any type of task and finally return the resulting value once all the “tasks” have been executed.

Here you can learn more about the Laravel pipelines

The most clear example about how pipelines works resides in one of the most used components of the framework itself. I’m talking about middlewares.

Middleware provide a convenient mechanism for filtering HTTP requests entering your application…

This is how a basic middleware looks like:

<?php
namespace App\Http\Middleware;
use Closure;
class TestMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
// Here you can add your code
        return $next($request);
}
}

These “middlewares” are in fact just pipes by where the request is going to be sent thru, in order to perform any needed task. Here you can check if the request is an HTTP request, a JSON request, if there is any user authenticated, etc.

If you take a quick look to theIlluminate\Foundation\Http\Kernel class, you’ll see how the middlewares are executed by using a new instance of the Pipeline class.

/**
* Send the given request through the middleware / router.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
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());
}

You can read in the code something like: a new pipeline that sends the request through a list of middlewares and then dispatch the router.

Don’t worry if this seems a little overwhelmed to you. Let’s try to clarify the concept with the follow example.

Working on a class that requires to run multiple tasks

Consider this situation. Let’s say you are building a forum where people can create threads and leave comments. But your client ask you to auto-remove tags or edit them on every piece of content when it’s created.
So this is what you are asked to do:
1. Replace link tags with plain text.
2. Replace bad words with “*”
3. Remove script tags entirely from the content

Probably you end up creating classes to handle each of these “tasks”.

$pipes = [
RemoveBadWords::class
ReplaceLinkTags::clas
RemoveScriptTags::class
];

What we are going to do is to pass the given “content” to each task and then return the result to the next one. We can do this using a pipeline.

<?php

public function create(Request $request)
{
    $pipes = [
RemoveBadWords::class,
ReplaceLinkTags::clas,
RemoveScriptTags::class
];
    $post = app(Pipeline::class)
->send($request->content)
->through($pipes)
->then(function ($content) {
return Post::create(['content' => 'content']);
});
    // return any type of response
}

Each “task” class should have a “handle” method to perform the action. Maybe it would be a good idea to have a contract to be implemented by each class:

<?php

namespace App;

use Closure;

interface Pipe
{
public function handle($content, Closure $next);
}
*Naming things is hard ¯\_(ツ)_/¯*
<?php

namespace App;

use Closure;

class RemoveBadWords implements Pipe
{
public function handle($content, Closure $next)
{
// Here you perform the task and return the updated $content
// to the next pipe
        return  $next($content);
}
}

The method used to perform the task should receive two parameters, the first one would be the passable object, and the second one would be a closure where the object is going to be redirected to after running the last pipe.

You can use a custom method name instead of ‘handle’. Then you need to specify the method name to be used by the pipeline, like so

app(Pipeline::class)
->send($content)
->through($pipes)
->via(‘customMethodName’) // <---- This one :)
->then(function ($content) {
return Post::create(['content' => $content]);
});

What happens at the end ?

What should happen here is that the post content is going to be modified by each one of the $pipesand at the end, this resulting content is going to be stored.

$post = app(Pipeline::class)
->send($request->all())
->through($pipes)
->then(function ($content) {
return Post::create(['content' => $content]);
});

Final words

Remember, there are tons of ways you can approach this type of issues. What you decide to do it’s up to you. But it is good to know that you have this tool in your arsenal to be used if necessary.
I hope this example gives you a better understanding of what these “laravel pipelines” are and how to use them.
You can also take a look at api laravel documents if you want to know more about how this works https://laravel.com/api/5.4/Illuminate/Pipeline/Pipeline.html

Where to use it ?

That would be something for you to find out… If you have any recommendations please let me know. 😉

Show your support

Clapping shows how much you appreciated Jeff’s story.