Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using multiple Laravel scopes in OR context

I have a Subscription model which contain start_date and end_date attributes in my Laravel app. I have created two query scopes, scopeActive and scopeFuture to find active and future subscriptions (respectively).

I would like to know how I can build a query using both scopes in OR context, so that I can find any active or future subscriptions.

Subscription Model

/**
 * Scope a query to only include active subscriptions.
 *
 * @param \Illuminate\Database\Eloquent\Builder $query
 * @return \Illuminate\Database\Eloquent\Builder
 */
public function scopeActive($query)
{
    return $query->where('start_date', '<', Carbon::now())
                 ->where('end_date', '>', Carbon::now());
}

/**
 * Scope a query to only include future subscriptions.
 *
 * @param \Illuminate\Database\Eloquent\Builder $query
 * @return \Illuminate\Database\Eloquent\Builder
 */
public function scopeFuture($query)
{
    return $query->where('start_date', '>', Carbon::now());
}


public function business()
{
    return $this->belongsTo('App\Business');
}

Business Model

.....
public function subscriptions()
{
    return $this->hasMany('App\Subscription');
}

User Model

public function business()
{
    return $this->hasOne('App\Business');
}

Controller

Subscription::active()->get();
like image 930
InvalidSyntax Avatar asked May 21 '17 15:05

InvalidSyntax


3 Answers

For static-context try:

$subscriptions = Subscription::query()
    ->active()
    ->orWhere(function ($query) {
        $query->future();
    })
    ->get();

First call query() to prevent errors (because we may have a non-static method with "active" as name).

Relation query (as requested in the comment)

$subscriptions = auth()->user()
    ->business()
    ->subscriptions()
    ->active()
    ->orWhere(function ($query) {
        $query->future();
    })
    ->get();

Note that above we don't need to call query() (because it's not from static-context).

like image 163
Sandeesh Avatar answered Nov 06 '22 05:11

Sandeesh


Subscription::active()->orWhere( function($q){
            return $q->future() ;
        } )->get() ;
like image 45
Hosam Elzagh Avatar answered Nov 06 '22 03:11

Hosam Elzagh


Take advantage of params. You could try something like...

public function scopeCanceled($query, $scope = 'where')
{
    return $query->$scope('canceled_at');
}

then you can do for example $query->canceled('orWhere')

you can then de-uglify with:

public function scopeOrCanceled($query)
{
    return $this->scopeCanceled($query, 'orWhere');
}

example $query->orCanceled()

in general with scopes, i find it handy to always have some sort of optional value, to make things flexible

public function scopeApproved($query, bool $value = true)
{
    return $query->where('is_approved', $value);
}

adding a third param for this use case can then make sense

public function scopeApproved($query, string $scope = 'where', bool $value = true) {
    return $query->$scope('is_approved', $value);
}
like image 1
mangonights Avatar answered Nov 06 '22 03:11

mangonights