Skip to content

Commit 207a89d

Browse files
committed
docs: document exception handling
1 parent 497958c commit 207a89d

File tree

1 file changed

+119
-2
lines changed

1 file changed

+119
-2
lines changed
Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,122 @@
11
---
22
title: Exception handling
3-
description: ""
4-
hidden: true
3+
description: "Learn how to gracefully handle exceptions in your application by writing exception processors."
54
---
5+
6+
## Overview
7+
8+
Tempest comes with its own exception handler, which provides a simple way to catch and process exceptions. During local development, Tempest uses [Whoops](https://github.com/filp/whoops) to display detailed error pages. In production, it will show a generic error page.
9+
10+
When an exception is thrown, it will be caught and piped through the registered exception processors. By default, the only registered exception processor, {b`Tempest\Core\LogExceptionProcessor`}, will simply log the exception.
11+
12+
Of course, you may create your own exception processors. This is done by creating a class that implements the {`Tempest\Core\ExceptionProcessor`} interface. Classes implementing this interface are automatically [discovered](../4-internals/02-discovery.md), so you don't need to register them manually.
13+
14+
## Reporting exceptions
15+
16+
Sometimes, you may want to report an exception without necessarily throwing it. For example, you may want to log an exception, but not stop the execution of the application. To do this, you can use the `Tempest\report()` function.
17+
18+
```php
19+
use function Tempest\report;
20+
21+
try {
22+
// Some code that may throw an exception
23+
} catch (SomeException $e) {
24+
report($e);
25+
}
26+
```
27+
28+
## Disabling default logging
29+
30+
Exception processors are discovered when Tempest boots, then stored in the `exceptionProcessors` property of {`Tempest\Core\AppConfig`}. The default logging processor, {b`Tempest\Core\LogExceptionProcessor`}, is automatically added to the list of processors.
31+
32+
To disable exception logging, you may remove it in a `KernelEvent::BOOTED` event handler:
33+
34+
```php
35+
use Tempest\Core\AppConfig;
36+
use Tempest\Core\KernelEvent;
37+
use Tempest\Core\LogExceptionProcessor;
38+
use Tempest\EventBus\EventHandler;
39+
use Tempest\Support\Arr;
40+
41+
final readonly class DisableExceptionLogging
42+
{
43+
public function __construct(
44+
private AppConfig $appConfig,
45+
) {
46+
}
47+
48+
#[EventHandler(KernelEvent::BOOTED)]
49+
public function __invoke(): void
50+
{
51+
Arr\forget_values($this->appConfig->exceptionProcessors, LogExceptionProcessor::class);
52+
}
53+
}
54+
```
55+
56+
## Adding context to exceptions
57+
58+
Sometimes, an exception may have information that you would like to be logged. By implementing the {`Tempest\Core\HasContext`} interface on an exception class, you can provide additional context that will be logged—and available to other processors.
59+
60+
```php
61+
use Tempest\Core\HasContext;
62+
63+
final readonly class UserNotFound extends Exception implements HasContext
64+
{
65+
public function __construct(private string $userId)
66+
{
67+
parent::__construct("User {$userId} not found.");
68+
}
69+
70+
public function context(): array
71+
{
72+
return [
73+
'user_id' => $this->userId,
74+
];
75+
}
76+
}
77+
```
78+
79+
## Customizing the error page
80+
81+
In production, when an uncaught exception occurs, Tempest displays a minimalistic, generic error page. You may customize this behavior by providing your own response to the {b`Tempest\Http\HttpException`}.
82+
83+
For instance, you may display a branded error page by providing a view:
84+
85+
```php
86+
use Tempest\Http\GenericResponse;
87+
use Tempest\Http\HttpException;
88+
use Throwable;
89+
90+
final class UncaughtExceptionProcessor implements ExceptionProcessor
91+
{
92+
public function process(Throwable $throwable): Throwable
93+
{
94+
if ($throwable instanceof HttpException) {
95+
$throwable->response = new GenericResponse(
96+
status: $throwable->status,
97+
body: view('./error.view.php', exception: $throwable),
98+
);
99+
}
100+
101+
return $throwable;
102+
}
103+
}
104+
```
105+
106+
## Testing
107+
108+
By extending {`Tempest\Framework\Testing\IntegrationTest`} from your test case, you gain access to the exception testing utilities, which allow you to make assertions about reported exceptions.
109+
110+
```php
111+
// Prevents exceptions from being actually processed
112+
$this->exceptions->preventReporting();
113+
114+
// Asserts that the exception was reported
115+
$this->exceptions->assertReported(UserNotFound::class);
116+
117+
// Asserts that the exception was not reported
118+
$this->exceptions->assertNotReported(UserNotFound::class);
119+
120+
// Asserts that no exceptions were reported
121+
$this->exceptions->assertNothingReported();
122+
```

0 commit comments

Comments
 (0)