Gli scopes di Eloquent costituiscono una risorsa utile per evitare la duplicazione del codice.

Uno scope non è altro che un vincolo, un metodo che quando invocato applica un filtro predefinito alla query. Vediamo un esempio preso direttamente dalla documentazione ufficiale di Laravel.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * Scope a query to only include popular users.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePopular($query)
    {
        return $query->where('votes', '>', 100);
    }

    /**
     * Scope a query to only include active users.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeActive($query)
    {
        return $query->where('active', 1);
    }
}

I metodi che definiscono lo scope hanno sempre come prefisso la parola scope seguita dal nome che si vuole assegnare. Il nome del metodo deve essere in camel case.

Per utilizzare lo scope si dovrà richiamare il nome del metodo privo del prefisso scope, come mostrato di seguito:

$users = User::popular()->get();

Ovviamente il parametro $query non deve essere considerato, sarà Eloquent a passare l’argomento. E’ possibile però creare degli scope dinamici, cioè passare allo scope uno o più argomenti per adattare la condizione al contesto in cui deve essere usata.

Se prendiamo come esempio scopePopular() dello snippet precedente, vediamo come dinamizzare il numero di voti.

/**
     * Scope a query to only include popular users.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePopular($query, $votes)
    {
        return $query->where('votes', '>', $votes);
    }

Global Scopes

E’ possibile definire vincoli da applicare su tutte le query di un model. Per far questo è necessario creare un global scope e utilizzarlo nel model.

Definizione di un global scope:

<?php

namespace App\Scopes;

use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class AgeScope implements Scope
{
    /**
     * Apply the scope to a given Eloquent query builder.
     *
     * @param  \Illuminate\Database\Eloquent\Builder  $builder
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @return void
     */
    public function apply(Builder $builder, Model $model)
    {
        $builder->where('age', '>', 200);
    }
}

Dopo aver creato la classe dello scope, possiamo applicarla al model sovrascrivendo il metodo boot() come mostrato nell’esempio di seguito:

<?php

namespace App;

use App\Scopes\AgeScope;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The "booting" method of the model.
     *
     * @return void
     */
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(new AgeScope);
    }
}

In questo esempio tutte le query eseguite verranno applicate ai record il cui campo age ha un valore superiore a 200.

Pagina della documentazione Ufficiale

Scopri i Corsi in aula Laravel di LaraMind! LaraMind è il punto di riferimento in Italia per quanto riguarda Laravel, Vue.js, PHP e JavaScript, scopri inoltre i nostri servizi custom, per privati e per aziende!