When building something in the laravel framework, your application might require filtering query results dynamically based on the user’s request parameters.
This tutorial will demonstrate the process of filtering query results using pipelines while keeping your code clean and readable.
Understanding Laravel Pipeline
Pipeline is a design pattern in OOP specifically designed for handling complex mutation of an object where the object is passed through each task (such as passing a pipe) and returns the final transformed object after executing all tasks.
In other words, the laravel pipeline breaks down the huge complex processes of manipulating objects into smaller individual pieces that are responsible for processing and passing data to the next step. As a result, the code becomes easier to maintain and reusable.
Let’s imagine a situation where we are not aware of pipelines, we would normally consider setting up a controller and filter query using conventional if statement.
class PostController
{
public function index(Request $request)
{
$query = Post::query();
if ($request->has('status')) {
$query->where('status', $request->status);
}
if ($request->has('orderBy')) {
$query->orderBy('created_at, $request->orderBy);
}
// And probably all other filters
$posts = $query->get();
return view('post.index', compact('posts'));
}
}
Although this approach might do the job, this will get messy pretty quickly if you have longer multiple conditions.
Filtering Query using Pipelines
This implementation has a major advantage over the approach previously stated above, its ability to handle an ever-growing number of conditions without compromising the code maintainability.
So, let’s try to refactor the if statement approach mentioned above using pipelines.
First, in order for pipelines to work, we need to create a filter class. So, let’s create a custom filter class inside app/QueryFilters
directory.
Next, Our filter class should have a handle
method that contains the logic to filter the query.
# app/QueryFilters/Status.php
<?php
namespace App\QueryFilters;
class Status
{
public function handle($query, $next)
{
if (request()->has('status')) {
$query->where('status', request('status'));
}
$next($builder);
}
}
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.
Pipeline ships with laravel so you don’t need to install any package. Therefore, we simply import Illuminate\Pipeline\Pipeline
and instantiate using app()
.
use Illuminate\Pipeline\Pipeline;
class PostController
{
public function index(Request $request)
{
$query = Post::query();
$posts = app(Pipeline::class)
->send($query)
->through([
\App\QueryFilters\Status::class,
\App\QueryFilters\OrderBy::class,
])
->thenReturn()
->get();
return view('post.index', compact('posts'));
}
}
- The
send()
method receives the actual object to send through the pipelines.
- The
through()
method receives array of filters (known as pipes).
- The
thenReturn()
method runs the pipeline and returns the result (which will return the inital query object).
Laravel pipeline gives you a very flexible approach to filtering queries. Whether deciding to use it or not depends upon the complexity of your project, but this short tutorial will give you an idea to make good use of pipelines.
I hope this has been informative and gives you an understanding of how to use laravel pipelines. You can check out more about pipelines and how it works at laravel official docs.
How about using $query->when()?
Thanks for the comment. That is also one way to do it but I think it’ll soon get convoluted after it reaches multiple numbers of checks. Hence, Pipeline to the rescue. 🙂
This approach looks clean indeed but I wonder if it will work with the Yajra Datatables package, specially using server-side option, as the solution is returning data with ->get().
I have tto thank yoou forr the efforts you’ve putt inn writing tthis site.
I really hope too see thee same high-grade cntent ftom yoou iin tthe future as well.
In truth, your creawtive writing abilities hhas encouraged
mme to get my very own blog now 😉