Skip to content

Commit

Permalink
fix: detect invalid constructor handle type
Browse files Browse the repository at this point in the history
An exception will now be thrown when a constructor is registered for
an invalid type: something other than a class.
  • Loading branch information
romm committed Aug 29, 2022
1 parent ae7ddcf commit b3cb592
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 1 deletion.
21 changes: 21 additions & 0 deletions src/Mapper/Object/Exception/InvalidClassConstructorType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace CuyZ\Valinor\Mapper\Object\Exception;

use CuyZ\Valinor\Definition\FunctionDefinition;
use CuyZ\Valinor\Type\Type;
use RuntimeException;

/** @internal */
final class InvalidClassConstructorType extends RuntimeException
{
public function __construct(FunctionDefinition $function, Type $type)
{
parent::__construct(
"Invalid type `{$type->toString()}` handled by constructor `{$function->signature()}`. It must be a valid class name.",
1659446121
);
}
}
10 changes: 9 additions & 1 deletion src/Mapper/Object/Factory/ConstructorObjectBuilderFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
use CuyZ\Valinor\Definition\ClassDefinition;
use CuyZ\Valinor\Definition\FunctionsContainer;
use CuyZ\Valinor\Mapper\Object\Exception\CannotInstantiateObject;
use CuyZ\Valinor\Mapper\Object\Exception\InvalidClassConstructorType;
use CuyZ\Valinor\Mapper\Object\FunctionObjectBuilder;
use CuyZ\Valinor\Mapper\Object\MethodObjectBuilder;
use CuyZ\Valinor\Mapper\Object\ObjectBuilder;
use CuyZ\Valinor\Type\Types\ClassType;

use function array_key_exists;
use function array_unshift;
Expand Down Expand Up @@ -70,7 +72,13 @@ private function listBuilders(ClassDefinition $class): array
$methods = $class->methods();

foreach ($this->constructors as $constructor) {
if ($constructor->definition()->returnType()->matches($type)) {
$handledType = $constructor->definition()->returnType();

if (! $handledType instanceof ClassType) {
throw new InvalidClassConstructorType($constructor->definition(), $handledType);
}

if ($handledType->matches($type)) {
$builders[] = new FunctionObjectBuilder($constructor);
}
}
Expand Down
13 changes: 13 additions & 0 deletions tests/Integration/Mapping/ConstructorRegistrationMappingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use CuyZ\Valinor\Mapper\MappingError;
use CuyZ\Valinor\Mapper\Object\Exception\CannotInstantiateObject;
use CuyZ\Valinor\Mapper\Object\Exception\InvalidClassConstructorType;
use CuyZ\Valinor\Mapper\Object\Exception\ObjectBuildersCollision;
use CuyZ\Valinor\MapperBuilder;
use CuyZ\Valinor\Tests\Fake\Mapper\Tree\Message\FakeErrorMessage;
Expand Down Expand Up @@ -387,6 +388,18 @@ public function test_non_registered_named_constructors_are_ignored(): void
->map(SomeClassWithPrivateNativeConstructor::class, []);
}

public function test_invalid_constructor_type_throws_exception(): void
{
$this->expectException(InvalidClassConstructorType::class);
$this->expectExceptionCode(1659446121);
$this->expectExceptionMessageMatches('/Invalid type `string` handled by constructor `.*`\. It must be a valid class name\./');

(new MapperBuilder())
->registerConstructor(fn (): string => 'foo')
->mapper()
->map(stdClass::class, []);
}

public function test_registered_datetime_constructor_is_used(): void
{
$default = new DateTime('@1356097062');
Expand Down

0 comments on commit b3cb592

Please sign in to comment.