Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## 4.1.1 under development

- no changes in this release.
- Enh #150: Cleanup templates, remove legacy code (@vjik)

## 4.1.0 April 18, 2025

Expand Down
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2",
"httpsoft/http-message": "^1.1.6",
"phpunit/phpunit": "^10.5.45",
"phpunit/phpunit": "^10.5.51",
"psr/event-dispatcher": "^1.0",
"rector/rector": "^2.0.11",
"rector/rector": "^2.1.3",
"roave/infection-static-analysis-plugin": "^1.35",
"spatie/phpunit-watcher": "^1.24",
"vimeo/psalm": "^5.26.1 || ^6.9.1",
"yiisoft/di": "^1.3",
"vimeo/psalm": "^5.26.1 || ^6.13.1",
"yiisoft/di": "^1.4",
"yiisoft/test-support": "^3.0.2"
},
"autoload": {
Expand Down
1 change: 1 addition & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
>
<projectFiles>
<directory name="src" />
<directory name="templates" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
Expand Down
12 changes: 10 additions & 2 deletions src/Exception/ErrorException.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,16 @@

/**
* `ErrorException` represents a PHP error.
* @psalm-type DebugBacktraceType = list<array{args?:list<mixed>,class?:class-string,file?:string,function:string,line?:int,object?:object,type?:string}>
*
* @psalm-type DebugBacktraceType = list<array{
* args?: array<mixed>,
* class?: class-string,
* file?: string,
* function?: string,
* line?: int,
* object?: object,
* type?: string
* }>
*
* @final
*/
Expand Down Expand Up @@ -121,7 +130,6 @@ private function addXDebugTraceToFatalIfAvailable(): void
}

$ref = new ReflectionProperty(Exception::class, 'trace');
$ref->setAccessible(true);
$ref->setValue($this, $trace);
}
}
Expand Down
6 changes: 2 additions & 4 deletions src/Renderer/HtmlRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ final class HtmlRenderer implements ThrowableRendererInterface
private readonly int $maxTraceLines;

/**
* @var string|null The trace header line with placeholders to be be substituted. Defaults to null.
* @var string|null The trace header line with placeholders to be substituted. Defaults to null.
*
* The placeholders are {file}, {line} and {icon}. A typical use case is the creation of IDE-specific links,
* since when you click on a trace header link, it opens directly in the IDE. You can also insert custom content.
Expand All @@ -97,7 +97,7 @@ final class HtmlRenderer implements ThrowableRendererInterface
* <a href="ide://open?file={file}&line={line}">{icon}</a>
* ```
*/
private readonly ?string $traceHeaderLine;
public readonly ?string $traceHeaderLine;

/**
* @var string[]|null The list of vendor paths is determined automatically.
Expand Down Expand Up @@ -632,8 +632,6 @@ private function groupVendorCallStackItems(array $items): array
$groupedItems[$groupIndex][$index] = $item;
}

/** @psalm-var array<int, array<int, string>> $groupedItems It's needed for Psalm <=4.30 only. */

return $groupedItems;
}

Expand Down
11 changes: 7 additions & 4 deletions templates/_call-stack-item.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* @var array $args
* @var bool $isVendorFile
* @var ReflectionMethod[] $reflectionParameters
* @var HtmlRenderer $this
*/

$icon = <<<HTML
Expand All @@ -24,16 +23,20 @@
<path d="M16,5h1.58l-6.29,6.28a1,1,0,0,0,0,1.42,1,1,0,0,0,1.42,0L19,6.42V8a1,1,0,0,0,1,1h0a1,1,0,0,0,1-1V4a1,1,0,0,0-1-1L16,3h0a1,1,0,0,0,0,2Z" />
</svg>
HTML;

