Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ class CastToMoney implements PropertyCaster
private string $currency
) {}

public function cast(mixed $value, ObjectMapper $mapper) : mixed
public function cast(mixed $value, ObjectMapper $mapper, ?string $expectedTypeName) : mixed
{
return new Money($value, Currency::fromString($this->currency));
}
Expand All @@ -416,7 +416,7 @@ class CastUnionToType implements PropertyCaster
private array $typeToClassMap
) {}

public function cast(mixed $value, ObjectMapper $mapper) : mixed
public function cast(mixed $value, ObjectMapper $mapper, ?string $expectedTypeName) : mixed
{
assert(is_array($value));

Expand Down
2 changes: 1 addition & 1 deletion src/Fixtures/CastEmptyStringToNull.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#[Attribute(Attribute::TARGET_PROPERTY)]
final class CastEmptyStringToNull implements PropertyCaster
{
public function cast(mixed $value, ObjectMapper $hydrator): mixed
public function cast(mixed $value, ObjectMapper $hydrator, ?string $expectedTypeName): mixed
{
if ($value === '') {
return null;
Expand Down
2 changes: 1 addition & 1 deletion src/Fixtures/CastToClassWithStaticConstructor.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#[Attribute(Attribute::TARGET_PARAMETER)]
final class CastToClassWithStaticConstructor implements PropertyCaster
{
public function cast(mixed $value, ObjectMapper $hydrator): mixed
public function cast(mixed $value, ObjectMapper $hydrator, ?string $expectedTypeName): mixed
{
return $hydrator->hydrateObject(ClassWithStaticConstructor::class, ['name' => $value]);
}
Expand Down
19 changes: 19 additions & 0 deletions src/Fixtures/CastToExpectedType/AuthorId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace EventSauce\ObjectHydrator\Fixtures\CastToExpectedType;

final class AuthorId
{
public function __construct(
private string $id
) {}
public static function fromString(string $id): static
{
return new static($id);
}

public function toString(): string
{
return $this->id;
}
}
19 changes: 19 additions & 0 deletions src/Fixtures/CastToExpectedType/BlogId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace EventSauce\ObjectHydrator\Fixtures\CastToExpectedType;

final class BlogId
{
public function __construct(
private string $id
) {}
public static function fromString(string $id): static
{
return new static($id);
}

public function toString(): string
{
return $this->id;
}
}
15 changes: 15 additions & 0 deletions src/Fixtures/CastToExpectedType/ClassWithIds.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

namespace EventSauce\ObjectHydrator\Fixtures\CastToExpectedType;

final class ClassWithIds
{
public function __construct(
#[IdCaster]
public AuthorId $authorId,
#[IdCaster]
public BlogId $blogId,
)
{
}
}
19 changes: 19 additions & 0 deletions src/Fixtures/CastToExpectedType/IdCaster.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace EventSauce\ObjectHydrator\Fixtures\CastToExpectedType;

use Attribute;
use EventSauce\ObjectHydrator\ObjectMapper;
use EventSauce\ObjectHydrator\PropertyCaster;

#[Attribute(Attribute::TARGET_PROPERTY)]
final class IdCaster implements PropertyCaster
{
public function cast(mixed $value, ObjectMapper $hydrator, ?string $expectedTypeName): mixed
{
if ($expectedTypeName === null) {
throw new \RuntimeException('Expected type name is required');
}
return $expectedTypeName::fromString($value);
}
}
2 changes: 1 addition & 1 deletion src/Fixtures/CastToLowerCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#[Attribute(Attribute::TARGET_PARAMETER)]
final class CastToLowerCase implements PropertyCaster
{
public function cast(mixed $value, ObjectMapper $hydrator): mixed
public function cast(mixed $value, ObjectMapper $hydrator, ?string $expectedTypeName): mixed
{
return strtolower((string) $value);
}
Expand Down
20 changes: 20 additions & 0 deletions src/ObjectHydrationTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

use EventSauce\ObjectHydrator\Fixtures\CastersOnClasses\ClassWithClassLevelMapFrom;
use EventSauce\ObjectHydrator\Fixtures\CastersOnClasses\ClassWithClassLevelMapFromMultiple;
use EventSauce\ObjectHydrator\Fixtures\CastToExpectedType\AuthorId;
use EventSauce\ObjectHydrator\Fixtures\CastToExpectedType\BlogId;
use EventSauce\ObjectHydrator\Fixtures\CastToExpectedType\ClassWithIds;
use EventSauce\ObjectHydrator\Fixtures\ClassThatCastsListsToDifferentTypes;
use EventSauce\ObjectHydrator\Fixtures\ClassThatContainsAnotherClass;
use EventSauce\ObjectHydrator\Fixtures\ClassThatHasMultipleCastersOnSingleProperty;
Expand Down Expand Up @@ -623,6 +626,23 @@ public function hydrating_a_class_with_valid_docblock_array_following_scalar():
self::assertInstanceOf(ClassWithDocblockAndArrayFollowingScalar::class, $object);
}

/**
* @test
*/
public function hydrating_a_class_casting_expected_types(): void {
$hydrator = $this->createObjectHydrator();
$payload = [
'authorId' => 'a',
'blogId' => 'b',
];

$object = $hydrator->hydrateObject(ClassWithIds::class, $payload);

self::assertInstanceOf(ClassWithIds::class, $object);
self::assertInstanceOf(AuthorId::class, $object->authorId);
self::assertInstanceOf(BlogId::class, $object->blogId);
}

/**
* @test
* @see https://github.com/EventSaucePHP/ObjectHydrator/issues/56
Expand Down
2 changes: 1 addition & 1 deletion src/ObjectMapperCodeGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ private function dumpClassHydrator(string $className, ClassHydrationDefinition $
\$$casterName = new \\$caster(...$casterOptions);
}

\$value = \${$casterName}->cast(\$value, \$this);
\$value = \${$casterName}->cast(\$value, \$this, '$definition->firstTypeName');

if (\$value === null) {
$isNullBody
Expand Down
6 changes: 4 additions & 2 deletions src/ObjectMapperUsingReflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,13 @@ public function hydrateObject(string $className, array $payload): object
continue;
}

$typeName = $definition->firstTypeName;

foreach ($definition->casters as [$caster, $options]) {
$key = $className . '-' . $caster . '-' . json_encode($options);
/** @var PropertyCaster $propertyCaster */
$propertyCaster = $this->casterInstances[$key] ??= new $caster(...$options);
$value = $propertyCaster->cast($value, $this);
$value = $propertyCaster->cast($value, $this, $typeName);
}

// same code as two sections above
Expand All @@ -133,7 +135,7 @@ public function hydrateObject(string $className, array $payload): object
$value = $this->hydrateViaTypeMap($definition, $value);
}

$typeName = $definition->firstTypeName;


if ($definition->isBackedEnum()) {
$value = $typeName::from($value);
Expand Down
1 change: 1 addition & 0 deletions src/ObjectSerializationTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use DateTimeImmutable;
use EventSauce\ObjectHydrator\Fixtures\CastersOnClasses\ClassWithClassLevelMapFrom;
use EventSauce\ObjectHydrator\Fixtures\CastersOnClasses\ClassWithClassLevelMapFromMultiple;
use EventSauce\ObjectHydrator\Fixtures\CastToExpectedType\ClassWithIds;
use EventSauce\ObjectHydrator\Fixtures\ClassReferencedByUnionOne;
use EventSauce\ObjectHydrator\Fixtures\ClassReferencedByUnionTwo;
use EventSauce\ObjectHydrator\Fixtures\ClassThatOmitsPublicMethods;
Expand Down
2 changes: 1 addition & 1 deletion src/PropertyCaster.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@

interface PropertyCaster
{
public function cast(mixed $value, ObjectMapper $hydrator): mixed;
public function cast(mixed $value, ObjectMapper $hydrator, ?string $expectedTypeName): mixed;
}
2 changes: 1 addition & 1 deletion src/PropertyCasters/CastListToType.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public function __construct(
$this->isEnum = enum_exists($this->propertyType);
}

public function cast(mixed $value, ObjectMapper $hydrator): mixed
public function cast(mixed $value, ObjectMapper $hydrator, ?string $expectedTypeName): mixed
{
assert(is_array($value), 'value is expected to be an array');

Expand Down
2 changes: 1 addition & 1 deletion src/PropertyCasters/CastToArrayWithKey.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public function __construct(private string $key)
{
}

public function cast(mixed $value, ObjectMapper $hydrator): mixed
public function cast(mixed $value, ObjectMapper $hydrator, ?string $expectedTypeName): mixed
{
return [$this->key => $value];
}
Expand Down
2 changes: 1 addition & 1 deletion src/PropertyCasters/CastToDateTimeImmutable.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public function __construct(private ?string $format = null, private ?string $tim
{
}

public function cast(mixed $value, ObjectMapper $hydrator): mixed
public function cast(mixed $value, ObjectMapper $hydrator, ?string $expectedTypeName): mixed
{
$timeZone = $this->timeZone ? new DateTimeZone($this->timeZone) : $this->timeZone;

Expand Down
2 changes: 1 addition & 1 deletion src/PropertyCasters/CastToType.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public function __construct(
) {
}

public function cast(mixed $value, ObjectMapper $hydrator): mixed
public function cast(mixed $value, ObjectMapper $hydrator, ?string $expectedTypeName): mixed
{
settype($value, $this->propertyType);

Expand Down
2 changes: 1 addition & 1 deletion src/PropertyCasters/CastToUuid.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public function __construct(private string $type = 'string')
{
}

public function cast(mixed $value, ObjectMapper $hydrator): UuidInterface
public function cast(mixed $value, ObjectMapper $hydrator, ?string $expectedTypeName): UuidInterface
{
$value = (string) $value;

Expand Down