How do you wrap Laravel Eloquent ORM query scopes in parentheses when chaining?

后端 未结 5 1980
不知归路
不知归路 2021-02-12 14:47

In Eloquent, I\'d like to generate this query:

SELECT * FROM table WHERE a=1 AND ( b=2 OR c=3 );

But I seem to be generating this query instead

相关标签:
5条回答
  • 2021-02-12 15:22

    Did you test whereRaw()?

    so your function should look like:

    function scopeIsFeaturedOrIsBlogPost($query) {
        return $query->whereRaw('( isFeatured = "true" OR type = "blogPost" )');
    }
    

    ps. this is untested

    0 讨论(0)
  • 2021-02-12 15:22

    I'm a little late to the party, but wouldn't the most logical way be to wrap the where in a Closure?

        Model::where('a', '=', 1)
                ->where(function($query) {
                        $query->where('b', '=', 2)
                        ->orWhere('c', '>', 3);
        })
        ->get();
    
    0 讨论(0)
  • 2021-02-12 15:24

    SEE EDIT FOR FINAL ANSWER

    Better than raw, use orWhere with a closure:

    $model = Model::whereAIsOne()->orWhere(function($query) {
        $query->where('b', 1)->where('c', 1);
    })->get();
    

    The really unfortunate thing (and the way I ended up at this post) is that the second $query used in the closure is an instance of \Illuminate\Database\Query\Builder rather than \Illuminate\Database\Eloquent\Builder - this means that you can't use the model scopes within that closure, because Query\Builder instances don't have a reference to a model.

    That said, I still think this is much more ORM-like and useful as a developer.

    EDIT

    Took a while to figure out, but this will work if you want to use your scopes as well:

    $model = Model::whereAIsOne()->orWhere(function($query) {
        $this->newEloquentBuilder($query)->setModel($this)->whereBIsOneAndCIsOne();
    })->get();
    

    I'm actually creating a fourth scope in my code that encompasses all of this, so the $this might not work in this context - however, I find that scoping for my models is one of the most important parts of building a good system.

    This definitely should be built into Eloquent - the engine has a good start, but so many features are missing.

    0 讨论(0)
  • To wrap queries, you can do something like this:

    $builder->where(function ($query) {
        $query->where('gender', 'Male')
            ->where('age', '>=', 18);
    })->orWhere(function($query) {
        $query->where('gender', 'Female')
            ->where('age', '>=', 65);   
    })
    

    It will output the following query:

    WHERE (gender = 'Male' and age >= 18) or (gender = 'Female' and age >= 65)
    
    0 讨论(0)
  • 2021-02-12 15:38

    You can generate parentheses by passing a callback function to where().

    Model::where('a',1)->where(function($query) {
        $query->where('b', 2)->orWhere('c',3);
    })->get();
    
    0 讨论(0)
提交回复
热议问题