8000 [HttpKernel] Wrap the exceptions into HttpException instances · symfony/symfony@081b0da · GitHub
[go: up one dir, main page]

Skip to content

Commit 081b0da

Browse files
committed
[HttpKernel] Wrap the exceptions into HttpException instances
1 parent d071389 commit 081b0da

File tree

4 files changed

+93
-95
lines changed

4 files changed

+93
-95
lines changed

src/Symfony/Component/HttpKernel/EventListener/ErrorListener.php

+15
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\ErrorHandler\Exception\FlattenException;
1616
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
1717
use Symfony\Component\HttpFoundation\Request;
18+
use Symfony\Component\HttpKernel\Attribute\HttpException as HttpExceptionAttribute;
1819
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
1920
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
2021
use Symfony\Component\HttpKernel\Event\ResponseEvent;
@@ -72,6 +73,20 @@ public function logKernelException(ExceptionEvent $event)
7273
break;
7374
}
7475

76+
// There's no specific status code defined in the configuration for this exception
77+
if (!$throwable instanceof HttpExceptionInterface) {
78+
$class = new \ReflectionClass($throwable);
79+
$attributes = $class->getAttributes(HttpExceptionAttribute::class, \ReflectionAttribute::IS_INSTANCEOF);
80+
81+
if (\count($attributes)) {
82+
/** @var HttpExceptionAttribute $instance */
83+
$instance = $attributes[0]->newInstance();
84+
85+
$throwable = new HttpException($instance->statusCode, $throwable->getMessage(), $throwable, $instance->headers);
86+
$event->setThrowable($throwable);
87+
}
88+
}
89+
7590
$e = FlattenException::createFromThrowable($throwable);
7691

7792
$this->logException($throwable, sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), $e->getFile(), $e->getLine()), $logLevel);

src/Symfony/Component/HttpKernel/HttpKernel.php

+1-13
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
use Symfony\Component\HttpFoundation\Request;
1616
use Symfony\Component\HttpFoundation\RequestStack;
1717
use Symfony\Component\HttpFoundation\Response;
18-
use Symfony\Component\HttpKernel\Attribute\HttpException;
1918
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
2019
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
2120
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
@@ -240,18 +239,7 @@ private function handleThrowable(\Throwable $e, Request $request, int $type): Re
240239
$response->setStatusCode($e->getStatusCode());
241240
$response->headers->add($e->getHeaders());
242241
} else {
243-
$class = new \ReflectionClass($e);
244-
$attributes = $class->getAttributes(HttpException::class, \ReflectionAttribute::IS_INSTANCEOF);
245-
246-
if (0 === \count($attributes)) {
247-
$response->setStatusCode(500);
248-
} else {
249-
/** @var HttpException $instance */
250-
$instance = $attributes[0]->newInstance();
251-
252-
$response->setStatusCode($instance->statusCode);
253-
$response->headers->add($instance->headers);
254-
}
242+
$response->setStatusCode(500);
255243
}
256244
}
257245

src/Symfony/Component/HttpKernel/Tests/EventListener/ErrorListenerTest.php

+77
19
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
use Symfony\Component\EventDispatcher\EventDispatcher;
1818
use Symfony\Component\HttpFoundation\Request;
19
use Symfony\Component\HttpFoundation\Response;
20+
use Symfony\Component\HttpKernel\Attribute\HttpException;
21+
use Symfony\Component\HttpKernel\Attribute\HttpException\NotFound;
2022
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
2123
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
2224
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
@@ -117,6 +119,36 @@ public function testHandleWithLoggerAndCustomConfiguration()
117119
$this->assertCount(1, $logger->getLogs('warning'));
118120
}
119121

122+
/**
123+
* @dataProvider exceptionWithAttributeProvider
124+
*/
125+
public function testHandleHttpAttribute(\Throwable $exception, int $expectedStatusCode, array $expectedHeaders)
126+
{
127+
$request = new Request();
128+
$event = new ExceptionEvent(new TestKernel(), $request, HttpKernelInterface::MAIN_REQUEST, $exception);
129+
$l = new ErrorListener('not used');
130+
$l->logKernelException($event);
131+
$l->onKernelException($event);
132+
133+
$this->assertEquals(new Response('foo', $expectedStatusCode, $expectedHeaders), $event->getResponse());
134 F438 +
}
135+
136+
public function testHandleCustomConfigurationAndHttpAttribute()
137+
{
138+
$request = new Request();
139+
$event = new ExceptionEvent(new TestKernel(), $request, HttpKernelInterface::MAIN_REQUEST, new NotFoundHttpExceptionWithAttribute());
140+
$l = new ErrorListener('not used', null, false, [
141+
NotFoundHttpExceptionWithAttribute::class => [
142+
'log_level' => 'warning',
143+
'status_code' => 401,
144+
],
145+
]);
146+
$l->logKernelException($event);
147+
$l->onKernelException($event);
148+
149+
$this->assertEquals(new Response('foo', 401), $event->getResponse());
150+
}
151+
120152
public function provider()
121153
{
122154
if (!class_exists(Request::class)) {
@@ -216,6 +248,13 @@ public function controllerProvider()
216248
return new Response('OK: '.$exception->getMessage());
217249
}];
218250
}
251+
252+
public function exceptionWithAttributeProvider()
253+
{
254+
yield [new NotFoundHttpExceptionWithAttribute(), 404, ['resource' => 'example']];
255+
yield [new WithCustomUserProvidedAttribute(), 208, ['name' => 'value']];
256+
yield [new WithGeneralAttribute(), 412, ['some' => 'thing']];
257+
}
219258
}
220259

