Implementing pipeline in laravel

Pipeline is design pattern used in Object Oriented Programming(OOP). It is designed to handle complex processes of manipulating object where object is passed through each task and returns the final executed result. As a result the code becomes easier to maintain and resuseable.

When you go to laravel documentation and search pipeline you won’t see any results. Pipeline is not public facing thing in laravel. But laravel uses pipeline in many of its components. So laravel already ships with implementation of pipeline we don’t have to actually implement it from scratch. You can see its official documentation.

Now lets enter into our main topic. Normally while using filter in our laravel app we go through conditions in controller or anywhere you use your logic. If conditions increase then it becomes difficult to maintain the code.

Let me show you how we normally use filter.

class PostController
{
    public function index(Request $request)
    {
        $query = Post::query();

        if ($request->has('status')) {
            $query->where('status', $request->status);
        }

        if ($request->has('sort')) {
           $query->orderBy('created_at, $request->sort);
        }

        $posts = $query->get();

        return view('post.index', compact('posts'));
    }
}

Although this gives you the result you wanted but as I said earlier it becomes messy if there are multiple conditions.

So now I will show you how we can achieve the same as above funtionality using pipelines.

Let’s make new directory named QueryFilters inside app so that all the pipelines remain in single directory. For this blog we will be filtering on the basis of status and sort them. I assume you already have installed laravel and setup database. Since we have two filtering conditions we make two classes named Status and Sort inside QueryFilters.

Filtering classes

namespace App\QueryFilters;
use Closure;

class Status
{
    public function handle($request, Closure $next){
        if(!request()->has('status')){
            return $next($request);
        }

        $builder=$next($request);
        return  $builder->where('status',request('status'));
    }
}
namespace App\QueryFilters;
use Closure;

class Sort
{
    public function handle($request, Closure $next){
        if(!request()->has('sort')){
            return $next($request);
        }

        $builder=$next($request);
        return  $builder->orderBy('created_at',request('sort'));
    }
}

This handle method will receive two parameters, the first object is what we pass through our pipeline and the second is a closure function that will move forward to our next filter. If you want to make another function instead of handle then you have to pass function name as parameter in via method of pipeline in controller.

Controller

Controller looks like this. We simply import Illuminate\Pipeline\Pipeline and instantiate using app().

use Illuminate\Pipeline\Pipeline;
use App\QueryFilters\Status;
use App\QueryFilters\Sort;
use App\Post;

class PostController
{
    public function index(Request $request)
    {
        $posts=app(Pipeline::class)
            ->send(Post::query())
            ->through([
                Status::class,
                Sort::class])
            ->via('functionName') // use it if you are using your own function instead of handle function.
            ->thenReturn()->get();
           
return view('post.index',compact('posts'));
    }
}
  • send() Set the object being sent through the pipeline.
  • through() Set the array of pipes.(In our case Status and Sort classes)
  • via() Set the method to call on the pipes.
  • thenReturn() Run the pipeline and return the result.

We successfully implemented pipelines for filtering query. Filter classes can be used for any other Models again. So reuseablity and maintainability is also achieved.Note: this much is enough to understand the use of pipeline in laravel. Section below is optional but fruitful.

Did you notice we have been repeating some lines of code in handle function in both filters.

if(!request()->has('sort')){
            return $next($request);
        }
$builder=$next($request);

So now i will be showing you how to get rid of it as well. Lets create abstract class named Filter inside QueryFilters directory. And make abstract function named applyFilter now this class works as contract since we will be extending this class in our Status and Sort classes.

namespace App\QueryFilters;
use Closure;
use Illuminate\Support\Str;

abstract class Filter
{
    public function handle($request, Closure $next)
    {
        if(empty(request($this->filterName()))){
            return $next($request);
        }
        $builder=$next($request);
        return $this->applyFilter($builder);
    }

    protected abstract function applyFilter($builder);

    protected function filterName(){
        return Str::snake(class_basename($this));
    }
}

filterName() function return name of base class in snake_case form.In our case it returns status and sort. If the class name was SometingElse then it would return something_else. Here you have to be bit careful about naming field name in your view blade file. The field name should match snake_case form of filter class. Now the filter class or pipelines looks like this.

namespace App\QueryFilters;
use Closure;

class Status extends Filter
{
    protected function applyFilter($builder)
    {
        return $builder->where('status',request($this->filterName()));
    }
}
namespace App\QueryFilters;
use Closure;

class Sort extends Filter
{
    protected function applyFilter($builder)
    {
        return $builder->orderBy('created_at',request($this->filterName()));
    }
}

Conclusion

It doesn’t mean this is the only approach to use pipeline in laravel. But I hope this tutorial gave you some information about pipeline and its way of implementation. This approach is specially suitable for complex project but it’s your choice to use it in any kind of project you want.

You can checkout my other blogs and refer to your friends who are planning to start career in web development. Your feedback is always appreciated. Thank you..

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments