Alura > Cursos de Programação > Cursos de PHP > Conteúdos de PHP > Primeiras aulas do curso Symfony Framework: lidando com eventos, tradução, logs e deploy

Symfony Framework: lidando com eventos, tradução, logs e deploy

Eventos do framework - Apresentação

Boas-vindas! O instrutor Vinicius Dias vai nos guiar nesse curso da Alura onde vamos aprofundar nossos conhecimentos no Symfony Framework.

Vinicius Dias é uma pessoa de pele clara e olhos escuros, com cabelos pretos e curtos. Usa bigode e cavanhaque e veste uma camiseta azul de mangas pretas com a inscrição "PHP 8". Está sentado em uma cadeira preta. Ao fundo, uma parede lisa com iluminação azul clara.

Esse é o 5º curso sobre Symfony da formação Symfony e Doctrine.

O que vamos aprender?

Nesse treinamento vamos evoluir a aplicação construída em cursos anteriores sobre controle de séries e episódios assistidos.

Primeiro, vamos falar sobre a utilidade de eventos do Symfony.

Inclusive, vamos implementar um evento para obter o idioma do navegador e redirecionar o usuário, caso tente acessar a aplicação sem informar o idioma utilizado.

Também vamos utilizar e conceituar tradução e localização para ter a mesma aplicação em dois idiomas, português e inglês, e deixá-la mais internacional.

Depois, vamos estudar sobre logs. Começaremos do básico, explicando o que é e para que serve um log.

Em seguida, vamos criar um log bem simples em arquivo com o Symfony Log, uma biblioteca mais simples. Logo após, vamos aprender sobre Monolog, uma biblioteca muito completa, e fazer configurações para nos ajudar com logs em produção.

Além disso, vamos citar alguns componentes interessantes do Symfony, como o Component Dumper - similar ao var_dump, mas mais elegante e presente direto na toolbar e outros lugares.

No final, vamos conversar sobre dicas para colocar sua aplicação Symfony em produção. Por exemplo, vamos enumerar um passo a passo relacionado ao Symfony, explicar como rodar migrations e discutir sobre performance.

Por último, faremos uma atualização da versão do framework. Nos cursos anteriores utilizávamos a versão 6.1, enquanto nesse curso vamos finalizar com a versão 6.2 do Symfony.

Dessa forma, vamos conhecer quais são as dificuldades de uma atualização. E você vai perceber que, na realidade, a atualização é tranquila.

Te esperamos no próximo vídeo para começar a falar sobre eventos no Symfony.

Eventos do framework - Lidando com exceções

Vamos relembrar o que temos em nosso sistema de controle de séries antes de nos aprofundar em mais conceitos de Symfony.

No navegador, vamos fazer login no sistema com nosso usuário. Na tela inicial, temos a nossa lista de séries e podemos adicionar uma nova série ao clicar no botão "Adicionar" localizado logo abaixo do título "Listagem de séries".

Na página de adição de séries, podemos informar nome, quantidade de temporadas e episódios em suas respectivas caixas de texto, além de enviar arquivos para imagem de capa.

Desafio

Em treinamentos anteriores, deixamos o desafio de implementar um novo formulário de edição. Pois, ao adicionar uma série colocamos certas informações, mas ao editar podemos querer modificar informações diferentes - o que exigiria um novo formulário.

Porém, o instrutor Vinicius não implementou esse formulário de edição. Suponhamos que o sistema foi para a produção com esse erro.

Se queremos editar a série e clicamos no botão "E" no lado direito aos nomes de séries listados na página inicial, será exibida uma mensagem de erro sobre a ocorrência de uma exceção:

LogicException - HTTP 500 Internal Server Error

The form's view data is expected to be a "App\DTO\SeriesCreationInputDTO", but it is a "App\Entity\Series". You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms "App\Entity\Series" to an instance of "App\DTO\SeriesCreationInputDTO".

Porém, essa mensagem detalhada só aparece quando estamos em um ambiente de desenvolvimento.

