Last active
November 16, 2022 09:24
-
-
Save ambengers/473dbba54ae94c96df998b8f01b6860d to your computer and use it in GitHub Desktop.
A trait for performing search on Eloquent model columns and related tables.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Filters\Concerns; | |
use Illuminate\Database\Eloquent\Builder; | |
use Illuminate\Database\Eloquent\Relations\MorphTo; | |
trait SearchesEloquent | |
{ | |
protected $query; | |
/** | |
* Apply the scope to a given Eloquent query query. | |
* | |
* @param \Illuminate\Database\Eloquent\Builder $query | |
* @param string|null $value | |
* @return void | |
*/ | |
public function apply(Builder $query, $value = null) : void | |
{ | |
$this->query = $query; | |
$this->search($value); | |
} | |
/** | |
* Perform a search from query string. | |
* | |
* @param string $text | |
* @return Illuminate\Database\Eloquent\Builder | |
*/ | |
protected function search($text = null) | |
{ | |
if (! $text || ! $this->columns) { | |
return $this->query; | |
} | |
$this->query->where(function ($query) use ($text) { | |
// Since we have a search filter, let's spin | |
// through our list of searchable columns | |
$this->performSearch($query, $text); | |
}); | |
return $this->query; | |
} | |
/** | |
* Iterate through searchable columns. | |
* | |
* @param Illuminate\Database\Eloquent\Builder $query | |
* @param string $text | |
* @return void | |
*/ | |
protected function performSearch(Builder $builder, $text) | |
{ | |
foreach ($this->columns as $attribute => $value) { | |
// If the value is an array, that means we want to search through a relationship. | |
// We need to make sure that we send through the closure's query instance so we | |
// can have an 'AND' query with nested queries wrapped within a parenthesis. | |
is_array($value) | |
? $this->performRelationSearch($builder, $attribute, $value, $text) | |
: $this->performColumnSearch($builder, $value, $text); | |
} | |
return $builder; | |
} | |
/** | |
* Peform search on model columns | |
* | |
* @param Illuminate\Contracts\Database\Eloquent\Builder $builder | |
* @param string|array $column | |
* @param string $text | |
* @return Illuminate\Contracts\Database\Eloquent\Builder | |
*/ | |
protected function performColumnSearch(Builder $builder, $column, $text) | |
{ | |
$builder->orWhere(function ($query) use ($column, $text) { | |
foreach (explode(' ', $text) as $word) { | |
$query->where($column, 'like', "{$word}%"); | |
} | |
}); | |
return $builder; | |
} | |
/** | |
* Search through related tables. | |
* | |
* @param Illuminate\Database\Eloquent\Builder $builder | |
* @param string $related | |
* @param array|string $columns | |
* @param string $text | |
* @return Illuminate\Database\Eloquent\Builder | |
*/ | |
protected function performRelationSearch(Builder $builder, $related, $columns, $text) | |
{ | |
$columns = is_array($columns) ? $columns : [$columns]; | |
$callback = function ($query) use ($columns, $text) { | |
// Here, we want to make sure that we are grouping our orWhere | |
// statement inside a where statement if incase the | |
// relatonship is also running query scopes | |
$query->where(function ($query) use ($columns, $text) { | |
foreach ($columns as $attribute => $value) { | |
is_array($value) | |
? $this->performRelationSearch($query, $attribute, $value, $text) | |
: $this->performColumnSearch($query, $value, $text); | |
} | |
}); | |
}; | |
return ($builder->getModel()->$related() instanceof MorphTo) | |
? $builder->orWhereHasMorph($related, '*', $callback) | |
: $builder->orWhereHas($related, $callback); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment