Blog EspecializaTi
Carlos Ferreira Por: Carlos Ferreira Comentar

Laravel Eloquent Global Scope

Laravel Eloquent Global Scope

No último tutorial detalhei sobre Local Scopes no Laravel, agora dando continuidade ao tutorial vou abordar sobre Global Scopes no Laravel.

Diferente do Local Scope que é aplicado manualmente na query, o Global Scope é aplicado por default (padrão). O recurso de Soft Deleting é aplicado por padrão devido ao recurso de Global Scope.

 
 

Em que cenário usar o Global Scope?

Vamos imaginar que temos uma tabela products (produtos), que tem diversas colunas com as informações do produto, e ainda tem uma coluna adicional chamada por exemplo “visible”, que é do tipo Boolean, e por default (padrão) o valor é “true” (visível).

No sistema precisamos exibir apenas os produtos visíveis, poderíamos criar um Local Scope para resolver isso, mas, neste caso precisaríamos em todos os momentos que fosse selecionar os produtos vincular a query com o Local Scope, ficaria trabalhoso. O Global Scope resolve este caso, porque podemos definir que uma ou mais condições sejam aplicadas automaticamente.

 
 

Vamos ao exemplo prático.

Dentro do diretório app/ do Laravel, crie um novo diretório chamado Scopes, é neste diretório pode podemos salvar todos os Global Scopes.

Dentro de app/Scopes/ crie um arquivo e classe chamado VisibleScope.
Visible” é o nome da funcioalidade, e “Scope” é interessante prefixar no nome da Classe para identificar o recurso.

Na classe VisibleScope crie um método apply(), para aplicar o filtro (where) default (padrão). Essa classe deve herdar de Illuminate\Database\Eloquent\Scope. Exemplo:

namespace App\Scopes;

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

class VisibleScope 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('visible', true);
    }
}

O método apply() injeta duas classes: Illuminate\Database\Eloquent\Builder que serve para aplicar as querys e Illuminate\Database\Eloquent\Model que é o objeto da Model, que pode ser usado para talvez aplicar uma query diferente para um Model específico.

Neste exemplo aplicamos um where() para filtrar os dados cuja a coluna visible seja true.

Se quiser aplicar mais de um where() pode encadear, algo assim:

public function apply(Builder $builder, Model $model)
{
    $builder->where('visible', true)
    			->where('price', '>', 0);
}

 
 

Aplicando Global Scopes

Uma vez que foi criado o nosso Global Scope, podemos aplicar em quantos Models for necessário aplicar o filtro default.
Para isso você deve fazer o override (Polimorfismo) do método estático boot(), assim:

namespace App\Models;

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

class Product extends Model
{
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(new VisibleScope);
    }
}

No método boot() chamamos o método boot() principal (PAI) com:
parent::boot();

E para aplicar o Scope Global bastou usar o método estático addGlobalScope() passando um objeto do nosso Global Scope App\Scopes\VisibleScope;

Agora quando fizer uma consulta através do Model Product automaticamente vai aplicar os filtros definidos no Global Scope VisibleScope

$product = Product::get(); // Product::all();
// Query: select * from `products` where `visible` = 1

Para debugar a query, faça o teste:

dd(Product::toSql());

 
 

Anonymous Global Scopes

Agora se precisa aplicar o conceito de Global Scope em um Model particular, sem a necessidade de reaproveitar, não em a necessidade de criar uma classe para aplicar a finalidade, pode reescrever (override) o método boot() aplicando o filtro default:

namespace App\Models;

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

class Product extends Model
{
    protected static function boot()
    {
        parent::boot();

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

Desta vez no método addGlobalScope() invés de passar um objeto do Global Scope passamos um nome de identificação “visible” + uma função de callback aplicando a query exclusiva de default (padrão) do Model.

 
 

Remover Global Scopes

Uma das possibilidades do Eloquent é excluir um Scope Global aplicado. Essa opção é interessante por exemplo em caso de ter que listar os produtos no site (com Scope Global), porém no painel de administração listar todos os produtos, sem filtro.

Para recuperar os produtos sem o Global Scope, pode fazer assim:

Product::withoutGlobalScope(VisibleScope::class)->get();

Também pode remover mais de um Global Scope, veja o exemplo:

Product::withoutGlobalScope([
    VisibleScope::class, ActiveScope::class
])->get();

Outra opção é remover todos os Global Scope, veja o exemplo:

Product::withoutGlobalScope()->get();

Agora se tiver definido o Global Scope Anonymous, deve fazer assim:

Product::withoutGlobalScope('visible')->get();

 

Basicamente é isso, espero que tenha gostado, e qualquer dúvida só deixar aquele comentário. 🙂

 

Deixa sua sugestão de conteúdo!

 

Abraços []’s
 

Carlos Ferreira

Sobre o Autor:

Carlos Ferreira

Carlos Ferreira é Analista de Sistemas Experiente, Empreendedor, Fundador da empresa EspecializaTi. Certificações: Comptia Linux +, LPI, Novell Certification.

Todos os direitos reservados © 2018 - EspecializaTi. É proibida a reprodução total ou parcial deste conteúdo.