Skip to content

Commit

Permalink
Fix error on create object by incompatible parameters in `HydratorTyp…
Browse files Browse the repository at this point in the history
…eCaster` + More tests (#59)
  • Loading branch information
vjik committed Oct 26, 2023
1 parent 4460cf7 commit 40ee56e
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 7 deletions.
13 changes: 6 additions & 7 deletions src/TypeCaster/HydratorTypeCaster.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

namespace Yiisoft\Hydrator\TypeCaster;

use ReflectionClass;
use ReflectionNamedType;
use ReflectionUnionType;
use Yiisoft\Hydrator\Exception\NonInstantiableException;
use Yiisoft\Hydrator\HydratorInterface;
use Yiisoft\Hydrator\Result;

Expand Down Expand Up @@ -56,13 +56,12 @@ private function castInternal(array $value, ReflectionNamedType $type, HydratorI

$class = $type->getName();

$reflection = new ReflectionClass($class);
if ($reflection->isInstantiable()) {
return Result::success(
$hydrator->create($class, $value)
);
try {
$object = $hydrator->create($class, $value);
} catch (NonInstantiableException) {
return Result::fail();
}

return Result::fail();
return Result::success($object);
}
}
12 changes: 12 additions & 0 deletions tests/Support/PrivateConstructorObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Hydrator\Tests\Support;

final class PrivateConstructorObject
{
private function __construct()
{
}
}
61 changes: 61 additions & 0 deletions tests/TestEnvironments/Php82/TypeCaster/HydratorTypeCasterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

declare(strict_types=1);

namespace TypeCaster;

use Closure;
use Countable;
use PHPUnit\Framework\TestCase;
use ReflectionFunction;
use Stringable;
use Yiisoft\Hydrator\Hydrator;
use Yiisoft\Hydrator\Result;
use Yiisoft\Hydrator\Tests\Support\StringableObject;
use Yiisoft\Hydrator\TypeCaster\HydratorTypeCaster;
use Yiisoft\Hydrator\TypeCaster\TypeCastContext;

final class HydratorTypeCasterTest extends TestCase
{
public function dataBase(): array
{
return [
'array to intersection type' => [
Result::fail(),
['string' => 'hello'],
$this->createContext(static fn(Stringable&Countable $object) => null),
],
'array to union type with intersection type' => [
Result::success(new StringableObject('hello')),
['string' => 'hello'],
$this->createContext(static fn(StringableObject|(Stringable&Countable) $object) => null),
],
'incompatible array to union type with intersection type' => [
Result::fail(),
['var' => 'hello'],
$this->createContext(static fn(StringableObject|(Stringable&Countable) $object) => null),
],
];
}

/**
* @dataProvider dataBase
*/
public function testBase(Result $expected, mixed $value, TypeCastContext $context): void
{
$typeCaster = new HydratorTypeCaster();

$result = $typeCaster->cast($value, $context);

$this->assertSame($expected->isResolved(), $result->isResolved());
$this->assertEquals($expected->getValue(), $result->getValue());
}

private function createContext(Closure $fn): TypeCastContext
{
return new TypeCastContext(
new Hydrator(),
(new ReflectionFunction($fn))->getParameters()[0],
);
}
}
80 changes: 80 additions & 0 deletions tests/TypeCaster/HydratorTypeCasterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Hydrator\Tests\TypeCaster;

use Closure;
use PHPUnit\Framework\TestCase;
use ReflectionFunction;
use Yiisoft\Hydrator\Hydrator;
use Yiisoft\Hydrator\Result;
use Yiisoft\Hydrator\Tests\Support\PrivateConstructorObject;
use Yiisoft\Hydrator\Tests\Support\StringableObject;
use Yiisoft\Hydrator\TypeCaster\HydratorTypeCaster;
use Yiisoft\Hydrator\TypeCaster\TypeCastContext;

final class HydratorTypeCasterTest extends TestCase
{
public function dataBase(): array
{
return [
'not array to not array' => [
Result::fail(),
'not array',
$this->createContext(static fn(int $a) => null),
],
'array to not array' => [
Result::fail(),
[5],
$this->createContext(static fn(int $a) => null),
],
'array to without type' => [
Result::fail(),
[5],
$this->createContext(static fn($a) => null),
],
'array to object' => [
Result::success(new StringableObject('hello')),
['string' => 'hello'],
$this->createContext(static fn(StringableObject $object) => null),
],
'array to union type object|int' => [
Result::success(new StringableObject('hello')),
['string' => 'hello'],
$this->createContext(static fn(StringableObject|int $object) => null),
],
'array to union type int|object' => [
Result::success(new StringableObject('hello')),
['string' => 'hello'],
$this->createContext(static fn(int|StringableObject $object) => null),
],
'array to non-instantiable object' => [
Result::fail(),
['string' => 'hello'],
$this->createContext(static fn(PrivateConstructorObject $object) => null),
],
];
}

/**
* @dataProvider dataBase
*/
public function testBase(Result $expected, mixed $value, TypeCastContext $context): void
{
$typeCaster = new HydratorTypeCaster();

$result = $typeCaster->cast($value, $context);

$this->assertSame($expected->isResolved(), $result->isResolved());
$this->assertEquals($expected->getValue(), $result->getValue());
}

private function createContext(Closure $fn): TypeCastContext
{
return new TypeCastContext(
new Hydrator(),
(new ReflectionFunction($fn))->getParameters()[0],
);
}
}

0 comments on commit 40ee56e

Please sign in to comment.