Valinor/tests/Unit/Mapper/MappingErrorTest.php

22 lines
449 B
PHP
Raw Normal View History

feat!: add access to root node when error occurs during mapping When an error occurs during mapping, the root instance of `Node` can now be accessed from the exception. This recursive object allows retrieving all needed information through the whole mapping tree: path, values, types and messages, including the issues that caused the exception. It can be used like the following: ```php try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { // Do something with `$error->node()` // See README for more information } ``` This change removes the method `MappingError::describe()` which provided a flattened view of messages of all the errors that were encountered during the mapping. The same behaviour can still be retrieved, see the example below: ```php use CuyZ\Valinor\Mapper\Tree\Message\Message; use CuyZ\Valinor\Mapper\Tree\Node; /** * @implements \IteratorAggregate<string, array<\Throwable&Message>> */ final class MappingErrorList implements \IteratorAggregate { private Node $node; public function __construct(Node $node) { $this->node = $node; } /** * @return \Traversable<string, array<\Throwable&Message>> */ public function getIterator(): \Traversable { yield from $this->errors($this->node); } /** * @return \Traversable<string, array<\Throwable&Message>> */ private function errors(Node $node): \Traversable { $errors = array_filter( $node->messages(), static fn (Message $m) => $m instanceof \Throwable ); if (! empty($errors)) { yield $node->path() => array_values($errors); } foreach ($node->children() as $child) { yield from $this->errors($child); } } } try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { $errors = iterator_to_array(new MappingErrorList($error->node())); } ``` The class `CannotMapObject` is deleted, as it does not provide any value; this means that `MappingError` which was previously an interface becomes a class.
2021-12-16 00:00:45 +01:00
<?php
declare(strict_types=1);
namespace CuyZ\Valinor\Tests\Unit\Mapper;
use CuyZ\Valinor\Mapper\MappingError;
use CuyZ\Valinor\Tests\Fake\Mapper\FakeNode;
feat!: add access to root node when error occurs during mapping When an error occurs during mapping, the root instance of `Node` can now be accessed from the exception. This recursive object allows retrieving all needed information through the whole mapping tree: path, values, types and messages, including the issues that caused the exception. It can be used like the following: ```php try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { // Do something with `$error->node()` // See README for more information } ``` This change removes the method `MappingError::describe()` which provided a flattened view of messages of all the errors that were encountered during the mapping. The same behaviour can still be retrieved, see the example below: ```php use CuyZ\Valinor\Mapper\Tree\Message\Message; use CuyZ\Valinor\Mapper\Tree\Node; /** * @implements \IteratorAggregate<string, array<\Throwable&Message>> */ final class MappingErrorList implements \IteratorAggregate { private Node $node; public function __construct(Node $node) { $this->node = $node; } /** * @return \Traversable<string, array<\Throwable&Message>> */ public function getIterator(): \Traversable { yield from $this->errors($this->node); } /** * @return \Traversable<string, array<\Throwable&Message>> */ private function errors(Node $node): \Traversable { $errors = array_filter( $node->messages(), static fn (Message $m) => $m instanceof \Throwable ); if (! empty($errors)) { yield $node->path() => array_values($errors); } foreach ($node->children() as $child) { yield from $this->errors($child); } } } try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { $errors = iterator_to_array(new MappingErrorList($error->node())); } ``` The class `CannotMapObject` is deleted, as it does not provide any value; this means that `MappingError` which was previously an interface becomes a class.
2021-12-16 00:00:45 +01:00
use PHPUnit\Framework\TestCase;
final class MappingErrorTest extends TestCase
{
public function test_node_can_be_retrieved(): void
{
$node = FakeNode::any();
feat!: add access to root node when error occurs during mapping When an error occurs during mapping, the root instance of `Node` can now be accessed from the exception. This recursive object allows retrieving all needed information through the whole mapping tree: path, values, types and messages, including the issues that caused the exception. It can be used like the following: ```php try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { // Do something with `$error->node()` // See README for more information } ``` This change removes the method `MappingError::describe()` which provided a flattened view of messages of all the errors that were encountered during the mapping. The same behaviour can still be retrieved, see the example below: ```php use CuyZ\Valinor\Mapper\Tree\Message\Message; use CuyZ\Valinor\Mapper\Tree\Node; /** * @implements \IteratorAggregate<string, array<\Throwable&Message>> */ final class MappingErrorList implements \IteratorAggregate { private Node $node; public function __construct(Node $node) { $this->node = $node; } /** * @return \Traversable<string, array<\Throwable&Message>> */ public function getIterator(): \Traversable { yield from $this->errors($this->node); } /** * @return \Traversable<string, array<\Throwable&Message>> */ private function errors(Node $node): \Traversable { $errors = array_filter( $node->messages(), static fn (Message $m) => $m instanceof \Throwable ); if (! empty($errors)) { yield $node->path() => array_values($errors); } foreach ($node->children() as $child) { yield from $this->errors($child); } } } try { (new \CuyZ\Valinor\MapperBuilder()) ->mapper() ->map(SomeClass::class, [/* ... */]); } catch (\CuyZ\Valinor\Mapper\MappingError $error) { $errors = iterator_to_array(new MappingErrorList($error->node())); } ``` The class `CannotMapObject` is deleted, as it does not provide any value; this means that `MappingError` which was previously an interface becomes a class.
2021-12-16 00:00:45 +01:00
$mappingError = new MappingError($node);
self::assertSame($node, $mappingError->node());
}
}