I'm trying to show a list of models. Having a text filter posed no problem but when trying to add a year filter, problems started occurring.
If a non-numeric value is sent back from the from
or to
input, I expected validation to catch it and just flash some errors to the session but instead I still get SQL errors because either from
or to
were not numeric (for example: invalid input syntax for integer: "2020a" (SQL: select * f rom "my_models" where "year" between 2020a and 2021)
)
Livewire Component code
class ModelList extends Component
{
use WithPagination;
public $from;
public $to;
public $search;
protected $models;
protected $rules = [
'from' => ['required', 'integer', 'between:1970,2021'],
'to' => ['required', 'integer', 'between:1970,2021'],
'search' => ['nullable', 'string'],
];
public function mount()
{
$this->from = (int) date('Y') - 10;
$this->to = (int) date('Y');
$this->search = null;
$this->doQuery();
}
public function updating($name, $value)
{
$this->validate();
$this->doQuery();
$this->resetPage();
}
public function render()
{
return view('livewire.list', ['models' => $this->models]);
}
protected function doQuery()
{
$this->models = MyModel::query()
->whereBetween('year', [$this->from, $this->to])
->search($this->search)
->orderByDesc('year')
->paginate(10);
}
}
View
<div>
<div id="filters" class="flex flex-col text-gray-800">
<div>
<input type="number" wire:model.lazy="from" min="1970" max="{{ date('Y') }}">
@error('from')
<span class="text-red-800">{{ $message }}</span>
@enderror
</div>
<div>
<input type="number" wire:model.lazy="to" min="1970" max="{{ date('Y') }}">
@error('to')
<span class="text-red-800">{{ $message }}</span>
@enderror
</div>
<div>
<input type="text" wire:model.lazy="search">
@error('search')
<span class="text-red-800">{{ $message }}</span>
@enderror
</div>
</div>
<div id="list">
@foreach ($models as $model)
{{ $model->id }}<br>
@endforeach
</div>
<div id="pagination">
{{ $models->links() }}
</div>
</div>
I've tried different things like
- just doing the query inside the
render()
method, inlining the doQuery()
method.
- just doing the query inside
updating()
method.
- just doing the query inside
mount()
method.
- doing the query inside both
updating()
, mount()
, and render()
methods.
- calling
$this->validate()
inside render()
but none of the above seem to work with bad input. Sometimes $models
gets unset and I get an error for calling the links()
method on it. If that doesn't happen, then I get an SQL error because the bad input went right through the validation.
I know I could use a select input or add some javascript to prevent non-numeric values but that doesn't fix the underlying issue of not being able to trust Livewire to validate my input. (And it only takes opening the console and writing a couple of lines to completely invalidate such flimsy validation.)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…