Se encerramos o servidor e o colocamos em um ambiente de produção, o erro será diferente. Vamos conferir.

Como já falamos sobre configuração e variáveis de ambiente, vamos rapidamente modicar o parâmetro APP_ENV que está igual à dev no arquivo .env. Em .env.local, vamos adicioná-lo como igual à prod:

.env.local:

APP_ENV=prod

No terminal local, vamos interromper o servidor e executá-lo novamente.

Em seguida, atualizamos a página no navegador e fazemos o login novamente. Queremos acessar a mesma URL que leva ao formulário de edição:

http://localhost:8080/series/edit/22

Agora, a mensagem de erro exibida é diferente e não dá detalhes de segurança. É uma página que um usuário poderia ver, informando um erro no servidor.

Oops! An Error Occurred

The server returned a "500 Internal Server Error".

Something is broken. Please let us know what you were doing when this error occurred. We will fix it as soon as possible. Sorry for any incovenience caused.

Mais adiante, também vamos falar mais sobre configurações que devem ser feitas ao colocar algo em produção.

Mas, por enquanto, saiba não vamos ter tantos detalhes quando um erro acontecer em um cenário onde nosso sistema já está em produção.

Nesse cenário, podemos proceder de algumas maneiras. Primeiramente, podemos analisar nossos logs, os quais vamos nos aprofundar mais adiante nesse curso.

Mas, também é possível ter uma ferramenta de monitoramento ou usar um software como o New Relic. Assim, sempre que acontecer uma exceção que não tratamos no sistema, podemos enviar a informação ou criar um evento no sistema de monitoramento.

Eventos

O que queremos fazer nessa aula é executar um determinado código sempre que acontecer uma exceção, erro ou problema não tratado no sistema. Essa execução pode ser feita no Symfony através de eventos.

Apesar de, geralmente, não se criar muitos eventos e ouvintes de eventos, é um assunto muito importante. O que acontece é que normalmente utilizamos códigos externos que fazem uso desse componente de eventos do Symfony.

Para entender melhor esse componente, vamos começar com a criação de um código que escuta esse evento de exceção (exception).

Antes de começar, vamos voltar ao ambiente de desenvolvimento. Para isso, interrompa seu servidor, remova APP_ENV=prod do arquivo .env.local e suba seu servidor novamente.

Com isso, voltamos a ver a mensagem de erro detalhada ao atualizar a página de formulário de edição.

Além de exibir o erro, também queremos mandar essa exceção para algum sistema de monitoramento ao executar um código.

Para isso, vamos criar um event listener (ouvinte de evento). Desse modo, um código é executado assim que um certo evento configurado ocorre.

Criando um event listener

Vamos observar o tópico "creating an event listener" na parte de eventos da documentação do Symfony.

No exemplo fornecido, adiciona-se um novo código em App\EventListener. Para seguir o padrão, vamos criar uma pasta de mesmo nome em nosso projeto.

Para isso, vamos clicar com o botão direito em "src > New > PHP Class". Vamos nomear essa classe como ExceptionEventListener e colocá-la no namespace App\EventListener.

src > Event Listener > ExceptionEventListener.php:

<?php

declare(strict_types=1);

namespace App\EventListener;

class ExceptionEventListener
{

}

Em seguida, assim como está na documentação, vamos criar um método onKernelException() que recebe um ExceptionEvent.

A palavra kernel vem do inglês e significa "núcleo". Com esse método, quando acontecer uma exceção que chegou ao núcleo do framework Symfony, ou seja, não foi tratada no código, esse evento será executado.

Em nossa classe, criamos essa public funciton chamada onKernelException() que espera um evento do tipo ExceptionEvent, o qual vem do namespace Symfony\Component\HttpKernel\Event\ExceptionEvent. Assim, ExceptionEvent é nosso $event.

Dentro das chaves da função onKernelException, poderíamos executar um código para enviar a exceção para New Relic, por exemplo.

