Pipeline Pattern in Laravel
Tags: laravel, php, pipeline, pattern
Published: 2021-08-07 13:41:07

> PP = Pipeline Pattern

Today, we will learn the Pipeline Pattern and how to use it in Laravel. You can read in depth about PP at [HERE](https://www.cise.ufl.edu/research/ParallelPatterns/PatternLanguage/AlgorithmStructure/Pipeline.htm). PP can be implemented differently in any language but we'll be seeing in PHP [Laravel](laravel.com) as Laravel already using this pattern at it's [core](https://github.com/laravel/framework/blob/dc393980dec1b3ee4b0f36b5b0188859a399b4e4/src/Illuminate/Foundation/Http/Kernel.php#L138). 

## What is Pipeline Pattern

![Pipeline Pattern](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7ek7dushwcdbxh03h7m.png)

> Pipeline is a design pattern specifically optimized to handle stepped changes to an object. Think of an assembly line, where each step is a pipe and by the end of the line, you have your transformed object.

There are vast implementations of PP but to understand easily let's implement a filtering functionality using the pipeline pattern and Laravel. 

## Example
Let's say we are building filtering system in Laravel, we can filter Post by different parameters like is active or not, sort by ASC or DESC. 

## Before Implementing PP. 

### PostController.php 
In the `index` method, we are performing filters. 
```
public function index(Request $request)
    {
        $query = Post::query();

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

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

        /* get filtered data */
        $posts = $query->get();

        return view('demo', compact('posts'));
    }
```

## Let's convert this mess into beautiful filter pipeline.

### PostController.php
To implement Pipeline pattern, we need to make little refactoring. `Index` method will looks like below 

```
public function index(Request $request)
    {
     $posts = app(Pipeline::class)
            ->send(Post::query())
            ->through([
                \App\Filters\Active::class,
                \App\Filters\Sort::class
            ])
            ->thenReturn()
            ->get();

     return view('demo', compact('posts'));
    }
```
*`send()` method will pass your query to handle method
*`through()` method get the parameter as classes to pass through them. In simple words this is the list of filter classes
*`thenReturn()` will return the final output
It's all provided by Laravel except we need to create Filter classes which being passed in `through()` method. 

### Active class
Create Active class under app/Filters namespace. 
```
namespace App\Filters;

use Closure;

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

        return $next($request)->where('active', request()->input('active'));
    }
}
```

### Sort class
Create Active class under app/Filters namespace. 
```
namespace App\Filters;

use Closure;

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

        return $next($request)->orderBy('title', $request->input('sort'));
    }
}
```

### That's it. 
Now if I want to add an other filter, I need to make new class let's say `Published` and this class in `through()` method and implement filter logic in class `handle` method. 

## Conclusion
It might feel overwhelm to implement Pipelines just for two filters but it will be much clean and beneficial for large number of filter or any other complex implementation. 

## Cleaning Filter Classes
PS: We can clean filter classes by extracting common code in base class. Comment below if you want refactoring of Filter classes in next article. 
Until next, 
Ahmad