Tabulka
Vlastní třída filtru
Rozšíření základní třídy filtru: vlastní ovládací prvek, vlastní dotaz, použitelné napříč tabulkami.
Na této stránce
Pro znovupoužitelné, složité filtry rozšiřte základní třídu Filter.
Jak to funguje
Tabulka zužuje dotaz jednou ze dvou cest a to, kterou filtr půjde, rozhoduje,
zda se vaše apply() vůbec zavolá:
- Plánovač dotazu — výchozí cesta pro jednu skalární hodnotu. Tabulka
přečte sloupec a hodnotu filtru a napíše
column = valuesama.apply()se nezavolá. apply()— použije se, když má filtr callback->query(), když je jeho hodnota pole a filtr není->multiple(), nebo kdyžbypassesPlanner()vrátítrue.
Filtr, který přepisuje apply() a odesílá jednu hodnotu, proto musí z
bypassesPlanner() vracet true, jinak za něj potichu odpoví plánovač. Před
oběma cestami platí, že hodnota null, '' nebo [] znamená vypnutý filtr a
přeskočí se.
Ovládací prvek kreslí render($value). Základní implementace vykreslí
filterView() a hledá ho nejdřív pod wire-table::, takže pohled pojmenovaný
jako dodávaný (tables.filters.select) nakreslí dodávaný prvek. Vykreslete svůj
pohled přímo jménem, jako kostra níže, a jméno se nemůže srazit.
Vygenerování
php artisan make:wire-filter Region
zapíše app/Tables/Filters/RegionFilter.php a
resources/views/tables/filters/region.blade.php: třída přepisuje apply(),
bypassesPlanner() a render() a pohled váže textové pole na
tableState.filters.region.value. Existující pohled se nikdy nepřepíše;
--force nahradí jen třídu. php artisan vendor:publish --tag=wire-table::stubs
zkopíruje filter.stub a filter-view.stub do stubs/wire-table/ a příkaz je
odtud čte přednostně.
Kostra
namespace App\Wire\Filters; use NyonCode\WireTable\Filters\Filter;use Illuminate\Database\Eloquent\Builder; class MyFilter extends Filter{ // Vlastní vlastnosti protected string $myOption = 'default'; // Fluent setter public function myOption(string $value): static { $this->myOption = $value; return $this; } // Getter (pro Blade pohled) public function getMyOption(): string { return $this->myOption; } // Přepsat apply logiku public function apply(Builder $query, mixed $value): Builder { if (empty($value)) { return $query; } // Vaše vlastní logika dotazu return $query->where(...); } // Jedna hodnota jde přes apply(), ne přes plánovač dotazu public function bypassesPlanner(): bool { return true; } // Vlastní Blade pohled (volitelné) — přepište render() a nasměrujte na svůj pohled. // Pohled dostane 'filter' (tuto instanci) a 'value' (aktuální stav). public function render(mixed $value = null): string { if (! $this->canView()) { return ''; } return view('filters.my-filter', ['filter' => $this, 'value' => $value])->render(); }}
Příklad: Filtr JSON Contains
namespace App\Wire\Filters; use NyonCode\WireTable\Filters\SelectFilter;use Illuminate\Database\Eloquent\Builder; // Rozšiřuje SelectFilter, takže dědí ->options()/->searchable()/->native().class JsonContainsFilter extends SelectFilter{ protected string $jsonPath = ''; public function jsonPath(string $path): static { $this->jsonPath = $path; return $this; } public function apply(Builder $query, mixed $value): Builder { if (empty($value)) { return $query; } $column = $this->getColumn(); if ($this->jsonPath) { return $query->whereJsonContains("{$column}->{$this->jsonPath}", $value); } return $query->whereJsonContains($column, $value); } // Jedna vybraná možnost je skalár, na který by odpověděl plánovač public function bypassesPlanner(): bool { return true; } }
Použití:
JsonContainsFilter::make('permissions') ->column('settings') ->jsonPath('permissions') ->options(['admin' => 'Admin', 'edit' => 'Edit', 'view' => 'View'])
Příklad: Filtr geo poloměru
namespace App\Wire\Filters; use NyonCode\WireTable\Filters\Filter;use Illuminate\Database\Eloquent\Builder; class GeoRadiusFilter extends Filter{ protected float $defaultRadius = 10.0; protected string $latColumn = 'latitude'; protected string $lngColumn = 'longitude'; public function radius(float $km): static { $this->defaultRadius = $km; return $this; } public function coordinates(string $lat, string $lng): static { $this->latColumn = $lat; $this->lngColumn = $lng; return $this; } public function apply(Builder $query, mixed $value): Builder { if (empty($value['lat']) || empty($value['lng'])) { return $query; } $lat = (float) $value['lat']; $lng = (float) $value['lng']; $radius = (float) ($value['radius'] ?? $this->defaultRadius); // Haversinův vzorec (vrací km) $haversine = "(6371 * acos( cos(radians(?)) * cos(radians({$this->latColumn})) * cos(radians({$this->lngColumn}) - radians(?)) + sin(radians(?)) * sin(radians({$this->latColumn})) ))"; return $query ->whereRaw("{$haversine} <= ?", [$lat, $lng, $lat, $radius]); } public function getDefaultRadius(): float { return $this->defaultRadius; } public function render(mixed $value = null): string { if (! $this->canView()) { return ''; } return view('filters.geo-radius', ['filter' => $this, 'value' => $value])->render(); }}