/**
* @var HtmlRenderer $this
*/
?>
<li class="<?= (!empty($lines) && ($index === 1 || !$isVendorFile)) ? 'application ' : '' ?>call-stack-item"
data-line="<?= (int) ($line - $begin) ?>">
data-line="<?= (int) $line - $begin ?>">
<div class="element-wrap">
<div class="flex-1 mw-100">
<?php if ($file !== null): ?>
<span class="file-name">
<?= "{$index}. in {$this->htmlEncode($file)}" ?>
<?php if ($this->traceHeaderLine !== null): ?>
<?= strtr($this->traceHeaderLine, ['{file}' => $file, '{line}' => $line + 1, '{icon}' => $icon]) ?>
<?= strtr($this->traceHeaderLine, ['{file}' => $file, '{line}' => (int) $line + 1, '{icon}' => $icon]) ?>
<?php endif ?>
</span>
<?php endif ?>
Expand Down Expand Up @@ -75,7 +78,7 @@
$<?= $this->htmlEncode(
is_int($key) && isset($reflectionParameters[$key])
? $reflectionParameters[$key]->getName()
: $key
: (string) $key
) ?>
</td>
<td class="functionArguments_type">
Expand Down
36 changes: 24 additions & 12 deletions templates/_call-stack-items.php
Original file line number Diff line number Diff line change
@@ -1,22 +1,34 @@
<?php
/* @var $applicationItems array<int, string> */
/* @var $vendorItemGroups array<int, array<int, string>> */
/* @var $this \Yiisoft\ErrorHandler\Renderer\HtmlRenderer */
$insertItem = static function (array &$items, array $item, int $offset = 0): void {
$itemIndex = array_key_first($item);
foreach (array_keys($items) as $index) {
$offset++;
if ($index === ($itemIndex - 1)) {
break;

use Yiisoft\ErrorHandler\Renderer\HtmlRenderer;

/**
* @psalm-var array<int, string> $applicationItems
* @psalm-var array<int, array<int, string>> $vendorItemGroups
* @var HtmlRenderer $this
*/

$insertItem =
/**
* @psalm-param array<int, string> $items
* @psalm-param non-empty-array<int, string> $item
*/
static function (array &$items, array $item, int $offset = 0): void {
$itemIndex = array_key_first($item);
foreach (array_keys($items) as $index) {
$offset++;
if ($index === ($itemIndex - 1)) {
break;
}
}
}
$items = array_slice($items, 0, $offset, true) + $item + array_slice($items, $offset, null, true);
};
$items = array_slice($items, 0, $offset, true) + $item + array_slice($items, $offset, null, true);
};
foreach ($vendorItemGroups as $key => $vendorItemGroup) {
$count = count($vendorItemGroup);
if ($count === 0) {
continue;
}
/** @psalm-var non-empty-array<int, string> $vendorItemGroup */
if ($count === 1) {
$insertItem($applicationItems, $vendorItemGroup);
continue;
Expand Down
9 changes: 7 additions & 2 deletions templates/_previous-exception.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
<?php
/* @var $throwable \Throwable */
/* @var $this \Yiisoft\ErrorHandler\Renderer\HtmlRenderer */

use Yiisoft\ErrorHandler\Renderer\HtmlRenderer;

/**
* @var Throwable $throwable
* @var HtmlRenderer $this
*/
?>
<div class="previous">
<span class="arrow">&crarr;</span>
Expand Down
17 changes: 9 additions & 8 deletions templates/development.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
use Yiisoft\FriendlyException\FriendlyExceptionInterface;

/**
* @var $this HtmlRenderer
* @var $request ServerRequestInterface|null
* @var $throwable Throwable
* @var ServerRequestInterface|null $request
* @var Throwable $throwable
*/

$theme = $_COOKIE['yii-exception-theme'] ?? '';
Expand All @@ -18,11 +17,13 @@
if ($throwable instanceof CompositeException) {
$throwable = $throwable->getFirstException();
}
$isFriendlyException = $throwable instanceof FriendlyExceptionInterface;
$solution = $isFriendlyException ? $throwable->getSolution() : null;
$solution = $throwable instanceof FriendlyExceptionInterface ? $throwable->getSolution() : null;
$exceptionClass = get_class($throwable);
$exceptionMessage = $throwable->getMessage();

/**
* @var HtmlRenderer $this
*/
?>
<!doctype html>
<html lang="en">
Expand Down Expand Up @@ -78,7 +79,7 @@
<div class="exception-card">
<div class="exception-class">
<?php
if ($isFriendlyException): ?>
if ($throwable instanceof FriendlyExceptionInterface): ?>
<span><?= $this->htmlEncode($throwable->getName())?></span>
&mdash;
<?= $exceptionClass ?>
Expand All @@ -98,12 +99,12 @@

<?= $this->renderPreviousExceptions($originalException) ?>

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

<a href="#"
class="copy-clipboard"
data-clipboard="<?= $this->htmlEncode($throwable) ?>"
data-clipboard="<?= $this->htmlEncode((string) $throwable) ?>"
title="Copy the stacktrace for use in a bug report or pastebin"
>
<svg width="26" height="30" fill="none" xmlns="http://www.w3.org/2000/svg">
Expand Down
8 changes: 6 additions & 2 deletions templates/production.php
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
<?php
/* @var $throwable \Throwable */
/* @var $this \Yiisoft\ErrorHandler\Renderer\HtmlRenderer */

use Yiisoft\ErrorHandler\Exception\UserException;
use Yiisoft\ErrorHandler\Renderer\HtmlRenderer;
use Yiisoft\ErrorHandler\ThrowableRendererInterface;

/**
* @var Throwable $throwable
* @var HtmlRenderer $this
*/

if ($throwable instanceof UserException) {
$name = $this->getThrowableName($throwable);
$message = $throwable->getMessage();
Expand Down
7 changes: 1 addition & 6 deletions tests/Renderer/HtmlRendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -354,18 +354,13 @@ private function invokeMethod(object $object, string $method, array $args = [])
{
$reflection = new ReflectionObject($object);
$method = $reflection->getMethod($method);
$method->setAccessible(true);
$result = $method->invokeArgs($object, $args);
$method->setAccessible(false);
return $result;
return $method->invokeArgs($object, $args);
}

private function setVendorPaths(HtmlRenderer $renderer, array $vendorPaths): void
{
$reflection = new ReflectionClass($renderer);
$property = $reflection->getProperty('vendorPaths');
$property->setAccessible(true);
$property->setValue($renderer, $vendorPaths);
$property->setAccessible(false);
}
}
Loading