New in Symfony 6.3: HTTP Exception Attributes
April 19, 2023 • Published by Javier Eguiluz
Symfony 6.3 is backed by:
Warning: This post is about an unsupported Symfony version. Some of this information may be out of date. Read the most recent Symfony Docs.
PHP attributes allow to define machine-readable metadata in your code instead of having to add that configuration in a separate file. With each new Symfony version we add more attributes that you can optionally use. In Symfony 6.3 we've added new attributes to configure HTTP exceptions.
Currently, to create your own HTTP exceptions, you need to implement HttpExceptionInterface
(or extend the HttpException
base class) and configure it in the
framework.exceptions option:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
use App\Domain\Exception\Order\OrderNotFound;
use Symfony\Component\HttpKernel\Exception\HttpException;
class OrderNotFound extends HttpException
{
public static function create(string $id): self
{
return new self(
statusCode: Response::HTTP_NOT_FOUND,
message: sprintf('The order "%s" could not be found.', $id),
headers: ['x-header' => 'foo'],
);
}
}
1 2 3 4 5 6
# config/packages/exceptions.yaml
framework:
exceptions:
App\Domain\Exception\Order\OrderNotFound:
log_level: 'debug'
status_code: 404
In Symfony 6.3, the above code and configuration still work, but you can optionally replace them by the following PHP attributes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
use App\Domain\Exception\Order\OrderNotFound;
use Psr\Log\LogLevel;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\WithHttpStatus;
use Symfony\Component\HttpKernel\Attribute\WithLogLevel;
#[WithHttpStatus(Response::HTTP_NOT_FOUND, headers: ['x-header' => 'foo'])]
#[WithLogLevel(LogLevel::DEBUG)]
class OrderNotFound extends \Exception
{
public function __construct(Order $order)
{
parent::__construct(
message: sprintf('The order "%s" could not be found.', $order->getId())
);
}
// ...
}
That's all. You no longer need to configure anything in the framework.exceptions
option. In addition to having all the information in a single file, this also removes
the coupling of your HTTP exceptions with the HttpKernel component. In other words,
your domain exceptions are decoupled from the infrastructure code.
If your application uses both attributes and the framework.exceptions
option,
the configuration will have more priority than the attributes.
Help the Symfony project!
As with any Open-Source project, contributing code or documentation is the most common way to help, but we also have a wide range of sponsoring opportunities.
Comments are closed.
To ensure that comments stay relevant, they are closed for old posts.
```php
#[WithLogLevel(LogLevel::DEBUG)]
class OrderNotFound extends HttpException
{
public int $code = Response::HTTP_NOT_FOUND;
// ...
}
```
However, the beauty of attributes is that they are declarative, so their implementation is independent from their declaration. We could add this class to a project not using Symfony and the exception class would still be working. Of course, we'd lose the behavior of the attributes but we could implement them ourselves or rely on a third-party library (or other framework) that implements them.
Whereas if you extend from `HttpException` in the exception, you need the HttpKernel to use the exception. See https://3v4l.org/MHeT7 vs https://3v4l.org/7HqB4