Contudo, o intuito desse treinamento não é configurar New Relic. Por isso, vamos apenas deixar como um comentário.

Para que possamos entender que entramos nesse método, vamos executar um echo para exibir na tela a mensagem 'Exceção aconteceu'.

<?php

declare(strict_types=1);

namespace App\EventListener;

use Symfony\Component\HttpKernel\Event\ExceptionEvent;

class ExceptionEventListener
{
    public function onKernelException(ExceptionEvent $event)
    {
        // enviar minha exceção para New Relic
        echo 'Exceção aconteceu';
    }
}

Configurando serviço

Após criar o event listener, precisamos informar ao Symfony para utilizar a classe ExceptionEventListener e o método onKernelException como event listener. Assim, quando acontecer determinado evento, chamará o código que criamos.

Para isso, vamos configurar nosso serviço também usando a documentação de exemplo.

Em nosso arquivo services.yaml, vamos definir nossa classe como serviço do Symfony.

Vamos em "config > services.yaml" e, ao final do arquivo, vamos criar App\EventListener\ExceptionEventListener.

Lembre-se de colocar dois-pontos após o nome da classe e, na próxima linha, adicionaremos algumas configurações.

Podemos definir tags para nossos eventos. Essas tags podem ser utilizadas para buscar serviços por código ou pelo próprio Symfony.

O Symfony vai buscar todos os serviços que possuem a tag name: kernel.event_listener e configurá-los como event listener.

Com isso, dizemos que a classe ExceptionEventListener é um event listener. Mas precisamos avisar também que a classa está preparada para executar um código quando um evento ocorrer.

No nosso caso, vamos especificar que o evento é o kernel.exception.

config > services.yaml:

services:

# código omitido

    App\EventListener\ExceptionEventListener:
        tags:
            - { name: kernel.event_listener, event: kernel.exception }

Durante esse vídeo, o instrutor usa a documentação na versão 6.1. Pode haver uma versão mais atual.

Mas como o Symfony que vai precisar chamar o método onKernelException do ExceptionEventListener.php?

Pois, criamos um método nomeado com a seguinte convenção: on que indica quando acontecer um evento, seguido do nome do evento utilizando CamelCase.

UpperCamelCase (também conhecida como PascalCase) é uma prática onde se coloca cada palavra de uma frase iniciando em letra maiúscula e sem espaços entre si - assim como exemplifica o nome do próprio termo.

Ao seguir esse padrão, o Symfony vai encontrar o método e executar o código que faria a instrumentação para o monitoramento da nossa exceção.

Dessa forma, configuramos o event listener e o serviço. Ressaltamos a importância de ler toda a documentação para entender melhor cada conceito.

Testando event listener

Novamente, vamos interromper o servidor e voltar a executá-lo pelo terminal.

Após atualizar a página do navegador e fazer o login, a mensagem de erro original continua a ser exibida.

Porém, também temos a frase estipulada no echo do método onKernelException.

Exceção aconteceu

Ou seja, nosso código foi executado quando o evento de exceção ocorreu.

Throwable e message

Para finalizar, vamos citar alguns detalhes do objeto do tipo event.

Cada evento ouvido vai trazer como parâmetro um evento diferente. No nosso caso, como kernel.exception estipulado em services.yaml é um evento de exceção, recebemos um ExceptionEvent como parâmetro de onKernelException na classe ExceptionEventListener.php.

Nesse $event, podemos usar getThrowable() para saber qual foi a exceção ou erro lançado. Poderíamos também exibir a mensagem com getMessage().

Assim, ao invés de exibir somente a mensagem "Exceção aconteceu" dentro das chaves de onKernelException, usaremos o echo para exibir a mensagem da exceção.

src > Event Listener > ExceptionEventListener.php:

//código omitido

class ExceptionEventListener
{
    public function onKernelException(ExceptionEvent $event)
    {
        // enviar minha exceção para New Relic
        echo $event->getThrowable()->getMessage()
    }
}

