Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel 5.3 - Query Builder starting with orWhere

Recently Laravel released version 5.3.

There are some upgrade instructions from 5.2 to 5.3 in the following link: https://laravel.com/docs/5.3/upgrade#upgrade-5.3.0

Eloquent scopes now respect the leading boolean of scope constraints. For example, if you are starting your scope with an orWhere constraint it will no longer be converted to normal where. If you were relying on this feature (e.g. adding multiple orWhere constraints within a loop), you should verify that the first condition is a normal where to avoid any boolean logic issues.

If your scopes begin with where constraints no action is required. Remember, you can verify your query SQL using the toSql method of a query:

This seems to make things a bit harder, and the upgrade will only add limitations to it.

We have an internal package, and to keep the code simple and as neat possible, there is a part that relies on starting a query with orWhere(), and makes use of this as well as the closure concept inside a recursive method. As you know, recursive methods are best to keep it short and simple.

According to the upgrade note now, it will for sure fail on Laravel 5.3

I was just wondering if anyone knows the reason to why this behavior is being removed?

Thanks!

Update:

I've migrated our system over to Laravel 5.3. I confirm that this is only affected in Eloquent builder, and not in the Query Builder (formerly "Fluent Builder").

Even the commit (which is a hell of a lotta changes) is only on Eloquent\Builder. https://github.com/laravel/framework/issues/14829

Anyway, to be on the safe side, I do recommend to make the tweak accordingly. That is what we did, though we know that it did not break our code (as of today).

like image 604
Thomas Cheng Avatar asked Jul 13 '16 16:07

Thomas Cheng


2 Answers

I believe the reason is exact this pull request: https://github.com/laravel/framework/pull/12918

Someone would like to use scopes like this:

User::approved()->orActive();

and in that case if orActive scope is defined like this:

public function scopeOrActive($q) {
   return $q->orWhere('active',1)
}

and approved scope is defined like this:

public function scopeApproved($q) {
   return $q->where('approved',1)
}

In laravel 5.2 it would resolve to:

where approved = 1 AND active = 1

and in Laravel 5.3 it's resolved to:

where approved = 1 OR active = 1

so it makes sense however I've never used scopes starting with orWhere

like image 194
Marcin Nabiałek Avatar answered Oct 27 '22 02:10

Marcin Nabiałek


Here is a way to use multiple orWhere clauses with booleans. Say you want to have a query like:

select * from users where active = 1 and (user_type = 1 or user_type = 2 or user_type = 3);

But we dont necessarily always want all of the user_types to be in the query, ie we have some boolean values which decide which ones should be present. This can be achieved like so:

$includeOne = true;
$includeTwo = false;
$includeThree = true;
$query = User::where('active', 1)
    ->where(function($q) use ($includeOne, $includeTwo, $includeThree) {
        $q->when($includeOne, function($query) {
            return $query->orWhere('user_type', 1);
        })
        ->when($includeTwo, function($query) {
            return $query->orWhere('user_type', 2);
        })
        ->when($includeThree, function($query) {
            return $query->orWhere('user_type', 3);
        });
    })->get();
like image 39
omarjebari Avatar answered Oct 27 '22 03:10

omarjebari