Skip to content

Commit 0e02d4f

Browse files
committed
Support multiple exception
1 parent e325329 commit 0e02d4f

File tree

5 files changed

+70
-16
lines changed

5 files changed

+70
-16
lines changed

src/CompositeException.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Yiisoft\ErrorHandler;
6+
7+
use Exception;
8+
use Throwable;
9+
10+
/**
11+
* Aggregate multiple exceptions into one.
12+
*/
13+
final class CompositeException extends Exception
14+
{
15+
/**
16+
* @var Throwable[]
17+
*/
18+
public array $rest;
19+
20+
public function __construct(
21+
private \Throwable $first,
22+
\Throwable ...$rest,
23+
) {
24+
$this->rest = $rest;
25+
parent::__construct($first->getMessage(), $first->getCode(), $first);
26+
}
27+
28+
public function getFirstException(): Throwable
29+
{
30+
return $this->first;
31+
}
32+
33+
public function getPreviousExceptions(): array
34+
{
35+
return $this->rest;
36+
}
37+
}

src/ErrorHandler.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
use function error_get_last;
1717
use function error_reporting;
1818
use function function_exists;
19-
use function ini_set;
2019
use function http_response_code;
20+
use function ini_set;
2121
use function register_shutdown_function;
2222
use function set_error_handler;
2323
use function set_exception_handler;
@@ -59,9 +59,7 @@ public function handle(
5959
ThrowableRendererInterface $renderer = null,
6060
ServerRequestInterface $request = null
6161
): ErrorData {
62-
if ($renderer === null) {
63-
$renderer = $this->defaultRenderer;
64-
}
62+
$renderer ??= $this->defaultRenderer;
6563

6664
try {
6765
$this->logger->error((string) (new PlainTextRenderer())->renderVerbose($t, $request), ['throwable' => $t]);

src/Middleware/ErrorCatcher.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Psr\Http\Server\MiddlewareInterface;
1414
use Psr\Http\Server\RequestHandlerInterface;
1515
use Throwable;
16+
use Yiisoft\ErrorHandler\CompositeException;
1617
use Yiisoft\ErrorHandler\ErrorHandler;
1718
use Yiisoft\ErrorHandler\Event\ApplicationError;
1819
use Yiisoft\ErrorHandler\HeadersProvider;
@@ -134,7 +135,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
134135
try {
135136
$this->eventDispatcher?->dispatch(new ApplicationError($t));
136137
} catch (Throwable $e) {
137-
// ignore exceptions thrown in event handlers
138+
$t = new CompositeException($e, $t);
138139
}
139140
return $this->generateErrorResponse($t, $request);
140141
}

src/Renderer/HtmlRenderer.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Psr\Http\Message\ServerRequestInterface;
1010
use RuntimeException;
1111
use Throwable;
12+
use Yiisoft\ErrorHandler\CompositeException;
1213
use Yiisoft\ErrorHandler\ErrorData;
1314
use Yiisoft\ErrorHandler\ThrowableRendererInterface;
1415
use Yiisoft\FriendlyException\FriendlyExceptionInterface;
@@ -32,9 +33,9 @@
3233
use function mb_strlen;
3334
use function mb_substr;
3435
use function ob_clean;
36+
use function ob_end_clean;
3537
use function ob_get_clean;
3638
use function ob_get_level;
37-
use function ob_end_clean;
3839
use function ob_implicit_flush;
3940
use function ob_start;
4041
use function realpath;
@@ -212,9 +213,17 @@ public function parseMarkdown(string $content): string
212213
*/
213214
public function renderPreviousExceptions(Throwable $t): string
214215
{
215-
if (($previous = $t->getPrevious()) !== null) {
216-
$templatePath = $this->defaultTemplatePath . '/_previous-exception.php';
217-
return $this->renderTemplate($templatePath, ['throwable' => $previous]);
216+
$templatePath = $this->defaultTemplatePath . '/_previous-exception.php';
217+
218+
if ($t instanceof CompositeException) {
219+
$result=[];
220+
foreach ($t->getPreviousExceptions() as $exception) {
221+
$result[] = $this->renderTemplate($templatePath, ['throwable' => $exception]);
222+
}
223+
return implode($result);
224+
}
225+
if ($t->getPrevious() !== null) {
226+
return $this->renderTemplate($templatePath, ['throwable' => $t->getPrevious()]);
218227
}
219228

220229
return '';

templates/development.php

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php
22

3+
use Yiisoft\ErrorHandler\CompositeException;
34
use Yiisoft\FriendlyException\FriendlyExceptionInterface;
45

56
/**
@@ -10,8 +11,15 @@
1011

1112
$theme = $_COOKIE['yii-exception-theme'] ?? '';
1213

14+
$originalException = $throwable;
15+
if ($throwable instanceof CompositeException) {
16+
$throwable = $throwable->getFirstException();
17+
}
1318
$isFriendlyException = $throwable instanceof FriendlyExceptionInterface;
1419
$solution = $isFriendlyException ? $throwable->getSolution() : null;
20+
$exceptionClass = get_class($throwable);
21+
$exceptionMessage = $throwable->getMessage();
22+
1523
?>
1624
<!doctype html>
1725
<html lang="en">
@@ -42,12 +50,12 @@
4250
</svg>
4351
</a>
4452

45-
<a href="https://stackoverflow.com/search?<?= http_build_query(['q' => $throwable->getMessage()]) ?>" title="Search error on Stackoverflow" target="_blank">
53+
<a href="https://stackoverflow.com/search?<?= http_build_query(['q' => $exceptionMessage]) ?>" title="Search error on Stackoverflow" target="_blank">
4654
<svg width="28" height="32" fill="none" xmlns="http://www.w3.org/2000/svg">
4755
<path d="M23.312 29.151v-8.536h2.849V32H.458008V20.615H3.29701v8.536H23.312zM6.14501 26.307H20.469v-2.848H6.14501v2.848zm.35-6.468L20.47 22.755l.599-2.76-13.96899-2.912-.605 2.756zm1.812-6.74L21.246 19.136l1.203-2.6-12.93699-6.041-1.204 2.584-.001.02zm3.61999-6.38L22.88 15.86l1.813-2.163L13.74 4.562l-1.803 2.151-.01.006zM19 0l-2.328 1.724 8.541 11.473 2.328-1.724L19 0z" fill="#787878"/>
4856
</svg>
4957
</a>
50-
<a href="https://www.google.com/search?<?= http_build_query(['q' => $throwable->getMessage()]) ?>" title="Search error on Google" target="_blank">
58+
<a href="https://www.google.com/search?<?= http_build_query(['q' => $exceptionMessage]) ?>" title="Search error on Google" target="_blank">
5159
<svg width="24" height="24" fill="none" xmlns="http://www.w3.org/2000/svg">
5260
<path d="M23.5313 9.825H12.2407v4.6406h6.45c-.2781 1.5-1.1219 2.7688-2.3937 3.6188-1.075.7187-2.4469 1.1437-4.0594 1.1437-3.12188 0-5.7625-2.1094-6.70625-4.9437-.2375-.7188-.375-1.4875-.375-2.2781 0-.7907.1375-1.5594.375-2.27818.94687-2.83125 3.5875-4.94062 6.70935-4.94062 1.7594 0 3.3375.60625 4.5813 1.79375l3.4375-3.44063C18.1813 1.20312 15.472.015625 12.2407.015625c-4.68435 0-8.73748 2.687495-10.70935 6.606245C.718848 8.24062.256348 10.0719.256348 12.0094s.4625 3.7656 1.275002 5.3843C3.50322 21.3125 7.55635 24 12.2407 24c3.2375 0 5.95-1.075 7.9313-2.9062 2.2656-2.0875 3.575-5.1625 3.575-8.8157 0-.85-.075-1.6656-.2157-2.4531z" fill="#787878"/>
5361
</svg>
@@ -56,24 +64,25 @@
5664

5765
<div class="exception-card">
5866
<div class="exception-class">
59-
<?php if ($isFriendlyException): ?>
67+
<?php
68+
if ($isFriendlyException): ?>
6069
<span><?= $this->htmlEncode($throwable->getName())?></span>
6170
&mdash;
62-
<?= get_class($throwable) ?>
71+
<?= $exceptionClass ?>
6372
<?php else: ?>
64-
<span><?= get_class($throwable) ?></span>
73+
<span><?= $exceptionClass ?></span>
6574
<?php endif ?>
6675
</div>
6776

6877
<div class="exception-message">
69-
<?= nl2br($this->htmlEncode($throwable->getMessage())) ?>
78+
<?= nl2br($this->htmlEncode($exceptionMessage)) ?>
7079
</div>
7180

7281
<?php if ($solution !== null): ?>
7382
<div class="solution"><?= $this->parseMarkdown($solution) ?></div>
7483
<?php endif ?>
7584

76-
<?= $this->renderPreviousExceptions($throwable) ?>
85+
<?= $this->renderPreviousExceptions($originalException) ?>
7786

7887
<textarea id="clipboard"><?= $this->htmlEncode($throwable) ?></textarea>
7988
<span id="copied">Copied!</span>

0 commit comments

Comments
 (0)