Ao atualizar o navegador, recebemos agora a mensagem de erro completa na página do formulário. Mas, também vemos a mensagem de erro original, logo baixo.

The form's view data is expected to be a "App\DTO\SeriesCreationInputDTO", but it is a "App\Entity\Series". You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms "App\Entity\Series" to an instance of "App\DTO\SeriesCreationInputDTO".

Repare que dessa maneira conseguimos acessar alguns detalhes do erro.

Response e request

Além disso, quase todos os eventos vão ter um objeto do tipo response (resposta) e outro do tipo request (requisição).

Alguns eventos terão apenas um, enquanto outros possuem ambos. O evento de exceção só possui requisição. Assim, conseguimos ter acesso ao objeto de requisição com getRequest() para saber o que foi enviado. Mas, não conseguimos ter acesso ao objeto de resposta com getResponse() para modificar a resposta.

No exemplo de criação de um event listener da documentação, o Symfony pega uma mensagem baseada na exceção com getMessage() e o código com getCode(). Também define como conteúdo da resposta a mensagem, editando o conteúdo com setContent().

Também vemos que se for uma exceção do tipo HTTP, pode-se definir o statusCode. Caso contrário, define-se como "500 Internal Server Error".

No final, depois de modificar a resposta, define-se a resposta no evento com setResponse().

Vamos fazer algo semelhante à documentação.

Dentro das chaves do método onKernelException na classe ExceptionEventListener.php, vamos ter a $response igual a uma nova resposta vazia, ou seja, new Response().

Atente-se que a Response será importada de Symfony\Component\HttpFoundation.

Também vamos substituir echo por $errorMessage, na linha anterior.

Em uma nova linha, digitamos $response e object operator (->) para definir como o conteúdo da resposta a $errorMessage, usando o setContent().

Poderíamos ter passado os parâmetros para newResponse(). Porém, vamos passar em uma nova linha com os setters. Isto é, escrevemos $response seguido de object operator (->)e definimos o StatusCode como 501 - só para definir um status diferente.

Enquanto no $event, podemos definir que a nova resposta é $response, utilizando setResponse($response). Assim, modificamos a resposta.

Então, o evento possui uma resposta padrão, mas, quando definimos uma nova resposta, sabe que é a resposta modificada que o Symfony deve enviar.

src > Event Listener > ExceptionEventListener.php:

//código omitido

class ExceptionEventListener
{
    public function onKernelException(ExceptionEvent $event)
    {
        // enviar minha exceção para New Relic
        $errorMessage = $event->getThrowable()->getMessage()

        $response = new Response();
        $response->setContent($errorMessage);
        $response->setStatusCode(501);

        $event->setResponse($response);
    }
}

Ao atualizar a página do formulário de edição no navegador, conseguimos ter somente a mensagem de erro que definimos:

The form's view data is expected to be a "App\DTO\SeriesCreationInputDTO", but it is a "App\Entity\Series". You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms "App\Entity\Series" to an instance of "App\DTO\SeriesCreationInputDTO".

Vamos apertar "F12" para exibir as ferramentas de desenvolvedor. Vamos na aba "Rede", no topo da caixa, e pressionamos "Ctrl + R" para fazer a atualização da rede. Ao atualizar, podemos ver o status 501 implementado.

Dessa forma, conseguimos analisar a requisição, modificar a resposta e fazer basicamente o que quisermos quando um evento acontecer.

Os event listeners são normalmente de fácil implementação. Porém, além desse formato de ouvir eventos, existe outro formato chamado event subscribers.

No próximo vídeo, vamos entender a diferença entre event listeners e event subscribers na teoria.

Eventos do framework - Detalhes de eventos

Já aprendemos sobre um conceito importante, eventos em Symfony, e praticamos com um desses eventos. Agora, vamos entender um pouco mais da teoria.

Aprendemos que na nossa classe "src > EventListener> ExceptionEventListener.php", o Symfony busca um método que segue uma padronização: on seguido do nome do evento. Como, onKernelException.

