Skip to content

Latest commit

 

History

History
84 lines (71 loc) · 2.54 KB

searching-multiple-columns.md

File metadata and controls

84 lines (71 loc) · 2.54 KB

Searching multiple columns

In laravel we can make macro for searching model by using multiple columns.

Using eloquent we can do this:

User::query()
   ->where('name', 'LIKE', "%{$searchTerm}%")
   ->orWhere('email', 'LIKE', "%{$searchTerm}%")
   ->get();

Instead we can build macro for searching in multiple columns:

Builder::macro('search', function ($attributes, string $searchTerm) {
    $this->where(function (Builder $query) use ($attributes, $searchTerm) {
        foreach (array_wrap($attributes) as $attribute) {
            $query->orWhere($attribute, 'LIKE', "%{$searchTerm}%");
        }
    });

    return $this;
});

Now we can do this:

// searching a single column
User::whereLike('name', $searchTerm)->get();

// searching multiple columns in one go
User::whereLike(['name', 'email'], $searchTerm)->get();

If we want a support for relations (ex. category.name):

Builder::macro('search', function ($attributes, string $searchTerm) {
    $this->where(function (Builder $query) use ($attributes, $searchTerm) {
        foreach (array_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;
});

With this macro, we can search like this:

Post::whereLike(['name', 'description', 'category.name'], $searchTerm)->get();

We can also allow for wildcard searches (ex. %jon, john%):

Builder::macro('search', function ($attributes, $terms) {
    $this->where(function (Builder $query) use ($attributes, $terms) {
        foreach (array_wrap($attributes) as $attribute) {
            foreach (array_wrap($terms) as $term) {
                /*** allow arbitrary patterns by not forcing % wildcard chars around the term(s) ***/
                $query->orWhere($attribute, 'LIKE', $term);
            }
        }
    });

    return $this;
});

With this macro we can search like this:

User::search('name', ['john%', 'jon%', 'jone%']);