Projetor de Eventos Laravel e conceito de geração de eventos


A tradução do artigo foi preparada para os alunos do curso profissional "Framework Laravel"




Frek Van der Herten e a equipe Spatie trabalharam muito por um longo tempo no Laravel Event Projector, um pacote que permite aplicar o conceito de Event Sourcing à estrutura do Laravel. E, finalmente, a primeira versão estável (v1.0.0) está disponível!


Você pode instalar o Event Projector em seu projeto usando o compositor e, graças à detecção automática de pacotes no Laravel, começa a trabalhar imediatamente após publicar as migrações e configurações de pacotes!


composer require spatie/laravel-event-projector:^1.0.0 

O Projetor de Eventos requer PHP 7.2, portanto, seu aplicativo deve suportar a versão mais recente do PHP, embora a própria estrutura Laravel precise de uma versão PHP de pelo menos 7.1.3.


O que é "geração de eventos"


No artigo Gerando eventos, esse conceito é descrito da seguinte maneira:


Em vez de armazenar o estado atual dos dados no domínio, use para registrar toda a sequência de ações executadas nesses dados, o armazenamento operando no modo somente anexado está adicionando apenas dados. O armazenamento atua como um sistema de registros e pode ser usado para materializar objetos de domínio. Isso nos permite simplificar tarefas em áreas de assunto complexas, pois não há necessidade de sincronizar o modelo de dados e a área de assunto, o que leva a uma melhor escalabilidade, aumento da produtividade e eficiência operacional. Essa abordagem garante a consistência dos dados transacionais e também permite manter um registro e histórico de alterações completos, possibilitando a realização de ações compensatórias.

Eu recomendo que você leia o artigo inteiro. Ele fornece uma excelente descrição desse modelo, expressa considerações para o uso adequado e descreve situações em que pode ser útil.


Também gosto da explicação do conceito de geração de eventos, que é apresentado na introdução à documentação do Event Projector:


A geração de eventos é a mesma em relação aos dados que o Git em relação ao código. A maioria dos aplicativos armazena apenas seu estado atual no banco de dados. Uma quantidade significativa de informações úteis é perdida - você não sabe como o aplicativo atingiu esse estado.

O conceito de geração de eventos é uma tentativa de resolver esse problema, salvando todos os eventos que ocorrem no seu aplicativo. O estado do aplicativo é formado como resultado da escuta desses eventos.

Para facilitar o entendimento, considere um pequeno exemplo da vida. Imagine que você é um banco. Seus clientes têm contas. Manter apenas informações sobre o saldo da conta não é suficiente. Você também deve se lembrar de todas as transações. Ao usar o modelo de geração de eventos, o saldo da conta não será apenas um campo separado no banco de dados, mas um valor calculado com base nas informações da transação armazenada. Esse é apenas um dos muitos benefícios que o conceito de geração de eventos oferece.

Este pacote foi desenvolvido para familiarizar os usuários da estrutura do Laravel com o conceito de geração de eventos e facilitar seu uso na prática.

Parece que o Projetor de Eventos ajuda a simplificar o trabalho com o padrão de geração de eventos. A documentação também me ajudou a descobrir como usar essa abordagem como parte dos conceitos da estrutura do Laravel que eu já conheço.


Fundamentos do Laravel Eventing


Para entender como a geração de eventos no pacote Projetor de Eventos funciona e quais componentes estão envolvidos nesse processo, leia a seção Criando o primeiro projetor .


Em um nível alto (perdoe-me se não estiver completamente correto em minha avaliação, já que a geração de eventos é um novo conceito para mim), a geração de eventos usando o Projetor de Eventos inclui:


  • Modelos Eloquentes
  • Eventos implementando a interface ShouldBeStored
  • Classes do projetor

