Created
October 12, 2024 11:39
-
-
Save sadegh19b/b8fb755b840a52fe2abff40d1de6f1b9 to your computer and use it in GitHub Desktop.
Filament Search Filter
This file contains hidden or 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\Filament\Filters; | |
use Filament\Forms; | |
use Filament\Tables\Filters\BaseFilter; | |
use Illuminate\Database\Eloquent\Builder; | |
use Illuminate\Support\Facades\Lang; | |
use Illuminate\Support\Str; | |
class SearchFilter extends BaseFilter | |
{ | |
protected bool $isRtlInput = true; | |
protected bool $isEncodeUtf8 = false; | |
protected bool $isSanitizeInput = false; | |
protected bool $isConcatColumns = false; | |
protected bool $isLabelWithSearchPrefix = true; | |
protected ?string $indicatorLabel = null; | |
protected ?string $relation = null; | |
protected array $searchColumns = []; | |
protected function setUp(): void | |
{ | |
parent::setUp(); | |
$filterName = strtolower($this->getName()); | |
$this->searchColumns = [$filterName]; | |
if (Str::contains($filterName, '.')) { | |
$this->name(Str::of($filterName)->replace('.', '_')->toString()); | |
$this->relation = Str::of($filterName)->beforeLast('.')->toString(); | |
$this->searchColumns[0] = Str::of($filterName)->afterLast('.')->toString(); | |
} | |
$this->getSetUpForm(); | |
$this->getSetUpQuery(); | |
$this->getSetUpIndicate(); | |
} | |
protected function getSetUpForm(): void | |
{ | |
$inputDirection = $this->isRtlInput ? 'rtl' : 'ltr'; | |
$this->form([ | |
Forms\Components\TextInput::make('value') | |
->label($this->getLabel()) | |
->extraInputAttributes(['dir' => $inputDirection]) | |
->lazy(), | |
]); | |
} | |
protected function getSetUpQuery(): void | |
{ | |
$this->query(fn(Builder $query, array $data) => | |
$query->when( | |
$data['value'], | |
fn(Builder $query, string $input) => (! is_null($this->relation)) | |
? $this->getRelationQuery($query, $input) | |
: $this->getSearchQuery($query, $input) | |
) | |
); | |
} | |
protected function getSetUpIndicate(): void | |
{ | |
$this->indicateUsing( | |
fn($state) => (filled($state['value'] ?? null)) | |
? [sprintf('%s: %s', $this->indicatorLabel, $state['value'])] | |
: [] | |
); | |
} | |
public function rtlInput(bool $condition = true): static | |
{ | |
$this->isRtlInput = $condition; | |
$this->getSetUpForm(); | |
return $this; | |
} | |
public function encodeToUtf8SearchInput(bool $condition = true): static | |
{ | |
$this->isEncodeUtf8 = $condition; | |
return $this; | |
} | |
public function sanitizeSpaceInSearchInput(bool $condition = true): static | |
{ | |
$this->isSanitizeInput = $condition; | |
return $this; | |
} | |
public function concatColumnsInQuery(bool $condition = true): static | |
{ | |
$this->isConcatColumns = $condition; | |
return $this; | |
} | |
public function labelWithSearchPrefix(bool $condition = true): static | |
{ | |
$this->isLabelWithSearchPrefix = $condition; | |
return $this; | |
} | |
public function searchFullName(array $columns = ['first_name', 'last_name']): static | |
{ | |
$this->searchColumns = $columns; | |
$this->isEncodeUtf8 = true; | |
$this->isSanitizeInput = true; | |
$this->isConcatColumns = true; | |
return $this; | |
} | |
public function relation(string $relation): static | |
{ | |
$this->relation = $relation; | |
return $this; | |
} | |
public function queryColumns(array $columns): static | |
{ | |
$this->searchColumns = $columns; | |
return $this; | |
} | |
public function label(string | \Closure | null $label): static | |
{ | |
parent::label($label); | |
$this->getSetUpForm(); | |
$this->getSetUpIndicate(); | |
return $this; | |
} | |
public function getLabel(): string | |
{ | |
$label = $this->evaluate($this->label); | |
if (blank($label)) { | |
$filterName = $this->getName(); | |
$label = Lang::has("filament.labels.{$filterName}") | |
? Lang::get("filament.labels.{$filterName}") | |
: ucwords(Str::of($filterName)->camel()->snake(' ')); | |
} | |
if ($this->shouldTranslateLabel) { | |
$label = __($label); | |
} | |
$this->indicatorLabel = $label; | |
if ($this->isLabelWithSearchPrefix) { | |
$label = Lang::get('filament.commons.search_for') . ' ' . $label; | |
} | |
return $label; | |
} | |
private function getRelationQuery(Builder $query, string $input): Builder | |
{ | |
return $query->whereHas($this->relation, fn(Builder $query) => $this->getSearchQuery($query, $input)); | |
} | |
private function getSearchQuery(Builder $query, string $input): Builder | |
{ | |
if ($this->isSanitizeInput) { | |
$input = str_replace(' ', '%', $input); | |
} | |
if ($this->isEncodeUtf8) { | |
$input = utf8_encode($input); | |
} | |
if (count($this->searchColumns) > 1) { | |
$query->where(function (Builder $query) use ($input) { | |
if ($this->isConcatColumns) { | |
$columns = implode(", ' ', ", $this->searchColumns); | |
return $query->whereRaw("CONCAT({$columns}) LIKE ?", ["%{$input}%"]); | |
} | |
foreach ($this->searchColumns as $column) { | |
$query->orWhere($column, 'LIKE', "%{$input}%"); | |
} | |
return $query; | |
}); | |
} else { | |
$query->where($this->searchColumns[0], 'LIKE', "%{$input}%"); | |
} | |
return $query; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment