Skip to content

Commit

Permalink
[HttpKernel] Allow using attributes for setting status code and heade…
Browse files Browse the repository at this point in the history
…rs for HTTP exceptions
  • Loading branch information
angelov committed Nov 27, 2022
1 parent c79d4ab commit eb43f5f
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 1 deletion.
29 changes: 29 additions & 0 deletions src/Symfony/Component/HttpKernel/Attribute/HttpException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\HttpKernel\Attribute;

use Symfony\Component\HttpFoundation\Response;

/**
* Allows HTTP status code and headers to be set for an exception
*
* @author Dejan Angelov <angelovdejan@protonmail.com>
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
class HttpException
{
public function __construct(
public readonly int $statusCode = Response::HTTP_INTERNAL_SERVER_ERROR,
public readonly array $headers = []
) {
}
}
15 changes: 14 additions & 1 deletion src/Symfony/Component/HttpKernel/HttpKernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\HttpException;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
Expand Down Expand Up @@ -239,7 +240,19 @@ private function handleThrowable(\Throwable $e, Request $request, int $type): Re
$response->setStatusCode($e->getStatusCode());
$response->headers->add($e->getHeaders());
} else {
$response->setStatusCode(500);
$class = new \ReflectionClass($e);
$attributes = $class->getAttributes(HttpException::class);

if (0 === count($attributes)) {
$response->setStatusCode(500);
} else {
$arguments = $attributes[0]->getArguments();
$statusCode = $arguments["statusCode"];
$headers = $arguments["headers"];

$response->setStatusCode($statusCode);
$response->headers->add($headers);
}
}
}

Expand Down
27 changes: 27 additions & 0 deletions src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\HttpException;
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
Expand Down Expand Up @@ -234,6 +235,22 @@ public function testHandleHttpException()
$this->assertEquals('POST', $response->headers->get('Allow'));
}

public function testHandleExceptionWithHttpAttribute()
{
$dispatcher = new EventDispatcher();
$dispatcher->addListener(KernelEvents::EXCEPTION, function (ExceptionEvent $event) {
$event->setResponse(new Response());
});

$kernel = $this->getHttpKernel($dispatcher, function () {
throw new NotFoundHttpExceptionWithAttribute();
});
$response = $kernel->handle(new Request());

$this->assertEquals('404', $response->getStatusCode());
$this->assertEquals('example', $response->headers->get('resource'));
}

public function getStatusCodes()
{
return [
Expand Down Expand Up @@ -525,3 +542,13 @@ function controller_func()
{
return new Response('foo');
}

#[HttpException(
statusCode: Response::HTTP_NOT_FOUND,
headers: [
'resource' => 'example'
]
)]
class NotFoundHttpExceptionWithAttribute extends \Exception
{
}

0 comments on commit eb43f5f

Please sign in to comment.