2
votes

I have a Post Model with SoftDelete capability and an active boolean field to determine Post active status.

class Post extends Model implements SluggableInterface
{
    use SoftDeletes;

    protected $primaryKey = 'post_id';
    .
    .
    .
 }

In addition to, Post Model has a start_date field that hold start date of publish post.

And now , I want to use Anonymous GlobalScope Laravel 5.2 to filter and fetch only active posts and those theirs start_date is NULL or less than Now() In addition to the non Soft Deleted models.

For that I added this to Post Model :

protected static function boot()
        {
            parent::boot();

            static::addGlobalScope('active', function(Builder $builder){
                $builder->where('active',1);
            });

            static::addGlobalScope('scheduled', function(Builder $builder){
                $builder
                    ->whereNull('start_date')->orWhere(function ($query) {
                        $query->where('start_date', '<=', Carbon::now());
                    });
            });
        }

active global scope alone, works fine but when I add second scope named scheduled, returns all records include soft Deleted and inActive models.

what is Problem? I can not understand

1

1 Answers

2
votes

It's because you're using orWhere. In these instances, using the Laravel Debug Bar to see the Raw SQL is very helpful, because I'd bet money your select statement looks like this:

SELECT * FROM table WHERE deleted_at IS NULL AND active=1 AND state_date IS NULL OR (start_Date <= now())

That would select anything that meets the one OR criterion.

To fix that, you should make scheduled look like this.

static::addGlobalScope('scheduled', function(Builder $builder) {
    $builder->where(function($query)) {
        $query->whereNull('start_date');
        $query->orWhere('start_date', '<=', Carbon::now());
    });
});

Which would (hopefully) make your query look like this:

SELECT * FROM table WHERE deleted_at IS NULL AND active=1 AND (state_date IS NULL OR start_Date <= now())

Which is what I think you want.