Filters in Laravel with OOP Practices
Basically, to implement the resource filter API, we check the query parameters from the existing request and apply the corresponding query bindings (where clause) to our Model
.
The normal way to implement the filter criteria seems like:
This approach of returning filtered data would be applicable for small-sized applications only. If the application is booted with heavy sets of filter logic then we would have to add recurring IF
logic in the controller itself. This makes our controller very bulky.
Now let's implement some OOP principles to extract and encapsulate the logic to its own separate classes.
- First, we create an abstract class named
BaseFilter
. We then add aapply()
method with some logic inside it as shown below. We shall discuss its working mechanism later in this blog.
2. Create a separate filter class for integrating filter logic for a resource that extends the BaseFilter
class. Before we had included the filter logic using nested IFs
in the Controller
class but now we extract them into individual methods.
Things to remember:
- The name of the method must be the key of the query parameters of the URL.
- The method name must be written in
camelCase
. - For eg, if the URL is
some-url?ward=20&municipality=2
and we have to filter the resource by ward and municipality, then we need to create two methods namingward()
andmunicipality()
respectively.
3. We then add a local scope
in the Model
class. This method accepts an instance of Eloquent Builder
as a first parameter and sets of filters
as the second parameter. It simply instantiates the FilterClass
which we had defined before in Step 2
and calls itsapply()
method.
4. Lastly, we can simply call the filterBy
scope of our Model
class and pass all the query parameters as its arguments.
What is happening behind the scene?
- First, in the controller class, we are returning the resource by binding the local scope to our builder
(filterBy)
which we had created in the model class. As a parameter, we pass the array of query parameters usingrequest()->all()
. - The
filterBy
scope then instantiate theFilterClass
and calls itsapply()
method. Keep in mind that, when we instantiate theFilterClass
, we need to pass the instance of query builder and the previous array of query parameters for the filters. - The filter class that we had created extends the
BaseFilter
class. It includes individual methods where the logic for the filter is written. - The
apply()
method of theBaseFilter
class is built in such a way that it iterates over every query parameter from the current URL and calls the filter method defined in its subclasses. - These methods are later responsible for binding the where clause in the Eloquent builder.
Wow, there it is. A neat and clean way to create a filter API for any resource. If you have to implement similar logic for any other Entity, simply create a new Filter class that extends the BaseFilter
class and add a local scope to its related Model
class.