-
Notifications
You must be signed in to change notification settings - Fork 11.7k
[10.x] Add whereAll and whereAny methods to the query builder
#50344
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[10.x] Add whereAll and whereAny methods to the query builder
#50344
Conversation
|
Thanks for submitting a PR! Note that draft PR's are not reviewed. If you would like a review, please mark your pull request as ready for review in the GitHub user interface. Pull requests that are abandoned in draft may be closed due to inactivity. |
whereMultiple method to the query builderwhereMultiple method to the query builder
|
Damn, I didn't know I needed this until today |
|
I love how this simplified the nested query. |
|
Yesterday this test Just want to make sure everything is ok 😅 |
|
For me it wasn't obvious by the name that the default value of How about instead of only one method, split it into four methods? That would allow you to simplify the signature greatly and also make the naming more obvious. My suggestion: whereAll($columns, $operator = null, $value = null); // same as: $columnsBoolean = 'and', $boolean = 'and'
orWhereAll($columns, $operator = null, $value = null); // same as: $columnsBoolean = 'and', $boolean = 'or'whereAny($columns, $operator = null, $value = null); // same as: $columnsBoolean = 'or', $boolean = 'and'
orWhereAny($columns, $operator = null, $value = null); // same as: $columnsBoolean = 'or', $boolean = 'or'IMO this would also match the pattern of the existing methods |
|
@johanrosenson oh, yes, you're right, it looks better and more intuitive 🤝 thanks for the idea. I'm working on it soon 🙃 |
whereMultiple method to the query builderwhereAll and whereAny methods to the query builder
|
I've split Also changed the visibility of the old method If I delete the old method, each new method will have something like that: Any ideas? 🤔 |
If this was my code I would have been ok with some duplication to make it easier to understand each method, I would have used your code above in Then there would be no need for the private |
|
Thanks for your help! 🫡 Now there are only 4 methods ( |
|
Time to remove whereLike macro 👀 |
|
In my case, you need to fix the keyboard layout in case the user didn't. Before Laravel 10.47class BuilderServiceProvider extends ServiceProvider
{
public function boot(): void
{
$this->bootWhereLike();
$this->bootOrWhereLike();
$this->bootOrWhereLikeColumns();
}
protected function bootWhereLike(): void
{
Builder::macro('whereLike', function (string $column, int | string $value, string $operator = 'and') {
$column = DB::raw("lower($column::text)");
$cyrillic = is_numeric($value) ? $value : Keyboard::toCyrillic($value);
$latin = is_numeric($value) ? $value : Keyboard::toLatin($value);
return $this->where(
column: fn(Builder $query) => $query
->when(
$cyrillic === $latin,
fn(Builder $query) => $query
->where($column, 'like', "%$cyrillic%")
->when(
$cyrillic !== $value,
fn(Builder $query) => $query
->orWhere($column, 'like', "%$value%")
),
fn(Builder $query) => $query
->where($column, 'like', "%$cyrillic%")
->orWhere($column, 'like', "%$latin%")
->when(
!in_array($value, [$cyrillic, $latin], true),
fn(Builder $query) => $query
->orWhere($column, 'like', "%$value%")
),
),
boolean: $operator
);
});
}
protected function bootOrWhereLike(): void
{
Builder::macro('orWhereLike', function (string $column, int | string $value) {
return $this->whereLike($column, $value, 'or');
});
}
protected function bootOrWhereLikeColumns(): void
{
Builder::macro('orWhereLikeColumns', function (array $columns, int | string $value) {
return $this->where(function (Builder $query) use ($columns, $value) {
foreach ($columns as $column) {
$query->orWhereLike($column, $value);
}
return $query;
});
});
}
}Laravel 10.47+class BuilderServiceProvider extends ServiceProvider
{
public function boot(): void
{
$this->whereLikeColumns();
}
protected function whereLikeColumns(): void
{
Builder::macro('whereLikeColumns', function (array | string $columns, int | string $value) {
$columns = collect(Arr::wrap($columns))->map(
fn(string $column) => DB::raw("lower($column::text)")
)->all();
$cyrillic = is_numeric($value) ? $value : Keyboard::toCyrillic($value);
$latin = is_numeric($value) ? $value : Keyboard::toLatin($value);
return $this->where(function (Builder $query) use ($columns, $value, $cyrillic, $latin) {
foreach (array_unique([$value, $cyrillic, $latin]) as $search) {
$query->orWhereAny($columns, 'LIKE', "%$search%");
}
});
});
}
}That said, they are used in almost the same way: // < 10.47
SomeModel::query()
->when(
$data->query,
fn (Builder $builder, int | string $query) => $builder->orWhereLikeColumns(['id', 'title'], $query)
)
// 10.47+
SomeModel::query()
->when(
$data->query,
fn (Builder $builder, int | string $query) => $builder->whereLikeColumns(['id', 'title'], $query)
) |
|
I don't get it for Is there a difference between this snippet using User::whereAll([
'first_name',
'last_name',
'email',
], 'LIKE', "%$search%")and this snippet using plain User::where([
['first_name', 'LIKE', "%$search%"],
['last_name', 'LIKE', "%$search%"],
['email', 'LIKE', "%$search%"],
])I mean, why should I learn a new command, when I can do the same thing with an existing command? |
In your second snippet I think you would also need to wrap those comparison arrays in a parent array? With this PR, it isn't necessary as the columns are already grouped. Nice addition IMO. I can see it being used a lot. |
|
You are right. I edited the snipped. |
Williamug
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So cool 🔥 🔥
Hi,
Sometimes I need to make a search input on some pages where one value is compared with multiple columns. For example, an admin needs to able to search users by first name, last name, email or phone. Usually I wrap
orWherein anotherwhereas a closure:We can create a scope 'search' or something, but it's anyway a lot of
whereinwhere, so I always wanted something like that:The method has these params:
$columnsBooleanis the boolean type between passed columns:The method creates a closure and
wherefor each passed column withororand. It looks like:I haven't found something similar, except putting an array in
where, but this is not the same. I hope I didn't miss the same functionality. If I did, please let me knowIt's my first PR, so if something is wrong or you just have any questions, let me know
Thanks,
Alex
Updates
whereMultiplehas been split intowhereAllandwhereAny.whereAll
Creates a nested query that uses the same operator and value for each column passed in, where ALL columns must match the value and operator.
Params:
Usage:
All columns has the same operator
LIKEand the same value"%test%", and they haveANDbetween each column:whereAny
Creates a nested query that uses the same operator and value for each column passed in, where ANY of the columns must match the value and operator.
Params:
Usage:
All columns has the same operator
LIKEand the same value"%test%", and they haveORbetween each column: