whereAny() and whereAll(): Searching Multiple Columns Without Repeating orWhere
You've written this query a hundred times: a search box that needs to match against a name, an email, and maybe a company field, all with the same operator.
The old way
$users = User::where(function ($query) use ($term) {
$query->where('name', 'like', "%{$term}%")
->orWhere('email', 'like', "%{$term}%")
->orWhere('company', 'like', "%{$term}%");
})->get();
It works, but it's boilerplate you have to get right every time — forget the wrapping closure and you'll accidentally AND your search term with every other constraint on the query instead of scoping the OR correctly.
whereAny()
$users = User::whereAny(
['name', 'email', 'company'],
'like',
"%{$term}%"
)->get();
Same result, one line. whereAny() takes an array of columns, an operator, and a value, and applies the condition across all of them joined with OR, automatically wrapped in its own group — so it composes safely with other where() calls on the same query.
$users = User::where('is_active', true)
->whereAny(['name', 'email', 'company'], 'like', "%{$term}%")
->get();
That gives you WHERE is_active = 1 AND (name LIKE ? OR email LIKE ? OR company LIKE ?) — exactly the grouping you'd want, without writing the closure yourself.
whereAll()
whereAll() is the AND equivalent — useful when a value needs to match across every column, which comes up more than you'd think with denormalized or mirrored fields:
$products = Product::whereAll(
['primary_locale', 'fallback_locale'],
'=',
'en'
)->get();
Or checking that several boolean flags are all true without spelling out each one:
$posts = Post::whereAll(
['is_published', 'is_reviewed', 'is_indexed'],
true
)->get();
Mixing with whereNot
Both have negated counterparts, whereNone(), that flip the logic:
// No column contains "test"
$users = User::whereNone(['name', 'email'], 'like', '%test%')->get();
When to reach for these vs. a full-text index
whereAny() is sugar over LIKE queries under the hood — it's not doing anything a database index can optimize the way a proper full-text search would. For an admin search box scanning a few thousand rows, it's perfectly fine and a lot more readable than the closure version. For public-facing search across a large table, you still want Scout, a full-text index, or a dedicated search engine — whereAny() just makes the small, everyday version of this pattern less annoying to write.