Laravel Pipeline Interpretation with Example

Hey Artisan,

Today we learn about pipeline design pattern. 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.

Larval uses the Pipeline Design Pattern in a couple of places throughout the framework. This means everything we need to implement this pattern is already part of the foundation of your application!

In today’s tutorial we will be looking at the Pipeline Design Pattern and how we can filter data using laravel pipeline, in this tutorial we are going to see that.

laravel-pipeline-example

What is the Pipeline Design Pattern?

The Pipeline Design Pattern is where a complex process is broken down into individual tasks. Each individual task is reusable and so the tasks can be composed into complex processes.

This allows you to break up monolithic processes into smaller tasks that process data and then pass that data to the next step.

Each task within the pipeline should receive and emit the same type of data. This allows tasks to be added, removed, or replaced from the pipeline without disturbing the other tasks.

You can check the original code of pipeline class from Laravel git repository. Just open this below link, you will find original code of Laravel pipeline class.

Now let's start our tutorial. In this tutorial we will create a post table, and filter them using active or inactive, asc or desc or will filter them order by title or name. That mean we are going to filter data using Laravel pipeline. Let's see.

 

Step 1 :  Create Route

Now we have to create a route to return our data, so create it.

Route::get('post','[email protected]index');

 

Step 2 :  Create Post Model

To create Post model, paste this code.

php artisan make:model Post -fm

 

Now open our newly created database table and  paste this following code.

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreatePostsTable extends Migration
{
    
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('title');
            $table->unsignedBigInteger('active')->comment('active or inactive');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}

 

Step 3: Generate some dummy data

To generate some dummy data, open PostFactory and paste below code

database/factories/PostFactory.php


/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Post;
use Faker\Generator as Faker;

$factory->define(Post::class, function (Faker $faker) {
    return [
        'title' => $faker->sentence,
        'active' => random_int(0,1)
    ];
});

 

and then run below command to generate fake data using faker.

php artisan tinker
//and then
factory(\App\Post::class,5)->create()
exit

 

Step 4:  Add Controller Method

Now at last we have to add new controller method index() in your Home Controller. So let's add index() method on HomeController.php file.

app/Http/Controllers/FilterController.php


namespace App\Http\Controllers;

use App\Post;

class FilterController extends Controller
{
    
    public function index()
    {
        $posts = Post::allPost();

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

}

 

Step 5:  Setup Model

Now open Post model, and paste this following code.

app/Post.php


namespace App;

use Illuminate\Pipeline\Pipeline;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    public static function allPost()
    {
       $posts = app(Pipeline::class)
                ->send(\App\Post::query())
                ->through([
                    \App\QueryFilters\Active::class,
                    \App\QueryFilters\Sort::class,
                    \App\QueryFilters\MaxCount::class,
                ])
                ->thenReturn()
                ->paginate(2);
        return $posts;
    }
}

 

If you see the pipeline class source code which i mentioned link above, you will understand clearly what is happening here. Pipeline class define some classes like, you pass in the object that you want to send through the pipeline:

$pipeline->send($request); 

 

 Next you pass an array of tasks that should accept and process the request:

$pipeline->through($middleware);  

 

Finally you run the pipeline with a destination callback:

$pipeline->then(function ($request) {  
// Do something  
});  

 

it also uses this below method which i used my code above.

/**
     * Run the pipeline and return the result.
     *
     * @return mixed
     */
    public function thenReturn()
    {
       //
    }

 

Now we have to create our own custom class to filter our database data.

app/QueryFilters/Filter.php

namespace App\QueryFilters;

use Closure;
use Illuminate\Support\Str;

abstract class Filter 
{
    public function handle($request, Closure $next)
    {  
        
        if( ! request()->has($this->filterName())){
            return $next($request);
        }

        $builder = $next($request);

        return $this->applyFilters($builder);
    }

    protected abstract function applyFilters($builder);

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

 

app/QueryFilters/Active.php

namespace App\QueryFilters;

class Active extends Filter
{

    protected function applyFilters($builder)
    {
        return $builder->where('active',request($this->filterName()));
    }

}

 

app/QueryFilters/Sort.php


namespace App\QueryFilters;

class Sort extends Filter
{

    protected function applyFilters($builder)
    {
       return $builder->orderBy('title',request($this->filterName()));
    }

}

 

app/QueryFilters/MaxCount.php


namespace App\QueryFilters;

class MaxCount extends Filter
{

    protected function applyFilters($builder)
    {
       return $builder->take(request($this->filterName()));
    }

}

 

Now if you visit this url, you will find our filter data

 

http://127.0.0.1:8000/post?active=1&sort=desc&max_count=1

Now you should the below output. Here we can see our all active post with descending order. make sure that paginate and max_count can not work together.

If you get data from model without out using paginate method then max_count also work for filtering. See below code to understand. Hope you will understand.

$posts = app(Pipeline::class)
                ->send(\App\Post::query())
                ->through([
                    \App\QueryFilters\Active::class,
                    \App\QueryFilters\Sort::class,
                    \App\QueryFilters\MaxCount::class,
                ])
                ->thenReturn()
                ->paginate(2); //just change here like below code


$posts = app(Pipeline::class)
                ->send(\App\Post::query())
                ->through([
                    \App\QueryFilters\Active::class,
                    \App\QueryFilters\Sort::class,
                    \App\QueryFilters\MaxCount::class,
                ])
                ->thenReturn()
                ->get();

laravel-pipeline-tutorial-with-example

 

http://127.0.0.1:8000/post?active=0&sort=desc&max_count=1

 

pipeline-design-pattern-example

Now you should the below output. Here we can see our all inactive post with descending order.

 

Step 6 : Create View File

Now paste this following code to this post.blade.php file.

resources/views/post.blade.php

 

Laravel makes good use of this design pattern internally in the framework. But you can use Laravel’s Pipeline functionality for your own projects.

In next week’s tutorial we’re going to be looking at how you can use the Pipeline functionality to deal with complex processes. Hope it can help you to gather new knowledge.