diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 216d2ad..e293f65 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -103,7 +103,7 @@ parameters: path: tests/Unit/Metadata/AttributeMetadataFactoryTest.php - - message: '#^Parameter \#1 \$class of method Patchlevel\\Hydrator\\MetadataHydrator\:\:hydrate\(\) expects class\-string\, string given\.$#' + message: '#^Parameter \#1 \$class of method Patchlevel\\Hydrator\\Hydrator\:\:hydrate\(\) expects class\-string\, string given\.$#' identifier: argument.type count: 1 path: tests/Unit/MetadataHydratorTest.php diff --git a/src/CoreExtension.php b/src/CoreExtension.php new file mode 100644 index 0000000..da16662 --- /dev/null +++ b/src/CoreExtension.php @@ -0,0 +1,17 @@ +addMiddleware(new TransformMiddleware(), -64); + $builder->addGuesser(new BuiltInGuesser(), -64); + } +} diff --git a/src/Cryptography/CryptographyExtension.php b/src/Cryptography/CryptographyExtension.php new file mode 100644 index 0000000..e2bdf98 --- /dev/null +++ b/src/Cryptography/CryptographyExtension.php @@ -0,0 +1,22 @@ +addMetadataEnricher(new CryptographyMetadataEnricher(), 64); + $builder->addMiddleware(new CryptographyMiddleware($this->cryptography), 64); + } +} diff --git a/src/Cryptography/CryptographyMetadataFactory.php b/src/Cryptography/CryptographyMetadataEnricher.php similarity index 69% rename from src/Cryptography/CryptographyMetadataFactory.php rename to src/Cryptography/CryptographyMetadataEnricher.php index d74c3ee..3569a8f 100644 --- a/src/Cryptography/CryptographyMetadataFactory.php +++ b/src/Cryptography/CryptographyMetadataEnricher.php @@ -7,25 +7,18 @@ use Patchlevel\Hydrator\Attribute\DataSubjectId; use Patchlevel\Hydrator\Attribute\SensitiveData; use Patchlevel\Hydrator\Metadata\ClassMetadata; -use Patchlevel\Hydrator\Metadata\MetadataFactory; +use Patchlevel\Hydrator\Metadata\MetadataEnricher; use ReflectionProperty; use function array_key_exists; -final class CryptographyMetadataFactory implements MetadataFactory +final class CryptographyMetadataEnricher implements MetadataEnricher { - public function __construct( - private readonly MetadataFactory $metadataFactory, - ) { - } - - public function metadata(string $class): ClassMetadata + public function enrich(ClassMetadata $classMetadata): void { - $metadata = $this->metadataFactory->metadata($class); - $subjectIdMapping = []; - foreach ($metadata->properties as $property) { + foreach ($classMetadata->properties as $property) { $isSubjectId = false; $attributeReflectionList = $property->reflection->getAttributes(DataSubjectId::class); @@ -34,8 +27,8 @@ public function metadata(string $class): ClassMetadata if (array_key_exists($subjectIdIdentifier, $subjectIdMapping)) { throw new DuplicateSubjectIdIdentifier( - $metadata->className, - $metadata->propertyForField($subjectIdMapping[$subjectIdIdentifier])->propertyName, + $classMetadata->className, + $classMetadata->propertyForField($subjectIdMapping[$subjectIdIdentifier])->propertyName, $property->propertyName, $subjectIdIdentifier, ); @@ -53,17 +46,17 @@ public function metadata(string $class): ClassMetadata } if ($isSubjectId) { - throw new SubjectIdAndSensitiveDataConflict($metadata->className, $property->propertyName); + throw new SubjectIdAndSensitiveDataConflict($classMetadata->className, $property->propertyName); } $property->extras[SensitiveDataInfo::class] = $sensitiveDataInfo; } - if ($subjectIdMapping !== []) { - $metadata->extras[SubjectIdFieldMapping::class] = new SubjectIdFieldMapping($subjectIdMapping); + if ($subjectIdMapping === []) { + return; } - return $metadata; + $classMetadata->extras[SubjectIdFieldMapping::class] = new SubjectIdFieldMapping($subjectIdMapping); } private function sensitiveDataInfo(ReflectionProperty $reflectionProperty): SensitiveDataInfo|null diff --git a/src/Extension.php b/src/Extension.php new file mode 100644 index 0000000..60a1160 --- /dev/null +++ b/src/Extension.php @@ -0,0 +1,10 @@ +> */ + private array $middlewares = []; + + /** @var array> */ + private array $metadataEnrichers = []; + + /** @var array> */ + private array $guessers = []; + + /** @return $this */ + public function addMiddleware(Middleware $middleware, int $priority = 0): static + { + $this->middlewares[$priority][] = $middleware; + + return $this; + } + + /** @return $this */ + public function addMetadataEnricher(MetadataEnricher $enricher, int $priority = 0): static + { + $this->metadataEnrichers[$priority][] = $enricher; + + return $this; + } + + /** @return $this */ + public function addGuesser(Guesser $guesser, int $priority = 0): static + { + $this->guessers[$priority][] = $guesser; + + return $this; + } + + public function enableDefaultLazy(bool $lazy = true): static + { + $this->defaultLazy = $lazy; + + return $this; + } + + public function useExtension(Extension $extension): static + { + $extension->configure($this); + + return $this; + } + + public function build(): Hydrator + { + krsort($this->middlewares); + krsort($this->metadataEnrichers); + krsort($this->guessers); + + return new MetadataHydrator( + new AttributeMetadataFactory( + guesser: new ChainGuesser(array_merge(...$this->guessers)), + ), + array_merge(...$this->middlewares), + array_merge(...$this->metadataEnrichers), + $this->defaultLazy, + ); + } +} diff --git a/src/Metadata/AttributeMetadataFactory.php b/src/Metadata/AttributeMetadataFactory.php index 36ba797..2355697 100644 --- a/src/Metadata/AttributeMetadataFactory.php +++ b/src/Metadata/AttributeMetadataFactory.php @@ -41,7 +41,7 @@ public function __construct( Guesser|null $guesser = null, ) { $this->typeResolver = $typeResolver ?: TypeResolver::create(); - $this->guesser = $guesser ?: new BuiltInGuesser(false); + $this->guesser = $guesser ?: new BuiltInGuesser(); } /** diff --git a/src/Metadata/MetadataEnricher.php b/src/Metadata/MetadataEnricher.php new file mode 100644 index 0000000..5516db1 --- /dev/null +++ b/src/Metadata/MetadataEnricher.php @@ -0,0 +1,10 @@ + */ private array $classMetadata = []; - /** @param list $middlewares */ + /** + * @param list $middlewares + * @param list $metadataEnrichers + */ public function __construct( private readonly MetadataFactory $metadataFactory = new AttributeMetadataFactory(), private readonly array $middlewares = [], + private readonly array $metadataEnrichers = [], private readonly bool $defaultLazy = false, ) { } @@ -110,33 +111,10 @@ private function metadata(string $class): ClassMetadata $property->normalizer->setHydrator($this); } - return $metadata; - } - - /** - * @param list $additionalMiddleware - * @param iterable $guessers - */ - public static function create( - array $additionalMiddleware = [], - iterable $guessers = [], - bool $defaultLazy = false, - ): self { - $guesser = new BuiltInGuesser(); - - if ($guessers !== []) { - $guesser = new ChainGuesser([ - ...$guessers, - $guesser, - ]); + foreach ($this->metadataEnrichers as $enricher) { + $enricher->enrich($metadata); } - return new self( - new AttributeMetadataFactory( - guesser: $guesser, - ), - [...$additionalMiddleware, new TransformMiddleware()], - $defaultLazy, - ); + return $metadata; } } diff --git a/tests/Benchmark/HydratorBench.php b/tests/Benchmark/HydratorBench.php index 529b980..9120b38 100644 --- a/tests/Benchmark/HydratorBench.php +++ b/tests/Benchmark/HydratorBench.php @@ -4,8 +4,9 @@ namespace Patchlevel\Hydrator\Tests\Benchmark; +use Patchlevel\Hydrator\CoreExtension; use Patchlevel\Hydrator\Hydrator; -use Patchlevel\Hydrator\MetadataHydrator; +use Patchlevel\Hydrator\HydratorBuilder; use Patchlevel\Hydrator\Tests\Benchmark\Fixture\ProfileCreated; use Patchlevel\Hydrator\Tests\Benchmark\Fixture\ProfileId; use Patchlevel\Hydrator\Tests\Benchmark\Fixture\Skill; @@ -18,7 +19,9 @@ final class HydratorBench public function __construct() { - $this->hydrator = MetadataHydrator::create(); + $this->hydrator = (new HydratorBuilder()) + ->useExtension(new CoreExtension()) + ->build(); } public function setUp(): void diff --git a/tests/Benchmark/HydratorWithCryptographyBench.php b/tests/Benchmark/HydratorWithCryptographyBench.php index 4e4af49..6f864c1 100644 --- a/tests/Benchmark/HydratorWithCryptographyBench.php +++ b/tests/Benchmark/HydratorWithCryptographyBench.php @@ -4,14 +4,12 @@ namespace Patchlevel\Hydrator\Tests\Benchmark; -use Patchlevel\Hydrator\Cryptography\CryptographyMetadataFactory; -use Patchlevel\Hydrator\Cryptography\CryptographyMiddleware; +use Patchlevel\Hydrator\CoreExtension; +use Patchlevel\Hydrator\Cryptography\CryptographyExtension; use Patchlevel\Hydrator\Cryptography\SensitiveDataPayloadCryptographer; use Patchlevel\Hydrator\Cryptography\Store\InMemoryCipherKeyStore; use Patchlevel\Hydrator\Hydrator; -use Patchlevel\Hydrator\Metadata\AttributeMetadataFactory; -use Patchlevel\Hydrator\MetadataHydrator; -use Patchlevel\Hydrator\Middleware\TransformMiddleware; +use Patchlevel\Hydrator\HydratorBuilder; use Patchlevel\Hydrator\Tests\Benchmark\Fixture\ProfileCreated; use Patchlevel\Hydrator\Tests\Benchmark\Fixture\ProfileId; use Patchlevel\Hydrator\Tests\Benchmark\Fixture\Skill; @@ -28,13 +26,10 @@ public function __construct() { $this->store = new InMemoryCipherKeyStore(); - $this->hydrator = new MetadataHydrator( - new CryptographyMetadataFactory(new AttributeMetadataFactory()), - [ - new CryptographyMiddleware(SensitiveDataPayloadCryptographer::createWithDefaultSettings($this->store)), - new TransformMiddleware(), - ], - ); + $this->hydrator = (new HydratorBuilder()) + ->useExtension(new CoreExtension()) + ->useExtension(new CryptographyExtension(SensitiveDataPayloadCryptographer::createWithDefaultSettings($this->store))) + ->build(); } public function setUp(): void diff --git a/tests/Benchmark/HydratorWithLazyBench.php b/tests/Benchmark/HydratorWithLazyBench.php index fe9c98d..de2b688 100644 --- a/tests/Benchmark/HydratorWithLazyBench.php +++ b/tests/Benchmark/HydratorWithLazyBench.php @@ -4,8 +4,9 @@ namespace Patchlevel\Hydrator\Tests\Benchmark; +use Patchlevel\Hydrator\CoreExtension; use Patchlevel\Hydrator\Hydrator; -use Patchlevel\Hydrator\MetadataHydrator; +use Patchlevel\Hydrator\HydratorBuilder; use Patchlevel\Hydrator\Tests\Benchmark\Fixture\ProfileCreated; use PhpBench\Attributes as Bench; @@ -16,7 +17,10 @@ final class HydratorWithLazyBench public function __construct() { - $this->hydrator = MetadataHydrator::create(defaultLazy: true); + $this->hydrator = (new HydratorBuilder()) + ->useExtension(new CoreExtension()) + ->enableDefaultLazy() + ->build(); } public function setUp(): void diff --git a/tests/Unit/Cryptography/CryptographyMetadataFactoryTest.php b/tests/Unit/Cryptography/CryptographyMetadataEnricherTest.php similarity index 85% rename from tests/Unit/Cryptography/CryptographyMetadataFactoryTest.php rename to tests/Unit/Cryptography/CryptographyMetadataEnricherTest.php index 7a07c30..b030daf 100644 --- a/tests/Unit/Cryptography/CryptographyMetadataFactoryTest.php +++ b/tests/Unit/Cryptography/CryptographyMetadataEnricherTest.php @@ -7,19 +7,20 @@ use Patchlevel\Hydrator\Attribute\DataSubjectId; use Patchlevel\Hydrator\Attribute\NormalizedName; use Patchlevel\Hydrator\Attribute\SensitiveData; -use Patchlevel\Hydrator\Cryptography\CryptographyMetadataFactory; +use Patchlevel\Hydrator\Cryptography\CryptographyMetadataEnricher; use Patchlevel\Hydrator\Cryptography\DuplicateSubjectIdIdentifier; use Patchlevel\Hydrator\Cryptography\SensitiveDataInfo; use Patchlevel\Hydrator\Cryptography\SubjectIdAndSensitiveDataConflict; use Patchlevel\Hydrator\Cryptography\SubjectIdFieldMapping; use Patchlevel\Hydrator\Metadata\AttributeMetadataFactory; +use Patchlevel\Hydrator\Metadata\ClassMetadata; use Patchlevel\Hydrator\Tests\Unit\Fixture\ParentWithSensitiveDataDto; use Patchlevel\Hydrator\Tests\Unit\Fixture\ParentWithSensitiveDataWithIdentifierDto; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; -#[CoversClass(CryptographyMetadataFactory::class)] -final class CryptographyMetadataFactoryTest extends TestCase +#[CoversClass(CryptographyMetadataEnricher::class)] +final class CryptographyMetadataEnricherTest extends TestCase { public function testSensitiveData(): void { @@ -35,8 +36,7 @@ public function __construct( } }; - $metadataFactory = new CryptographyMetadataFactory(new AttributeMetadataFactory()); - $metadata = $metadataFactory->metadata($event::class); + $metadata = $this->metadata($event::class); self::assertArrayHasKey(SubjectIdFieldMapping::class, $metadata->extras); $subjectIdFieldMapping = $metadata->extras[SubjectIdFieldMapping::class]; @@ -66,8 +66,7 @@ public function __construct( $this->expectException(SubjectIdAndSensitiveDataConflict::class); - $metadataFactory = new CryptographyMetadataFactory(new AttributeMetadataFactory()); - $metadataFactory->metadata($event::class); + $this->metadata($event::class); } public function testMultipleDataSubjectIdWithSameIdentifier(): void @@ -84,8 +83,7 @@ public function __construct( $this->expectException(DuplicateSubjectIdIdentifier::class); - $metadataFactory = new CryptographyMetadataFactory(new AttributeMetadataFactory()); - $metadataFactory->metadata($event::class); + $this->metadata($event::class); } public function testSensitiveDataWithMultipleDataSubjectIdWithDifferentNames(): void @@ -108,8 +106,7 @@ public function __construct( } }; - $metadataFactory = new CryptographyMetadataFactory(new AttributeMetadataFactory()); - $metadata = $metadataFactory->metadata($event::class); + $metadata = $this->metadata($event::class); self::assertArrayHasKey(SubjectIdFieldMapping::class, $metadata->extras); $subjectIdFieldMapping = $metadata->extras[SubjectIdFieldMapping::class]; @@ -155,17 +152,15 @@ public function __construct( } }; - $metadataFactory = new CryptographyMetadataFactory(new AttributeMetadataFactory()); - $this->expectException(DuplicateSubjectIdIdentifier::class); $this->expectExceptionMessageMatches('/Duplicate subject id identifier found\. Used foo for .*::fooId and .*::barId\./'); - $metadataFactory->metadata($event::class); + + $this->metadata($event::class); } public function testExtendsWithSensitiveData(): void { - $metadataFactory = new CryptographyMetadataFactory(new AttributeMetadataFactory()); - $metadata = $metadataFactory->metadata(ParentWithSensitiveDataDto::class); + $metadata = $this->metadata(ParentWithSensitiveDataDto::class); self::assertCount(2, $metadata->properties); @@ -186,8 +181,7 @@ public function testExtendsWithSensitiveData(): void public function testExtendsWithSensitiveDataWithName(): void { - $metadataFactory = new CryptographyMetadataFactory(new AttributeMetadataFactory()); - $metadata = $metadataFactory->metadata(ParentWithSensitiveDataWithIdentifierDto::class); + $metadata = $this->metadata(ParentWithSensitiveDataWithIdentifierDto::class); self::assertCount(2, $metadata->properties); @@ -205,4 +199,13 @@ public function testExtendsWithSensitiveDataWithName(): void self::assertSame('profile', $sensitiveDataInfo->subjectIdName); self::assertSame(null, $sensitiveDataInfo->fallback); } + + /** @param class-string $class */ + private function metadata(string $class): ClassMetadata + { + $metadata = (new AttributeMetadataFactory())->metadata($class); + (new CryptographyMetadataEnricher())->enrich($metadata); + + return $metadata; + } } diff --git a/tests/Unit/Cryptography/SensitiveDataPayloadCryptographerTest.php b/tests/Unit/Cryptography/SensitiveDataPayloadCryptographerTest.php index b34c6f0..17d2f0c 100644 --- a/tests/Unit/Cryptography/SensitiveDataPayloadCryptographerTest.php +++ b/tests/Unit/Cryptography/SensitiveDataPayloadCryptographerTest.php @@ -9,7 +9,7 @@ use Patchlevel\Hydrator\Cryptography\Cipher\CipherKey; use Patchlevel\Hydrator\Cryptography\Cipher\CipherKeyFactory; use Patchlevel\Hydrator\Cryptography\Cipher\DecryptionFailed; -use Patchlevel\Hydrator\Cryptography\CryptographyMetadataFactory; +use Patchlevel\Hydrator\Cryptography\CryptographyMetadataEnricher; use Patchlevel\Hydrator\Cryptography\MissingSubjectId; use Patchlevel\Hydrator\Cryptography\SensitiveDataPayloadCryptographer; use Patchlevel\Hydrator\Cryptography\Store\CipherKeyNotExists; @@ -474,10 +474,9 @@ public function testCreateWithOpenssl(): void /** @param class-string $class */ private function metadata(string $class): ClassMetadata { - $factory = new CryptographyMetadataFactory( - new AttributeMetadataFactory(), - ); + $metadata = (new AttributeMetadataFactory())->metadata($class); + (new CryptographyMetadataEnricher())->enrich($metadata); - return $factory->metadata($class); + return $metadata; } } diff --git a/tests/Unit/HydratorBuilderTest.php b/tests/Unit/HydratorBuilderTest.php new file mode 100644 index 0000000..47e973f --- /dev/null +++ b/tests/Unit/HydratorBuilderTest.php @@ -0,0 +1,112 @@ +build(); + + self::assertInstanceOf(MetadataHydrator::class, $hydrator); + } + + public function testAddMiddlewareWithPriority(): void + { + $middleware1 = $this->createMock(Middleware::class); + $middleware2 = $this->createMock(Middleware::class); + + $builder = new HydratorBuilder(); + $builder->addMiddleware($middleware1, 10); + $builder->addMiddleware($middleware2, 20); + + $hydrator = $builder->build(); + + $reflection = new ReflectionProperty(MetadataHydrator::class, 'middlewares'); + $middlewares = $reflection->getValue($hydrator); + + self::assertSame([$middleware2, $middleware1], $middlewares); + } + + public function testAddMetadataEnricherWithPriority(): void + { + $enricher1 = $this->createMock(MetadataEnricher::class); + $enricher2 = $this->createMock(MetadataEnricher::class); + + $builder = new HydratorBuilder(); + $builder->addMetadataEnricher($enricher1, 10); + $builder->addMetadataEnricher($enricher2, 20); + + $hydrator = $builder->build(); + + $reflection = new ReflectionProperty(MetadataHydrator::class, 'metadataEnrichers'); + $enrichers = $reflection->getValue($hydrator); + + self::assertSame([$enricher2, $enricher1], $enrichers); + } + + public function testAddGuesserWithPriority(): void + { + $guesser1 = $this->createMock(Guesser::class); + $guesser2 = $this->createMock(Guesser::class); + + $builder = new HydratorBuilder(); + $builder->addGuesser($guesser1, 10); + $builder->addGuesser($guesser2, 20); + + $hydrator = $builder->build(); + + $reflection = new ReflectionProperty(MetadataHydrator::class, 'metadataFactory'); + $metadataFactory = $reflection->getValue($hydrator); + + self::assertInstanceOf(AttributeMetadataFactory::class, $metadataFactory); + + $reflection = new ReflectionProperty(AttributeMetadataFactory::class, 'guesser'); + $guesser = $reflection->getValue($metadataFactory); + + self::assertInstanceOf(ChainGuesser::class, $guesser); + + $reflection = new ReflectionProperty(ChainGuesser::class, 'guessers'); + $guessers = $reflection->getValue($guesser); + + self::assertSame([$guesser2, $guesser1], $guessers); + } + + public function testEnableDefaultLazy(): void + { + $builder = new HydratorBuilder(); + $builder->enableDefaultLazy(); + + $hydrator = $builder->build(); + + $reflection = new ReflectionProperty(MetadataHydrator::class, 'defaultLazy'); + self::assertTrue($reflection->getValue($hydrator)); + } + + public function testUseExtension(): void + { + $extension = $this->createMock(Extension::class); + $builder = new HydratorBuilder(); + + $extension->expects(self::once()) + ->method('configure') + ->with($builder); + + $builder->useExtension($extension); + } +} diff --git a/tests/Unit/MetadataHydratorTest.php b/tests/Unit/MetadataHydratorTest.php index e0355f5..00220fb 100644 --- a/tests/Unit/MetadataHydratorTest.php +++ b/tests/Unit/MetadataHydratorTest.php @@ -9,10 +9,12 @@ use DateTimeZone; use Patchlevel\Hydrator\CircularReference; use Patchlevel\Hydrator\ClassNotSupported; -use Patchlevel\Hydrator\Cryptography\CryptographyMiddleware; +use Patchlevel\Hydrator\CoreExtension; +use Patchlevel\Hydrator\Cryptography\CryptographyExtension; use Patchlevel\Hydrator\Cryptography\PayloadCryptographer; use Patchlevel\Hydrator\DenormalizationFailure; -use Patchlevel\Hydrator\Guesser\Guesser; +use Patchlevel\Hydrator\Hydrator; +use Patchlevel\Hydrator\HydratorBuilder; use Patchlevel\Hydrator\Metadata\AttributeMetadataFactory; use Patchlevel\Hydrator\Metadata\ClassMetadata; use Patchlevel\Hydrator\MetadataHydrator; @@ -20,7 +22,6 @@ use Patchlevel\Hydrator\Middleware\Stack; use Patchlevel\Hydrator\Middleware\TransformMiddleware; use Patchlevel\Hydrator\NormalizationFailure; -use Patchlevel\Hydrator\Normalizer\Normalizer; use Patchlevel\Hydrator\Tests\Unit\Fixture\Circle1Dto; use Patchlevel\Hydrator\Tests\Unit\Fixture\Circle2Dto; use Patchlevel\Hydrator\Tests\Unit\Fixture\Circle3Dto; @@ -45,18 +46,16 @@ use PHPUnit\Framework\Attributes\RequiresPhp; use PHPUnit\Framework\TestCase; use ReflectionClass; -use stdClass; -use Symfony\Component\TypeInfo\Type\ObjectType; #[CoversClass(MetadataHydrator::class)] #[CoversClass(TransformMiddleware::class)] final class MetadataHydratorTest extends TestCase { - private MetadataHydrator $hydrator; + private Hydrator $hydrator; public function setUp(): void { - $this->hydrator = MetadataHydrator::create(); + $this->hydrator = (new HydratorBuilder())->useExtension(new CoreExtension())->build(); } public function testExtract(): void @@ -153,6 +152,7 @@ public function testExtractWithContext(): void 'dateTimeImmutable' => '2015-02-13T22:34:32+01:00', 'dateTime' => '2015-02-13T22:34:32+01:00', 'dateTimeZone' => 'EDT', + 'array' => ['foo'], ]; $middleware = $this->createMock(Middleware::class); @@ -166,7 +166,10 @@ public function testExtractWithContext(): void $this->isInstanceOf(Stack::class), )->willReturn($expect); - $hydrator = MetadataHydrator::create([$middleware]); + $hydrator = (new HydratorBuilder()) + ->useExtension(new CoreExtension()) + ->addMiddleware($middleware) + ->build(); $data = $hydrator->extract($object, ['context' => '123']); @@ -270,6 +273,7 @@ public function testHydrateWithContext(): void 'dateTimeImmutable' => '2015-02-13T22:34:32+01:00', 'dateTime' => '2015-02-13T22:34:32+01:00', 'dateTimeZone' => 'EDT', + 'array' => ['foo'], ]; $middleware = $this->createMock(Middleware::class); @@ -283,7 +287,10 @@ public function testHydrateWithContext(): void $this->isInstanceOf(Stack::class), )->willReturn($expect); - $hydrator = MetadataHydrator::create([$middleware]); + $hydrator = (new HydratorBuilder()) + ->useExtension(new CoreExtension()) + ->addMiddleware($middleware) + ->build(); $object = $hydrator->hydrate(InferNormalizerDto::class, $data, ['context' => '123']); @@ -328,13 +335,10 @@ public function testDecrypt(): void ->with($metadataFactory->metadata(ProfileCreated::class), $encryptedPayload) ->willReturn($payload); - $hydrator = new MetadataHydrator( - $metadataFactory, - [ - new CryptographyMiddleware($cryptographer), - new TransformMiddleware(), - ], - ); + $hydrator = (new HydratorBuilder()) + ->useExtension(new CoreExtension()) + ->useExtension(new CryptographyExtension($cryptographer)) + ->build(); $return = $hydrator->hydrate(ProfileCreated::class, $encryptedPayload); @@ -360,13 +364,10 @@ public function testEncrypt(): void ->with($metadataFactory->metadata(ProfileCreated::class), $payload) ->willReturn($encryptedPayload); - $hydrator = new MetadataHydrator( - $metadataFactory, - [ - new CryptographyMiddleware($cryptographer), - new TransformMiddleware(), - ], - ); + $hydrator = (new HydratorBuilder()) + ->useExtension(new CoreExtension()) + ->useExtension(new CryptographyExtension($cryptographer)) + ->build(); $return = $hydrator->extract($object); @@ -546,65 +547,4 @@ public function testLazyExtract(): void self::assertEquals(['profileId' => '1', 'email' => 'info@patchlevel.de'], $data); } - - public function testCreate(): void - { - $guesser = new class implements Guesser { - public int $count = 0; - - /** @param ObjectType $type */ - public function guess(ObjectType $type): Normalizer|null - { - $this->count++; - - return null; - } - }; - - $hydrator = MetadataHydrator::create( - [ - new class implements Middleware - { - /** - * @param ClassMetadata $metadata - * @param array $data - * @param array $context - * - * @return T - * - * @template T of object - */ - public function hydrate(ClassMetadata $metadata, array $data, array $context, Stack $stack): object - { - return $stack->next()->hydrate($metadata, $data, $context, $stack); - } - - /** - * @param ClassMetadata $metadata - * @param T $object - * @param array $context - * - * @return array - * - * @template T of object - */ - public function extract(ClassMetadata $metadata, object $object, array $context, Stack $stack): array - { - return $stack->next()->extract($metadata, $object, $context, $stack); - } - }, - ], - [$guesser], - ); - - $hydrator->extract(new InferNormalizerDto( - Status::Draft, - new DateTimeImmutable('2015-02-13 22:34:32+01:00'), - new DateTime('2015-02-13 22:34:32+01:00'), - new DateTimeZone('EDT'), - ['foo'], - )); - - self::assertSame(4, $guesser->count); - } }