Skip to content

Commit

Permalink
improve projection errors and traces
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidBadura committed Feb 2, 2024
1 parent 137f05c commit 64cc693
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 3 deletions.
17 changes: 16 additions & 1 deletion phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ parameters:
path: src/Projection/Projection/ProjectionError.php

-
message: "#^Parameter \\#2 \\$errorContext of class Patchlevel\\\\EventSourcing\\\\Projection\\\\Projection\\\\ProjectionError constructor expects array\\<int, array\\{message\\: string, code\\: int\\|string, file\\: string, line\\: int, trace\\: array\\<int, array\\{file\\?\\: string, line\\?\\: int, function\\?\\: string, class\\?\\: string, type\\?\\: string, args\\?\\: array\\}\\>\\}\\>\\|null, mixed given\\.$#"
message: "#^Parameter \\#2 \\$errorContext of class Patchlevel\\\\EventSourcing\\\\Projection\\\\Projection\\\\ProjectionError constructor expects array\\<int, array\\{class\\: class\\-string, message\\: string, code\\: int\\|string, file\\: string, line\\: int, trace\\: array\\<int, array\\{file\\?\\: string, line\\?\\: int, function\\?\\: string, class\\?\\: string, type\\?\\: string, args\\?\\: array\\}\\>\\}\\>\\|null, mixed given\\.$#"
count: 1
path: src/Projection/Projection/Store/DoctrineStore.php

Expand All @@ -30,6 +30,21 @@ parameters:
count: 1
path: src/Projection/Projection/Store/ErrorContext.php

-
message: "#^Method Patchlevel\\\\EventSourcing\\\\Projection\\\\Projection\\\\Store\\\\ErrorContext\\:\\:transformTrace\\(\\) has parameter \\$trace with no value type specified in iterable type array\\.$#"
count: 1
path: src/Projection/Projection/Store/ErrorContext.php

-
message: "#^Method Patchlevel\\\\EventSourcing\\\\Projection\\\\Projection\\\\Store\\\\ErrorContext\\:\\:transformTrace\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: src/Projection/Projection/Store/ErrorContext.php

-
message: "#^PHPDoc tag @var for variable \\$trace has no value type specified in iterable type array\\.$#"
count: 1
path: src/Projection/Projection/Store/ErrorContext.php

-
message: "#^Method Patchlevel\\\\EventSourcing\\\\Projection\\\\Projector\\\\InMemoryProjectorRepository\\:\\:projectors\\(\\) should return array\\<int, object\\> but returns array\\<int\\|string, object\\>\\.$#"
count: 1
Expand Down
34 changes: 32 additions & 2 deletions src/Projection/Projection/Store/ErrorContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@

use Throwable;

use function array_walk_recursive;
use function get_resource_type;
use function is_object;
use function is_resource;
use function sprintf;

/**
* @psalm-type Trace = array{file?: string, line?: int, function?: string, class?: string, type?: string, args?: array}
* @psalm-type Context = array{message: string, code: int|string, file: string, line: int, trace: list<Trace>}
* @psalm-type Context = array{class: class-string, message: string, code: int|string, file: string, line: int, trace: list<Trace>}
*/
final class ErrorContext
{
Expand All @@ -29,11 +35,35 @@ public static function fromThrowable(Throwable $error): array
private static function transformThrowable(Throwable $error): array
{
return [
'class' => $error::class,
'message' => $error->getMessage(),
'code' => $error->getCode(),
'file' => $error->getFile(),
'line' => $error->getLine(),
'trace' => $error->getTrace(),
'trace' => self::transformTrace($error->getTrace()),
];
}

/**
* @param list<Trace> $trace
*
* @return list<Trace>
*/
private static function transformTrace(array $trace): array
{
array_walk_recursive($trace, static function (mixed &$value): void {
if (is_object($value)) {
$value = sprintf('object(%s)', $value::class);
}

if (!is_resource($value)) {
return;
}

$value = sprintf('resource(%s)', get_resource_type($value));
});

/** @var list<Trace> $trace */
return $trace;
}
}
72 changes: 72 additions & 0 deletions tests/Unit/Projection/Projection/ErrorContextTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

declare(strict_types=1);

namespace Patchlevel\EventSourcing\Tests\Unit\Projection\Projection;

use Patchlevel\EventSourcing\Aggregate\CustomId;
use Patchlevel\EventSourcing\Projection\Projection\Store\ErrorContext;
use PHPUnit\Framework\TestCase;
use RuntimeException;

use function count;
use function fclose;
use function fopen;

final class ErrorContextTest extends TestCase
{
public function testErrorContext(): void
{
$resource = fopen('php://memory', 'r');
$result = ErrorContext::fromThrowable(
$this->createException(
'test',
new CustomId('test'),
$resource,
['test' => [1, 2, 3]],
static fn () => null,
),
);
fclose($resource);

$this->assertCount(1, $result);
$error = $result[0];

$this->assertSame(RuntimeException::class, $error['class']);
$this->assertSame('test', $error['message']);
$this->assertSame(0, $error['code']);
$this->assertSame(__FILE__, $error['file']);
$this->assertGreaterThan(0, count($error['trace']));
$this->assertArrayHasKey(0, $error['trace']);

$firstTrace = $error['trace'][0];

$this->assertArrayHasKey('file', $firstTrace);
$this->assertSame(__FILE__, $firstTrace['file'] ?? null);
$this->assertArrayHasKey('line', $firstTrace);
$this->assertSame('createException', $firstTrace['function'] ?? null);
$this->assertArrayHasKey('class', $firstTrace);
$this->assertSame(self::class, $firstTrace['class'] ?? null);
$this->assertArrayHasKey('type', $firstTrace);
$this->assertSame('->', $firstTrace['type'] ?? null);
$this->assertArrayHasKey('args', $firstTrace);
$this->assertSame([
'test',
'object(Patchlevel\EventSourcing\Aggregate\CustomId)',
'resource(stream)',
['test' => [1, 2, 3]],
'object(Closure)',
], $firstTrace['args'] ?? null);
}

/** @param resource $resource */
private function createException(
string $message,
CustomId $id,
$resource,
array $array,
callable $callable,
): RuntimeException {
return new RuntimeException($message);
}
}

0 comments on commit 64cc693

Please sign in to comment.