Question below. I need a searchable list of a certain resource, so:
$users = User::query()
->when(
value: $this->search,
callback: fn($query) => $query->where('name', 'like', "%$this->search%")
)
->get()
Sometimes you want to search on multiple columns, so:
...
callback: fn($query) => $query->where(fn($query) => $query
->orWhere('name', 'like', "%$this->search%")
->orWhere('email', 'like', "%$this->search%")
->orWhere('nickname', 'like', "%$this->search%")
...
Hey let’s pull that logic into a reusable method:
public function searchable(array $columns):array
{
return [
$this->search,
fn($query) => $query->where(function ($query) use ($columns) {
foreach ( $columns as $column ) {
$query->orWhere($column, 'like', "%$this->search%");
}
})
];
}
...
$users = User::query()
->when(...$this->searchable([
'name',
'email',
'nickname',
]))
->get()
This code works beautifully in testing. My problem is, I need to tell PHPStan what I’m doing. (I’ve gotten pretty good at PHPStan in the last 2 months, but this is stumping me.) Here’s the furthest I’ve gotten:
use IlluminateDatabaseEloquentBuilder;
use IlluminateDatabaseEloquentModel;
use IlluminateDatabaseEloquentRelationsHasMany;
/**
* @template TModel of Model
* @template TBuilder of Builder<TModel>|HasMany<TModel>
*
* @param list<string> $columns
* @return array{
* 0:string,
* 1:callable(TBuilder):TBuilder|void
* }
*/
public function searchable(array $columns):array
PHPStan says:
Parameter #2 $callback of method IlluminateDatabaseEloquentBuilder<AppModelsUser>::when() expects
(callable(IlluminateDatabaseEloquentBuilder<AppModelsUser>,
callable(IlluminateDatabaseEloquentBuilder<IlluminateDatabaseEloquentModel>|IlluminateDatabaseEloquentRelationsHasMany<IlluminateDatabaseEloquentModel>):
(IlluminateDatabaseEloquentBuilder<IlluminateDatabaseEloquentModel>|IlluminateDatabaseEloquentRelationsHasMany<IlluminateDatabaseEloquentModel>)|string|void):
mixed)|null,
(callable(IlluminateDatabaseEloquentBuilder<IlluminateDatabaseEloquentModel>|IlluminateDatabaseEloquentRelationsHasMany<IlluminateDatabaseEloquentModel>):
(IlluminateDatabaseEloquentBuilder<IlluminateDatabaseEloquentModel>|IlluminateDatabaseEloquentRelationsHasMany<IlluminateDatabaseEloquentModel>))|void
given.
💡 Type #1 from the union: Template type TModelClass on class IlluminateDatabaseEloquentBuilder is not covariant. Learn more:
https://phpstan.org/blog/whats-up-with-template-covariant
Please, any help? TIA