221260
class TestLogger extends Logger implements DebugLoggerInterface
@@ -246,3 +285,41 @@ public function handle(Request $request, $type = self::MAIN_REQUEST, $catch = tr
246285
throw new \RuntimeException('bar');
247286
}
248287
}
288+
289+
#[NotFound(
290+
headers: [
291+
'resource' => 'example',
292+
]
293+
)]
294+
class NotFoundHttpExceptionWithAttribute extends \Exception
295+
{
296+
}
297+
298+
#[\Attribute(\Attribute::TARGET_CLASS)]
299+
class UserProvidedHttpStatusCodeAttribute extends HttpException
300+
{
301+
public function __construct(array $headers = [])
302+
{
303+
parent::__construct(
304+
Response::HTTP_ALREADY_REPORTED,
305+
$headers
306+
);
307+
}
308+
}
309+
310+
#[UserProvidedHttpStatusCodeAttribute(headers: [
311+
'name' => 'value',
312+
])]
313+
class WithCustomUserProvidedAttribute extends \Exception
314+
{
315+
}
316+
317+
#[HttpException(
318+
statusCode: Response::HTTP_PRECONDITION_FAILED,
319+
headers: [
320+
'some' => 'thing',
321+
]
322+
)]
323+
class WithGeneralAttribute extends \Exception
324+
{
325+
}

src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php

-82
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818
use Symfony\Component\HttpFoundation\Request;
1919
use Symfony\Component\HttpFoundation\RequestStack;
2020
use Symfony\Component\HttpFoundation\Response;
21-
use Symfony\Component\HttpKernel\Attribute\HttpException;
22-
use Symfony\Component\HttpKernel\Attribute\HttpException\NotFound;
2321
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
2422
use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface;
2523
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
@@ -236,48 +234,6 @@ public function testHandleHttpException()
236234
$this->assertEquals('POST', $response->headers->get('Allow'));
237235
}
238236

239-
public function testHandleExceptionWithSpecificHttpAttribute()
240-
{
241-
$dispatcher = new EventDispatcher();
242-
$dispatcher->addListener(KernelEvents::EXCEPTION, function (ExceptionEvent $event) {
243-
$event->setResponse(new Response());
244-
});
245-
246-
$kernel = $this->getHttpKernel($dispatcher, function () { throw new NotFoundHttpExceptionWithAttribute(); });
247-
$response = $kernel->handle(new Request());
248-
249-
$this->assertEquals('404', $response->getStatusCode());
250-
$this->assertEquals('example', $response->headers->get('resource'));
251-
}
252-
253-
public function testHandleExceptionWithUserProvidedHttpAttribute()
254-
{
255-
$dispatcher = new EventDispatcher();
256-
$dispatcher->addListener(KernelEvents::EXCEPTION, function (ExceptionEvent $event) {
257-
$event->setResponse(new Response());
258-
});
259-
260-
$kernel = $this->getHttpKernel($dispatcher, function () { throw new WithCustomUserProvidedAttribute(); });
261-
$response = $kernel->handle(new Request());
262-
263-
$this->assertEquals('208', $response->getStatusCode());
264-
$this->assertEquals('value', $response->headers->get('name'));
265-
}
266-
267-
public function testHandleExceptionWithGeneralHttpAttribute()
268-
{
269-
$dispatcher = new EventDispatcher();
270-
$dispatcher->addListener(KernelEvents::EXCEPTION, function (ExceptionEvent $event) {
271-
$event->setResponse(new Response());
272-
});
273-
274-
$kernel = $this->getHttpKernel($dispatcher, function () { throw new WithGeneralAttribute(); });
275-
$response = $kernel->handle(new Request());
276-
277-
$this->assertEquals('412', $response->getStatusCode());
278-
$this->assertEquals('thing', $response->headers->get('some'));
279-
}
280-
281237
public function getStatusCodes()
282238
{
283239
return [
@@ -569,41 +525,3 @@ function controller_func()
569525
{
570526
return new Response('foo');
571527
}
572-
573-
#[NotFound(
574-
headers: [
575-
'resource' => 'example',
576-
]
577-
)]
578-
class NotFoundHttpExceptionWithAttribute extends \Exception
579-
{
580-
}
581-
582-
#[\Attribute(\Attribute::TARGET_CLASS)]
583-
class UserProvidedHttpStatusCodeAttribute extends HttpException
584-
{
585-
public function __construct(array $headers = [])
586-
{
587-
parent::__construct(
588-
Response::HTTP_ALREADY_REPORTED,
589-
$headers
590-
);
591-
}
592-
}
593-
594-
#[UserProvidedHttpStatusCodeAttribute(headers: [
595-
'name' => 'value',
596-
])]
597-
class WithCustomUserProvidedAttribute extends \Exception
598-
{
599-
}
600-
601-
#[HttpException(
602-
statusCode: Response::HTTP_PRECONDITION_FAILED,
603-
headers: [
604-
'some' => 'thing',
605-
]
606-
)]
607-
class WithGeneralAttribute extends \Exception
608-
{
609-
}

0 commit comments

Comments
 (0)
0