Skip to content

Handling Exception

Symfony kernel provides a event machoism to raise an Exception in Controller class and handle them in your custom EventListener or EventSubscriber .

Creating PostNotFoundException

For example, create a PostNotFoundException.

class PostNotFoundException extends \RuntimeException
{

    public function __construct(Uuid $uuid)
    {
        parent::__construct("Post #" . $uuid . " was not found");
    }

}

Creating EventListener

Create a EventListener to catch this exception, and handle the exception as expected.

class ExceptionListener implements LoggerAwareInterface
{
    private LoggerInterface $logger;

    public function __construct()
    {
    }

    public function onKernelException(ExceptionEvent $event)
    {
        // You get the exception object from the received event
        $exception = $event->getThrowable();
        $data = ["error" => $exception->getMessage()];

        // Customize your response object to display the exception details
        $response = new JsonResponse($data);

        // HttpExceptionInterface is a special type of exception that
        // holds status code and header details

        if ($exception instanceof PostNotFoundException) {
            $response->setStatusCode(Response::HTTP_NOT_FOUND);
        } else if ($exception instanceof HttpExceptionInterface) {
            $response->setStatusCode($exception->getStatusCode());
            $response->headers->replace($exception->getHeaders());
        } else {
            $response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR);
        }

        // sends the modified response object to the event
        $event->setResponse($response);
    }

    public function setLogger(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
}

Next, register this ExceptionListener in config/service.yml file. Then it will be applied in the HTTP request lifecycle.

  App\EventListener\ExceptionListener:
    tags:
      - { name: kernel.event_listener, event: kernel.exception, priority: 50 }

It binds the event.exception event to this ExceptionListener, and set priority value to setup the execution order at runtime.

Run the following command to show all registered EventListener/EventSubscribers on event kernel.exception.

php bin/console debug:event-subscriber kernel.exception

Throwing Exception in Controller

Open the PostController, change the getById function to the following.

#[Route(path: "/{id}", name: "byId", methods: ["GET"])]
function getById(Uuid $id): Response
{
    $data = $this->posts->findOneBy(["id" => $id]);
    if ($data) {
        return $this->json($data);
    } else {
        throw new PostNotFoundException($id);
    }
}

Run the application again, and try to access a single Post through a non-existing id.

curl http://localhost:8000/posts/1ec3e1e0-17b3-6ed2-a01c-edecc112b438 -H "Accept: application/json" -v
> GET /posts/1ec3e1e0-17b3-6ed2-a01c-edecc112b438 HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.55.1
> Accept: application/json
>
< HTTP/1.1 404 Not Found
< Cache-Control: no-cache, private
< Content-Type: application/json
< Date: Mon, 22 Nov 2021 03:57:51 GMT
< X-Powered-By: PHP/8.0.10
< X-Robots-Tag: noindex
< Content-Length: 69
<
{"error":"Post #1ec3e1e0-17b3-6ed2-a01c-edecc112b438 was not found."}