fix: allow missing value for shaped array nullable node in flexible mode

This commit is contained in:
Romain Canon 2022-11-03 20:56:37 +01:00
parent 25ce2188bb
commit 08fb0e17ba
4 changed files with 19 additions and 48 deletions

View File

@ -4,7 +4,6 @@ declare(strict_types=1);
namespace CuyZ\Valinor\Mapper\Tree\Builder;
use CuyZ\Valinor\Mapper\Tree\Exception\ShapedArrayElementMissing;
use CuyZ\Valinor\Mapper\Tree\Exception\SourceMustBeIterable;
use CuyZ\Valinor\Mapper\Tree\Exception\UnexpectedShapedArrayKeys;
use CuyZ\Valinor\Mapper\Tree\Shell;
@ -59,15 +58,12 @@ final class ShapedArrayNodeBuilder implements NodeBuilder
$child = $shell->child((string)$key, $element->type());
if (! array_key_exists($key, $value)) {
if (! $element->isOptional()) {
$children[$key] = TreeNode::error($child, new ShapedArrayElementMissing($element));
}
if (array_key_exists($key, $value)) {
$child = $child->withValue($value[$key]);
} elseif ($element->isOptional()) {
continue;
}
$child = $child->withValue($value[$key]);
$children[$key] = $rootBuilder->build($child);
unset($value[$key]);

View File

@ -1,40 +0,0 @@
<?php
declare(strict_types=1);
namespace CuyZ\Valinor\Mapper\Tree\Exception;
use CuyZ\Valinor\Mapper\Tree\Message\ErrorMessage;
use CuyZ\Valinor\Mapper\Tree\Message\HasParameters;
use CuyZ\Valinor\Type\Types\ShapedArrayElement;
use CuyZ\Valinor\Utility\String\StringFormatter;
use CuyZ\Valinor\Utility\TypeHelper;
use RuntimeException;
/** @internal */
final class ShapedArrayElementMissing extends RuntimeException implements ErrorMessage, HasParameters
{
private string $body = 'Cannot be empty and must be filled with a value matching type {expected_type}.';
/** @var array<string, string> */
private array $parameters;
public function __construct(ShapedArrayElement $element)
{
$this->parameters = [
'expected_type' => TypeHelper::dump($element->type()),
];
parent::__construct(StringFormatter::for($this), 1631613641);
}
public function body(): string
{
return $this->body;
}
public function parameters(): array
{
return $this->parameters;
}
}

View File

@ -171,6 +171,21 @@ final class FlexibleMappingTest extends IntegrationTest
self::assertSame(null, $result->bar);
}
public function test_missing_value_for_nullable_shaped_array_element_fills_it_with_null(): void
{
try {
$result = (new MapperBuilder())->flexible()->mapper()->map(
'array{foo: string, bar: ?string}',
['foo' => 'foo']
);
} catch (MappingError $error) {
$this->mappingFail($error);
}
self::assertSame('foo', $result['foo']);
self::assertSame(null, $result['bar']);
}
public function test_value_that_cannot_be_cast_throws_exception(): void
{
try {

View File

@ -55,7 +55,7 @@ final class ShapedArrayMappingTest extends IntegrationTest
} catch (MappingError $exception) {
$error = $exception->node()->children()['bar']->messages()[0];
self::assertSame('1631613641', $error->code());
self::assertSame('1655449641', $error->code());
self::assertSame('Cannot be empty and must be filled with a value matching type `int`.', (string)$error);
}
}