-
Notifications
You must be signed in to change notification settings - Fork 11.1k
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
[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. |
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
orWhere
in anotherwhere
as a closure:We can create a scope 'search' or something, but it's anyway a lot of
where
inwhere
, so I always wanted something like that:The method has these params:
$columnsBoolean
is the boolean type between passed columns:The method creates a closure and
where
for each passed column withor
orand
. 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
whereMultiple
has been split intowhereAll
andwhereAny
.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
LIKE
and the same value"%test%"
, and they haveAND
between 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
LIKE
and the same value"%test%"
, and they haveOR
between each column: