Demystifying Laravel Code: Adding Search Filters with Builder::macro

·

3 min read

Demystifying Laravel Code: Adding Search Filters with Builder::macro

If you’re new to Laravel and find this code a bit daunting, don’t worry! We’ll break it down into simple parts to help you understand what’s going on. This code snippet is used in Laravel, a popular PHP web application framework, to add search filters to database queries. Let’s dive in.

Builder::macro('searchFilters', function ($attributes, string $searchTerm) {
    $this->where(function (Builder $query) use ($attributes, $searchTerm) {
        foreach (Arr::wrap($attributes) as $attribute) {
            $query->when(
                str_contains($attribute, '.'),
                function (Builder $query) use ($attribute, $searchTerm) {
                    [$relationName, $relationAttribute] = explode('.', $attribute);

                    $query->orWhereHas($relationName, function (Builder $query) use ($relationAttribute, $searchTerm) {
                        $query->where($relationAttribute, 'LIKE', "%{$searchTerm}%");
                    });
                },
                function (Builder $query) use ($attribute, $searchTerm) {
                    $query->orWhere($attribute, 'LIKE', "%{$searchTerm}%");
                }
            );
        }
    });
    return $this;
});

The Builder::macro Method

In Laravel, a “macro” is a way to add custom methods to classes. In this case, we are adding a custom method called searchFilters to Laravel’s query builder (`Builder`) class.

Builder::macro('searchFilters', function ($attributes, string $searchTerm) {
    // ... code ...
    return $this;
});

Parameters

  • $attributes: This is an array or a single attribute that you want to search in.

  • $searchTerm: The term you want to search for in the database.

The where Method

Inside the searchFilters method, you see a where method being used. This method is used to build conditions for a database query.

$this->where(function (Builder $query) use ($attributes, $searchTerm) {
    // ... code ...
});

Anonymous Function

Inside the where method, we are defining an anonymous function (a function without a name). This function takes a $query parameter, which represents the query builder instance.

Looping Through Attributes

Now, let’s look at what happens inside the anonymous function. We have a loop that goes through the provided attributes.

foreach (Arr::wrap($attributes) as $attribute) {
    // ... code ...
}

Arr::wrap

The Arr::wrap method is used to ensure that $attributes is treated as an array, even if it’s a single value. This makes it easier to handle both single attributes and arrays of attributes consistently.

Checking for Relationships

Inside the loop, we check if an attribute contains a dot (`.`). If it does, it means we are dealing with a relationship in the database.

$query->when(
    str_contains($attribute, '.'),
    function (Builder $query) use ($attribute, $searchTerm) {
        // Code for relationships
    },
    function (Builder $query) use ($attribute, $searchTerm) {
        // Code for regular attributes
    }
);

str_contains

The str_contains function checks if the attribute contains a dot, indicating a relationship. If it does, we handle relationships; otherwise, we handle regular attributes.

Handling Relationships

If we are dealing with a relationship, we split the attribute into two parts: the relationship name and the attribute within the relationship.

[$relationName, $relationAttribute] = explode('.', $attribute);

Then, we use orWhereHas to create a condition for searching within that relationship.

$query->orWhereHas($relationName, function (Builder $query) use ($relationAttribute, $searchTerm) {
    $query->where($relationAttribute, 'LIKE', "%{$searchTerm}%");
});

Here, we are searching for records where the $relationAttribute matches the $searchTerm within the $relationName relationship.

Handling Regular Attributes

If we are dealing with a regular attribute (no dot in the name), we use a simple orWhere clause to create a search condition.

$query->orWhere($attribute, 'LIKE', "%{$searchTerm}%");

This code searches for records where the $attribute matches the $searchTerm.

Returning the Query Builder

Finally, after adding all these conditions, we return the modified query builder `$this` to allow for further chaining of query builder methods.

In a nutshell, this code allows you to easily add search filters to your database queries in Laravel. It handles both regular attributes and relationships, making your search functionality flexible and powerful. As you become more familiar with Laravel, you’ll find these kinds of code snippets incredibly useful for building dynamic applications.