Um exemplo de uma classe de modelo com o método estático createWithAttributes , fornecido na documentação:


 namespace App; use App\Events\AccountCreated; use App\Events\AccountDeleted; use App\Events\MoneyAdded; use App\Events\MoneySubtracted; use Illuminate\Database\Eloquent\Model; use Ramsey\Uuid\Uuid; class Account extends Model { protected $guarded = []; protected $casts = [ 'broke_mail_send' => 'bool', ]; public static function createWithAttributes(array $attributes): Account { /* *      (uuid). */ $attributes['uuid'] = (string) Uuid::uuid4(); /* *          uuid. */ event(new AccountCreated($attributes)); /* *         uuid. */ return static::uuid($attributes['uuid']); } public function addMoney(int $amount) { event(new MoneyAdded($this->uuid, $amount)); } public function subtractMoney(int $amount) { event(new MoneySubtracted($this->uuid, $amount)); } public function delete() { event(new AccountDeleted($this->uuid)); } /* *         uuid. */ public static function uuid(string $uuid): ?Account { return static::where('uuid', $uuid)->first(); } } 

Aqui você precisa prestar atenção aos eventos AccountCreated , MoneyAdded , MoneySubtracted e AccountDeleted , acionados respectivamente para abrir uma conta, adicionar dinheiro à conta, sacar dinheiro da conta e excluir a conta.


A seguir, é apresentado um exemplo do evento MoneyAdded (adicionando dinheiro a uma conta). A interface ShouldBeStored informa ao pacote do Event Projector que este evento deve ser salvo:


 namespace App\Events; use Spatie\EventProjector\ShouldBeStored; class MoneyAdded implements ShouldBeStored { /** @var string */ public $accountUuid; /** @var int */ public $amount; public function __construct(string $accountUuid, int $amount) { $this->accountUuid = $accountUuid; $this->amount = $amount; } } 

E, finalmente, um exemplo parcial de um manipulador de eventos dentro da classe do projetor para reabastecer fundos na conta (meu tipo favorito de evento bancário):


 public function onMoneyAdded(MoneyAdded $event) { $account = Account::uuid($event->accountUuid); $account->balance += $event->amount; $account->save(); } 

Para vincular tudo isso, considere um exemplo da documentação sobre como criar uma nova conta e adicionar fundos:


 Account::createWithAttributes(['name' => 'Luke']); Account::createWithAttributes(['name' => 'Leia']); $account = Account::where(['name' => 'Luke'])->first(); $anotherAccount = Account::where(['name' => 'Leia'])->first(); $account->addMoney(1000); $anotherAccount->addMoney(500); $account->subtractMoney(50); 

Suspeito que o saldo nas contas de Luke e Leia esteja expresso em empréstimos padrão galácticos, embora em geral duvide que eles realizariam abertamente essas operações.


Minha atenção também foi atraída pela seguinte vantagem de gerar eventos usando este pacote, indicado na documentação:


Um ponto interessante ao trabalhar com projetores - eles podem ser criados após a ocorrência de eventos. Imagine que o banco deseja receber um relatório sobre o saldo médio de cada conta. Nesse caso, será suficiente criar um novo projetor, reproduzir todos os eventos e obter esses dados no final.

A própria idéia de criar novos projetores no final dos eventos parece muito promissora. Acontece que você não precisa obter todos os dados "certos" com antecedência, mas pode chegar ao resultado de forma iterativa.


Quanto ao desempenho, de acordo com a documentação, o acesso aos projetores "acontece muito rapidamente".


Deseja saber mais?


Para começar, recomendo que você leia a documentação do Projetor de Eventos e verifique se possui a versão mais recente do PHP 7.2. A equipe da Spatie também enviou um exemplo de aplicativo no Laravel , demonstrando os recursos do pacote Event Projector.


Você pode baixar o código, marcar o repositório com um asterisco e também contribuir para o desenvolvimento do projeto Event Projector no GitHub . No momento da redação deste artigo, o projeto Event Projector já contava com 15 participantes, cujos esforços possibilitaram a liberação estável da versão 1.0. Bom trabalho, Spatie! Tenho certeza que o Event Projector será outro ótimo pacote que será apreciado pela comunidade Laravel.

Source: https://habr.com/ru/post/pt460683/


All Articles