⌘K

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á:

  1. Plánovač dotazu — výchozí cesta pro jednu skalární hodnotu. Tabulka přečte sloupec a hodnotu filtru a napíše column = value sama. apply() se nezavolá.
  2. 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();
}
}