Como aliviar seus controllers com os eventos do Eloquent no Laravel

O sonho de todo programador é desenvolver código limpo, organizado, legível, manutenível e muitos outros adjetivos que poderia colocar em uma lista enorme. O Laravel possui vários recursos que nos ajuda a organizar nosso código para conseguir alcançar alguns desses atributos que descrevi acima, se usados de maneira correta. Um desses recursos são os eventos do Eloquent.

Esses eventos são executados sempre que uma ação acontece no model. Isso possibilita removermos responsabilidade dos controllers e executar quando o evento for acionado, com isso, conseguimos um controller mais simples e organizado.

O Eloquent disponibiliza os eventos:

  • Retrieved
  • Creating e Created
  • Updating e Updated
  • Saving e Saved
  • Deleting e Deleted
  • Restoring e Restored

Os eventos com final ing são executados antes da ação no banco de dados e os eventos com final ed são executados após a ação no banco de dados.

Relacionando os eventos no Model

É possível relacionar um evento do Eloquent a um método que fará a ação de três modos diferentes.

Via o método boot

O primeiro modo que podemos adicionar uma ação em um evento do model é através do método estático boot. Por exemplo, para executar uma ação antes da criação podemos fazer:

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

    static::creating(function ($nomeDoModel) {
        //Ação a ser executada 
    });

}

O Eloquent sempre injeta uma instância do model automaticamente no evento. Nos eventos executados antes da ação no banco é possível alterar os valores do model que serão persistidos.

A utilização dos eventos dentro do próprio model pode não ser a mais aconselhável, pois dependendo da quantidade de eventos pode sobrecarregar, tirando a complexidade dos controllers e transferindo para o models, o que não é bom, pois a solução de um problema criaria outro.

Via classe de evento

Um modo mais limpo de executar os eventos do Eloquent é através de classes específicas para cada um dos eventos. Para isso, basta declarar no model uma propriedade chamada dispatchesEvents com um array contendo o nome do evento e a respectiva classe que será responsável por executar a ação:

protected $dispatchesEvents = [
        'creating' => NomeDoModelCreating::class,
        'deleting' => NomeDoModelDeleting::class,
    ];

Via Observer

Na minha opinião, esse é o modo mais prático de executar ações quando precisamos executar ações em vários eventos do mesmo model.

Essa abordagem consiste basicamente em criar uma classe e declarar métodos públicos com o mesmo nome dos eventos, com isso, o próprio Eloquent verifica se o método existe, se sim, ele executa.

<?php

namespace App\Observers;

use App\NomeDoModel;

class NomeDoModelObserver
{

    public function creating(NomeDoModel $nomeDoModel)
    {
        //Executa antes de criar no banco
    }

    public function deleting(NomeDoModel $nomeDoModel)
    {
        //Executa antes de deletar no banco
    }
}

Único detalhe é que para o Eloquent fazer a referência entre a classe do model e a classe do Observer precisamos declarar dentro do método boot do AppServiceProvider essa relação:

NomeDoModel::observe(NomeDoModelObserver::class);

Note que usamos o método observe() do próprio model que recebe o caminho da classe do observer.

Exemplo prático

Vamos supor que temos uma relação 1 para 1 entre festa e cliente. Baseado nisso, a cada evento do model festa precisamos executar uma ação:

  • Quanto uma festa for criada para um cliente precisamos alterar o status do cliente para com-proposta;
  • Quando uma festa for atualizada, se o atributo valor for maior que zero precisamos alterar o status do cliente para festa-agendada;
  • Por fim, se a festa for excluída, alteramos o status do cliente para sem-proposta;

Nesse caso, podemos criar um observer com os eventos created, updated e deleted para realizar essas ações:

<?php

namespace App\Observers;

use App\Festa;

class FestaObserver
{

    /**
     * Evento executado após a festa ser criada
     *
     * @param Festa $festa
     */
    public function created(Festa $festa)
    {
        $festa->cliente->update(['status' => 'com-proposta']);
    }


    /**
     * Evento executado após a festa ser atualizada
     *
     * @param Festa $festa
     */
    public function updated(Festa $festa)
    {
        if ($festa->valor > 0) {
            $festa->cliente->update(['status' => 'festa-agendada']);
        }
    }

    /**
     * Evento executado após a festa ser deletada
     *
     * @param Festa $festa
     */
    public function deleted(Festa $festa)
    {
        $festa->cliente->update(['status' => 'sem-proposta']);
    }

}

Conclusão

Esse é apenas um dos recursos que podemos usar no Laravel para manter a organização do código. Podemos usar outros como View Composer, Route Model Bind, Policies para permissões, Presenters para remover lógica das views e muito mais.

Quais dos recursos você tem utilizado em seus projetos para melhorar a qualidade do seu código? Fique à vontade para nos contar aqui nos comentários.

Ah, temos um curso muito bom de Laravel no TreinaWeb. Dê uma espiadinha? 🙂

Até a próxima! 🙂

Deixe seu comentário

Desenvolvedor, autor e instrutor. Apaixonado por desenvolvimento de software e tudo ligado a área de tecnologia. É autor de cursos em diversos temas, como, desenvolvimento back-end, cloud computing e CMSs. Nas horas vagas adora estudar sobre o mercado financeiro, cozinhar e brincar com pequeno Daniel de 1 ano.