Porém, existem outras formas de trabalharmos.

Lógica para chamar métodos no event listener

Atributo method

A primeira forma é ir ao arquivo que definimos o event listener. No nosso caso, vamos em "config > services.yaml". Se colocamos o parâmetro method nas tags do evento, o Symfony buscará um método com esse nome.

Por exemplo, se chamamos o method de myMethod no arquivo de services.yaml, podemos definir o método com myMethod em ExceptionEventListener.php.

config > services.yaml:

services:

# código omitido

    App\EventListener\ExceptionEventListener:
        tags:
            - { name: kernel.event_listener, event: kernel.exception, method: myMethod}

src > Event Listener > ExceptionEventListener.php:

//código omitido

class ExceptionEventListener
{
    public function myMethod(ExceptionEvent $event)
    {
        // código omitido
    }
}

Se acessamos o nosso sistema pelo navegador, vamos continuar a receber a mesma mensagem de erro que estipulamos:

The form's view data is expected to be a "App\DTO\SeriesCreationInputDTO", but it is a "App\Entity\Series". You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms "App\Entity\Series" to an instance of "App\DTO\SeriesCreationInputDTO".

Então, conseguimos utilizar um outro nome de método na definição do nosso event listener.

Repare que a opção do atributo method é o que o Symfony busca em primeiro lugar, segundo a documentação de eventos do Symfony.

Porém, se não definimos um atributo method na tag, o Symfony busca em segundo lugar o método com nome "on + nome do evento" - como fizemos originalmente. Essa a forma mais comumente utilizada.

Invoke

Com a terceira opção não é preciso informar method na tag onde definimos o event listener.

config > services.yaml:

services:

# código omitido

    App\EventListener\ExceptionEventListener:
        tags:
            - { name: kernel.event_listener, event: kernel.exception}

Mas, para não precisar lembrar de definir o nome correto do método na classe ExceptionEventListener.php, você pode usar o método invoke().

No PHP, quando um objeto possui esse método __invoke() (chamado de "mágico" pela documentação), o objeto pode ser chamado como se fosse uma função.

Com isso, o Symfony vai tentar executar o objeto do event listener como uma função e, consequentemente, vai chamar o __invoke().

src > Event Listener > ExceptionEventListener.php:

//código omitido

class ExceptionEventListener
{
    public function __invoke(ExceptionEvent $event)
    {
        // código omitido
    }
}

Dessa forma, a mensagem de erro continua a ser exibida no navegador, como esperado.

The form's view data is expected to be a "App\DTO\SeriesCreationInputDTO", but it is a "App\Entity\Series". You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms "App\Entity\Series" to an instance of "App\DTO\SeriesCreationInputDTO".

Contudo, essa opção só funciona se colocamos o parâmetro correto para __invoke().

Vamos supor que, ao invés do parâmetro ExceptionEvent, recebemos um ControllerArgumentsEvent - um outro evento para quando definimos as propriedades do controller.

Com ControllerArgumentsEvent não temos acesso aos mesmos métodos, como getThrowable() e setResponse().

//CÓDIGO DE EXEMPLO

class ExceptionEventListener
{
    public function __invoke(ControllerArgumentsEvent $event)
    {
        // …
    }
}

Ao tentar executar, temos um novo erro. O erro diz que não conseguiram passar o argumento correto, porque esperam o ControllerArgumentsEvent, mas recebem ExceptionEvent.

Type Error - HTTp 500 Internal Server Error

App\EventListener\ExceptionEventListener::__invoke():Argument#1($event) must be of type Symfony\Component\HttpKernel\ControllerArgumentsEvent, Symfony\Component\HttpKernel\Event\ExceptionEvent given, called in /app/vendor/symfony/event-dispatcher/Debug/WrappedListener.php on line 115

Em suma, embora possamos utilizar um nome de método mais genérico com __invoke(), precisamos receber o parâmetro correto.

