Skip to content

Commit

Permalink
fix: handle single array mapping when a superfluous value is present
Browse files Browse the repository at this point in the history
  • Loading branch information
romm committed Mar 15, 2024
1 parent 13b6d01 commit 471ef03
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 12 deletions.
3 changes: 2 additions & 1 deletion src/Library/Container.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ public function __construct(Settings $settings)
$this->get(ClassDefinitionRepository::class),
$this->get(ObjectBuilderFactory::class),
$this->get(ObjectNodeBuilder::class),
$settings->enableFlexibleCasting
$settings->enableFlexibleCasting,
$settings->allowSuperfluousKeys,
);

$builder = new CasterProxyNodeBuilder($builder);
Expand Down
16 changes: 8 additions & 8 deletions src/Mapper/Object/ArgumentsValues.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,22 @@ private function __construct(Arguments $arguments)
$this->arguments = $arguments;
}

public static function forInterface(Arguments $arguments, mixed $value): self
public static function forInterface(Arguments $arguments, mixed $value, bool $allowSuperfluousKeys): self
{
$self = new self($arguments);
$self->forInterface = true;

if (count($arguments) > 0) {
$self = $self->transform($value);
$self = $self->transform($value, $allowSuperfluousKeys);
}

return $self;
}

public static function forClass(Arguments $arguments, mixed $value): self
public static function forClass(Arguments $arguments, mixed $value, bool $allowSuperfluousKeys): self
{
$self = new self($arguments);
$self = $self->transform($value);
$self = $self->transform($value, $allowSuperfluousKeys);

return $self;
}
Expand Down Expand Up @@ -82,11 +82,11 @@ public function hadSingleArgument(): bool
return $this->hadSingleArgument;
}

private function transform(mixed $value): self
private function transform(mixed $value, bool $allowSuperfluousKeys): self
{
$clone = clone $this;

$transformedValue = $this->transformValueForSingleArgument($value);
$transformedValue = $this->transformValueForSingleArgument($value, $allowSuperfluousKeys);

if (! is_array($transformedValue)) {
throw new InvalidSource($transformedValue, $this->arguments);
Expand All @@ -109,7 +109,7 @@ private function transform(mixed $value): self
return $clone;
}

private function transformValueForSingleArgument(mixed $value): mixed
private function transformValueForSingleArgument(mixed $value, bool $allowSuperfluousKeys): mixed
{
if (count($this->arguments) !== 1) {
return $value;
Expand All @@ -122,7 +122,7 @@ private function transformValueForSingleArgument(mixed $value): mixed
&& $type->keyType() !== ArrayKeyType::integer();

if (is_array($value) && array_key_exists($name, $value)) {
if ($this->forInterface || ! $isTraversableAndAllowsStringKeys || count($value) === 1) {
if ($this->forInterface || ! $isTraversableAndAllowsStringKeys || $allowSuperfluousKeys || count($value) === 1) {
return $value;
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/Mapper/Tree/Builder/InterfaceNodeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public function __construct(
private ClassDefinitionRepository $classDefinitionRepository,
private ObjectBuilderFactory $objectBuilderFactory,
private ObjectNodeBuilder $objectNodeBuilder,
private bool $enableFlexibleCasting
private bool $enableFlexibleCasting,
private bool $allowSuperfluousKeys,
) {}

public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
Expand Down Expand Up @@ -116,7 +117,7 @@ private function transformSourceForClass(Shell $shell, Arguments $interfaceArgum
*/
private function children(Shell $shell, Arguments $arguments, RootNodeBuilder $rootBuilder): array
{
$arguments = ArgumentsValues::forInterface($arguments, $shell->value());
$arguments = ArgumentsValues::forInterface($arguments, $shell->value(), $this->allowSuperfluousKeys);

$children = [];

Expand Down
2 changes: 1 addition & 1 deletion src/Mapper/Tree/Builder/ObjectNodeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public function __construct(private bool $allowSuperfluousKeys) {}

public function build(ObjectBuilder $builder, Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
{
$arguments = ArgumentsValues::forClass($builder->describeArguments(), $shell->value());
$arguments = ArgumentsValues::forClass($builder->describeArguments(), $shell->value(), $this->allowSuperfluousKeys);

$children = $this->children($shell, $arguments, $rootBuilder);

Expand Down
20 changes: 20 additions & 0 deletions tests/Integration/Mapping/Other/SuperfluousKeysMappingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,26 @@ public function test_single_list_property_node_can_be_mapped_(): void

self::assertSame([7, 8, 9], $result->values);
}

public function test_object_with_one_array_property_can_be_mapped_when_superfluous_key_is_present(): void
{
$class = new class () {
/** @var array<string> */
public array $values;
};

try {
$result = $this->mapper->map($class::class, [
'values' => ['foo', 'bar'],
'superfluous_key' => 'useless value',
]);
} catch (MappingError $error) {
$this->mappingFail($error);
}

self::assertSame('foo', $result->values[0]);
self::assertSame('bar', $result->values[1]);
}
}

final class UnionOfBarAndFizAndFoo
Expand Down

0 comments on commit 471ef03

Please sign in to comment.