Skip to content
Draft
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
41 changes: 41 additions & 0 deletions src/Normalizer/InlineNormalizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

namespace Patchlevel\Hydrator\Normalizer;

use Attribute;
use Closure;

#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_CLASS)]
final class InlineNormalizer implements Normalizer
{
/**
* @param Closure(mixed): mixed $normalize
* @param Closure(mixed): mixed $denormalize
*/
public function __construct(
private readonly Closure $normalize,
private readonly Closure $denormalize,
private readonly bool $passNull = false,
) {
}

public function normalize(mixed $value): mixed
{
if (!$this->passNull && $value === null) {
return null;
}

return ($this->normalize)($value);
}

public function denormalize(mixed $value): mixed
{
if (!$this->passNull && $value === null) {
return null;
}

return ($this->denormalize)($value);
}
}
25 changes: 25 additions & 0 deletions tests/Unit/Fixture/ProfileCreatedWithInlineNormalizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Patchlevel\Hydrator\Tests\Unit\Fixture;

use Patchlevel\Hydrator\Normalizer\InlineNormalizer;

final class ProfileCreatedWithInlineNormalizer
{
public function __construct(
#[IdNormalizer]
public ProfileId $profileId,
#[InlineNormalizer(
normalize: static function (Email $email): string {
return $email->toString();
},
denormalize: static function (string $value): Email {
return Email::fromString($value);
},
)]
public Email $email,
) {
}
}
33 changes: 32 additions & 1 deletion tests/Unit/MetadataHydratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
use Patchlevel\Hydrator\Tests\Unit\Fixture\NormalizerInBaseClassDefinedDto;
use Patchlevel\Hydrator\Tests\Unit\Fixture\ParentDto;
use Patchlevel\Hydrator\Tests\Unit\Fixture\ProfileCreated;
use Patchlevel\Hydrator\Tests\Unit\Fixture\ProfileCreatedWithInlineNormalizer;
use Patchlevel\Hydrator\Tests\Unit\Fixture\ProfileCreatedWithNormalizer;
use Patchlevel\Hydrator\Tests\Unit\Fixture\ProfileCreatedWrapper;
use Patchlevel\Hydrator\Tests\Unit\Fixture\ProfileId;
Expand Down Expand Up @@ -113,7 +114,7 @@ public function testExtractCircularReference(): void
$this->hydrator->extract($dto1);
}

public function testExtractWithInferNormalizer2(): void
public function testExtractWithInferNormalizer(): void
{
$result = $this->hydrator->extract(
new InferNormalizerWithNullableDto(
Expand Down Expand Up @@ -148,6 +149,20 @@ public function testExtractWithInferNormalizerFailed(): void
);
}

#[RequiresPhp('>=8.5')]
public function testExtractWithInlineNormalizer(): void
{
$event = new ProfileCreatedWithInlineNormalizer(
ProfileId::fromString('1'),
Email::fromString('info@patchlevel.de'),
);

self::assertEquals(
['profileId' => '1', 'email' => 'info@patchlevel.de'],
$this->hydrator->extract($event),
);
}

public function testExtractWithHooks(): void
{
$data = $this->hydrator->extract(new DtoWithHooks());
Expand Down Expand Up @@ -236,6 +251,22 @@ public function testHydrateWithTypeMismatch(): void
);
}

#[RequiresPhp('>=8.5')]
public function testHydrateWithInlineNormalizer(): void
{
$expected = new ProfileCreatedWithInlineNormalizer(
ProfileId::fromString('1'),
Email::fromString('info@patchlevel.de'),
);

$event = $this->hydrator->hydrate(
ProfileCreatedWithInlineNormalizer::class,
['profileId' => '1', 'email' => 'info@patchlevel.de'],
);

self::assertEquals($expected, $event);
}

public function testDenormalizationFailure(): void
{
$this->expectException(DenormalizationFailure::class);
Expand Down
Loading