Mas, se não temos o atributo method definido em tag, nem o método defino como "on + nome do evento" e também não usamos o __invoke(), o Symfony lançará uma exceção e não conseguirá resolver o event listener.

Esses são os detalhes sobre o event listener. Porém, existem vários outros eventos.

Quais eventos existem?

No começo da página da documentação do Symfony sobre eventos, podemos entender que durante a execução de uma aplicação Symfony vários eventos de notificação são enviados.

Assim, vários eventos acontecem durante o ciclo de vida de uma aplicação Symfony. E o nosso código pode ouvir e reagir a esses eventos.

O próprio Symfony lança vários eventos chamado de kernel events.

Nós podemos criar nossos próprios eventos, assim como qualquer outro bundle ou código externo também pode criar esses custom events (eventos customizados).

Kernel events

Na documentação sobre kernel events, notamos que os eventos do Symfony são:

Na documentação existe uma descrição de cada um desses kernel events. Alguns têm nomes autoexplicativos, como o kernel.request para quando recebemos uma requisição e o kernel.view para quando montamos uma view.

Já outros eventos não tão óbvios, como diferenciar entre kernel.controller e kernel.controller_arguments ou kernel.finish_request e kernel.terminate.

Mas, basicamente, os kernel events são executados na ordem em os listamos acima. Ressaltamos que leia toda a documentação para entender mais sobre a ordem e o momento em que são executados.

Para exemplificar, vamos analisar o kernel.controller. Esse evento é disparado depois que o controller foi resolvido, mas antes de executá-lo.

Em outras palavras, conseguimos instanciar o controller, ou seja, passamos as dependências. Mas, não executamos o controller, isto é, o método que efetivamente executa aquela rota não foi chamado ainda.

Já o kernel.controller_arguments é disparado logo antes do controller ser efetivamente chamado.

Perceba que kernel.controller e kernel.controller_arguments estão próximos, mas com kernel.controller_arguments podemos configurar os argumentos que serão passados.

Como já dissemos anteriormente, normalmente não criamos listeners para esse tipo de evento. Geralmente, buscamos conhecer esses kernel events para saber como alguns códigos externos resolvem problemas. Ao invés disso, lidamos com custom events (eventos customizados) - que nós mesmos ou outros códigos podem criar.

Custom Events

Agora, vamos analisar a documentação sobre custom events.

Então, conseguimos definir um evento e fazer um dispatch, com o qual podemos enviar eventos.

Assim, podemos registrar diversos event listeners e, ao final, enviar um evento com dispatch.

//CÓDIGO DE EXEMPLO DA DOCUMENTAÇÃO SYMFONY 6.1

use Acme\Store\Event\OrderPlacedEvent;
use Acme\Store\Order;

// the order is somehow created or retrieved
$order = new Order();
// ...

// creates the OrderPlacedEvent and dispatches it
$event = new OrderPlacedEvent($order);
$dispatcher->dispatch($event, OrderPlacedEvent::NAME);

Suponha que você utiliza algum bundle externo que pode se comunicar com o código da sua aplicação através de eventos.

Events subscribers

Além de event listeners também podemos criar event subscribers.

Essa é uma outra forma de ouvir eventos, porém, o event subscriber já sabe os eventos que vão chegar.

Podemos ouvir vários eventos no seguinte formato:

//CÓDIGO DE EXEMPLO DA DOCUMENTAÇÃO SYMFONY 6.1

class ExceptionSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::EXCEPTION => [
                ['processException', 10],
                ['logException', 0],
                ['notifyException', -10],
            ],
        ];
    }

// …

}

Ou seja, podemos ter um array (lista) infomando quais eventos vamos ouvir, dentro das chaves de getSubscribedEvents().

Dentro do array, informamos que quando acontecer o KernelEvents::EXCEPTION, vamos executar os métodos processException, logException e notifyException.

Se acontecer outro evento, podemos definir outros métodos.

O event subscriber é uma forma diferente de fazer a mesma coisa que o event listener.

