Skip to content

Commit

Permalink
Merge pull request #1044 from spiral/feature/ignore-exceptions
Browse files Browse the repository at this point in the history
[spiral/exceptions] Add non-reportable exceptions
  • Loading branch information
butschster committed Jan 3, 2024
2 parents 44459b0 + 8b40155 commit dc1fe0b
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 8 deletions.
10 changes: 10 additions & 0 deletions src/Exceptions/src/Attribute/NonReportable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Spiral\Exceptions\Attribute;

#[\Attribute(\Attribute::TARGET_CLASS)]
class NonReportable
{
}
34 changes: 34 additions & 0 deletions src/Exceptions/src/ExceptionHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
namespace Spiral\Exceptions;

use Closure;
use Spiral\Exceptions\Attribute\NonReportable;
use Spiral\Exceptions\Renderer\PlainRenderer;
use Spiral\Filters\Exception\AuthorizationException;
use Spiral\Filters\Exception\ValidationException;
use Spiral\Http\Exception\ClientException;

/**
* The class is responsible for:
Expand All @@ -24,6 +28,11 @@ class ExceptionHandler implements ExceptionHandlerInterface
/** @var array<int, ExceptionReporterInterface|Closure> */
protected array $reporters = [];
protected mixed $output = null;
protected array $nonReportableExceptions = [
ClientException::class,
AuthorizationException::class,
ValidationException::class,
];

public function __construct()
{
Expand Down Expand Up @@ -64,6 +73,10 @@ public function canRender(string $format): bool

public function report(\Throwable $exception): void
{
if ($this->shouldNotReport($exception)) {
return;
}

foreach ($this->reporters as $reporter) {
try {
if ($reporter instanceof ExceptionReporterInterface) {
Expand Down Expand Up @@ -106,6 +119,14 @@ public function addRenderer(ExceptionRendererInterface $renderer): void
\array_unshift($this->renderers, $renderer);
}

/**
* @param class-string<\Throwable> $exception
*/
public function dontReport(string $exception): void
{
$this->nonReportableExceptions[] = $exception;
}

/**
* @param ExceptionReporterInterface|Closure(\Throwable):void $reporter
*/
Expand Down Expand Up @@ -160,4 +181,17 @@ protected function bootBasicHandlers(): void
{
$this->addRenderer(new PlainRenderer());
}

protected function shouldNotReport(\Throwable $exception): bool
{
foreach ($this->nonReportableExceptions as $nonReportableException) {
if ($exception instanceof $nonReportableException) {
return true;
}
}

$attribute = (new \ReflectionClass($exception))->getAttributes(NonReportable::class)[0] ?? null;

return $attribute !== null;
}
}
56 changes: 56 additions & 0 deletions src/Exceptions/tests/ExceptionHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,19 @@
namespace Spiral\Tests\Exceptions;

use Mockery as m;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use RuntimeException;
use Spiral\Exceptions\ExceptionHandler;
use Spiral\Exceptions\ExceptionRendererInterface;
use Spiral\Exceptions\ExceptionReporterInterface;
use Spiral\Filters\Exception\AuthorizationException;
use Spiral\Filters\Exception\ValidationException;
use Spiral\Http\Exception\ClientException;
use Spiral\Http\Exception\ClientException\ForbiddenException;
use Spiral\Http\Exception\ClientException\NotFoundException;
use Spiral\Http\Exception\ClientException\UnauthorizedException;
use Spiral\Tests\Exceptions\Fixtures\TestException;

class ExceptionHandlerTest extends TestCase
{
Expand Down Expand Up @@ -91,6 +99,38 @@ public function testAllReportersShouldBeCalled(): void
$this->assertTrue(true);
}

#[DataProvider('nonReportableExceptionsDataProvider')]
public function testNonReportableExceptions(\Throwable $exception): void
{
$reporter = $this->createMock(ExceptionReporterInterface::class);
$reporter->expects($this->never())->method('report');

$handler = $this->makeEmptyErrorHandler();
$handler->addReporter($reporter);

$handler->report($exception);
}

public function testAddNonReportableExceptions(): void
{
$handler = $this->makeEmptyErrorHandler();
$ref = new \ReflectionProperty($handler, 'nonReportableExceptions');
$this->assertSame([
ClientException::class,
AuthorizationException::class,
ValidationException::class,
], $ref->getValue($handler));

$handler->dontReport(\DomainException::class);

$this->assertSame([
ClientException::class,
AuthorizationException::class,
ValidationException::class,
\DomainException::class
], $ref->getValue($handler));
}

private function makeEmptyErrorHandler(): ExceptionHandler
{
return new class extends ExceptionHandler {
Expand All @@ -104,4 +144,20 @@ private function makeErrorHandler(): ExceptionHandler
{
return new ExceptionHandler();
}

public static function nonReportableExceptionsDataProvider(): \Traversable
{
yield [new class extends ClientException {}];
yield [new NotFoundException()];
yield [new class extends NotFoundException {}];
yield [new ForbiddenException()];
yield [new class extends ForbiddenException {}];
yield [new UnauthorizedException()];
yield [new class extends UnauthorizedException {}];
yield [new AuthorizationException()];
yield [new class extends AuthorizationException {}];
yield [new ValidationException([])];
yield [new class([]) extends ValidationException {}];
yield [new TestException()];
}
}
12 changes: 12 additions & 0 deletions src/Exceptions/tests/Fixtures/TestException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Spiral\Tests\Exceptions\Fixtures;

use Spiral\Exceptions\Attribute\NonReportable;

#[NonReportable]
class TestException extends \Exception
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

/**
* HTTP 500 exception.
* @deprecated since v3.12
*/
class ServerErrorException extends ClientException
{
Expand Down
8 changes: 0 additions & 8 deletions src/Http/tests/ExceptionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use Spiral\Http\Exception\ClientException\BadRequestException;
use Spiral\Http\Exception\ClientException\ForbiddenException;
use Spiral\Http\Exception\ClientException\NotFoundException;
use Spiral\Http\Exception\ClientException\ServerErrorException;
use Spiral\Http\Exception\ClientException\UnauthorizedException;

class ExceptionsTest extends TestCase
Expand Down Expand Up @@ -46,12 +45,6 @@ public function testUnauthorized(): void
$this->assertSame(401, $e->getCode());
}

public function testServerError(): void
{
$e = new ServerErrorException();
$this->assertSame(500, $e->getCode());
}

#[DataProvider('allExceptionsWithPreviousSet')]
public function testPreviousSetter(\Throwable $exception): void
{
Expand All @@ -63,7 +56,6 @@ public static function allExceptionsWithPreviousSet(): \Generator
yield [new Exception\ClientException\BadRequestException('', new \Exception())];
yield [new Exception\ClientException\ForbiddenException('', new \Exception())];
yield [new Exception\ClientException\NotFoundException('', new \Exception())];
yield [new Exception\ClientException\ServerErrorException('', new \Exception())];
yield [new Exception\ClientException\UnauthorizedException('', new \Exception())];
yield [new Exception\ClientException(0, '', new \Exception())];
yield [new Exception\DotNotFoundException('', 0, new \Exception())];
Expand Down

0 comments on commit dc1fe0b

Please sign in to comment.