Para ter um event subscriber basta implementar a interface EventSubscriberInterface. Não precisamos de configuração no services.yaml.

Normalmente, o event subscriber é utilizado quando temos mais de um método sendo executado em determinado evento ou a mesma classe reagirá a vários eventos.

Em suma, usamos o subscriber quando queremos algo mais rebuscado, enquanto o listener é mais simples.

Event listener a partir da versão 6.1

Você pode pensar que o event listener não é mais simples, já que precisamos criar a classe e também definir configurações em services.yaml.

Porém, a partir da versão 6.1 do Symfony que depende da versão 8.1 do PHP, podemos definir um attribute em "src > Event Listener > ExceptionEventListener.php".

Para definir um atributo, logo abaixo das importações e acima da classe, colocamos uma cerquilha (#) seguida de colchetes [] contendo AsEventListener().

Entre os parênteses de AsEventListener() poderíamos informar qual evento se está ouvindo. Porém, no nosso caso, não precisamos fazê-lo já que estamos informando um ExceptionEvent.

Caso queira informar o evento, basta passar o parâmetro event e informar kernel.exception entre aspas simples.

src > Event Listener > ExceptionEventListener.php:

<?php

declare(strict_types=1);

namespace App\EventListener;

use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;

#[AsEventListener(event: 'kernel.exception')]
class ExceptionEventListener
{
    public function __invoke(ExceptionEvent $event)
    {
        // enviar minha exceção para New Relic
        $errorMessage = $event->getThrowable()->getMessage();

        $response = new Response();
        $response->setContent($errorMessage);
        $response->setStatusCode(501);

        $event->setResponse($response);
    }
}

Dessa maneira, não precisamos adicionar arquivos de configuração. Podemos apagar o que escrevemos sobre event listener em service.yaml:

config > services.yaml:

services:

# código omitido

# apague esse trecho a partir daqui
    App\EventListener\ExceptionEventListener:
        tags:
            - { name: kernel.event_listener, event: kernel.exception, method: myMethod}
# apague esse trecho até aqui

Para conferir, podemos acessar a página de formulário de edição no navegador novamente. Mais uma vez é exibido nossa resposta modifica como queríamos.

The form's view data is expected to be a "App\DTO\SeriesCreationInputDTO", but it is a "App\Entity\Series". You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms "App\Entity\Series" to an instance of "App\DTO\SeriesCreationInputDTO".

Ressaltamos novamente que podemos remover o parâmetro event do atributo AsEventListener() da classe ExceptionEventListener.php já que é o evento de exceção.

O que aprendemos?

Repara que temos várias formas de definir um event listener: com o arquivo de configuração services.yaml; com um atributo logo acima da nossa classe; com method nos parâmetros; não passar um método e fazer __invoke(); entre outras formas.

Além disso, podemos ter listeners ou subscribers.

Quando o assunto é eventos, temos muito para configurar e poderia ser um curso inteiro de Symfony. Porém, acreditamos que com essa base, você fica cada vez mais independente para acessar a documentação e buscar a sua necessidade específica.

Em suma, o Symfony trabalha com eventos. Inclusive, você pode criar eventos próprios, criar classes de eventos e fazer o dispatch de evento.

Também pode utilizar um bundle que faz dispatch de evento e criar um event listener para o evento desse bundle.

Em outras palavras, conseguimos trabalhar com eventos no Symfony e nos comunicar com bundles externos.

Talvez você esteja se perguntando sobre a similaridade dos eventos com os messengers para enviar mensagens, visto em treinamentos anteriores.

Qual a diferença entre o componente de eventos e o componente de messenger? Vamos falar brevemente sobre essa diferença no próximo vídeo.

Sobre o curso Symfony Framework: lidando com eventos, tradução, logs e deploy

O curso Symfony Framework: lidando com eventos, tradução, logs e deploy possui 156 minutos de vídeos, em um total de 46 atividades. Gostou? Conheça nossos outros cursos de PHP em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda PHP acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas