Skip to content

Commit 116cfd0

Browse files
committed
add context feature
1 parent 58e069f commit 116cfd0

File tree

10 files changed

+112
-49
lines changed

10 files changed

+112
-49
lines changed

src/Cryptography/CryptographyMiddleware.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,33 +18,36 @@ public function __construct(
1818
/**
1919
* @param ClassMetadata<T> $metadata
2020
* @param array<string, mixed> $data
21+
* @param array<string, mixed> $context
2122
*
2223
* @return T
2324
*
2425
* @template T of object
2526
*/
26-
public function hydrate(ClassMetadata $metadata, array $data, Stack $stack): object
27+
public function hydrate(ClassMetadata $metadata, array $data, array $context, Stack $stack): object
2728
{
2829
return $stack->next()->hydrate(
2930
$metadata,
3031
$this->cryptography->decrypt($metadata, $data),
32+
$context,
3133
$stack,
3234
);
3335
}
3436

3537
/**
36-
* @param ClassMetadata<T> $metadata
37-
* @param T $object
38+
* @param ClassMetadata<T> $metadata
39+
* @param T $object
40+
* @param array<string, mixed> $context
3841
*
3942
* @return array<string, mixed>
4043
*
4144
* @template T of object
4245
*/
43-
public function extract(ClassMetadata $metadata, object $object, Stack $stack): array
46+
public function extract(ClassMetadata $metadata, object $object, array $context, Stack $stack): array
4447
{
4548
return $this->cryptography->encrypt(
4649
$metadata,
47-
$stack->next()->extract($metadata, $object, $stack),
50+
$stack->next()->extract($metadata, $object, $context, $stack),
4851
);
4952
}
5053
}

src/Hydrator.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,20 @@ interface Hydrator
99
/**
1010
* @param class-string<T> $class
1111
* @param array<string, mixed> $data
12+
* @param array<string, mixed> $context
1213
*
1314
* @return T
1415
*
1516
* @throws ClassNotSupported if the class is not supported or not found.
1617
*
1718
* @template T of object
1819
*/
19-
public function hydrate(string $class, array $data): object;
20+
public function hydrate(string $class, array $data, array $context = []): object;
2021

21-
/** @return array<string, mixed> */
22-
public function extract(object $object): array;
22+
/**
23+
* @param array<string, mixed> $context
24+
*
25+
* @return array<string, mixed>
26+
*/
27+
public function extract(object $object, array $context = []): array;
2328
}

src/MetadataHydrator.php

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,13 @@ public function __construct(
3737
/**
3838
* @param class-string<T> $class
3939
* @param array<string, mixed> $data
40+
* @param array<string, mixed> $context
4041
*
4142
* @return T
4243
*
4344
* @template T of object
4445
*/
45-
public function hydrate(string $class, array $data): object
46+
public function hydrate(string $class, array $data, array $context = []): object
4647
{
4748
try {
4849
$metadata = $this->metadata($class);
@@ -53,33 +54,37 @@ public function hydrate(string $class, array $data): object
5354
if (PHP_VERSION_ID < 80400) {
5455
$stack = new Stack($this->middlewares);
5556

56-
return $stack->next()->hydrate($metadata, $data, $stack);
57+
return $stack->next()->hydrate($metadata, $data, $context, $stack);
5758
}
5859

5960
$lazy = $metadata->lazy ?? $this->defaultLazy;
6061

6162
if (!$lazy) {
6263
$stack = new Stack($this->middlewares);
6364

64-
return $stack->next()->hydrate($metadata, $data, $stack);
65+
return $stack->next()->hydrate($metadata, $data, $context, $stack);
6566
}
6667

6768
return (new ReflectionClass($class))->newLazyProxy(
68-
function () use ($metadata, $data): object {
69+
function () use ($metadata, $data, $context): object {
6970
$stack = new Stack($this->middlewares);
7071

71-
return $stack->next()->hydrate($metadata, $data, $stack);
72+
return $stack->next()->hydrate($metadata, $data, $context, $stack);
7273
},
7374
);
7475
}
7576

76-
/** @return array<string, mixed> */
77-
public function extract(object $object): array
77+
/**
78+
* @param array<string, mixed> $context
79+
*
80+
* @return array<string, mixed>
81+
*/
82+
public function extract(object $object, array $context = []): array
7883
{
7984
$metadata = $this->metadata($object::class);
8085
$stack = new Stack($this->middlewares);
8186

82-
return $stack->next()->extract($metadata, $object, $stack);
87+
return $stack->next()->extract($metadata, $object, $context, $stack);
8388
}
8489

8590
/**

src/Middleware/Middleware.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,22 @@ interface Middleware
1111
/**
1212
* @param ClassMetadata<T> $metadata
1313
* @param array<string, mixed> $data
14+
* @param array<string, mixed> $context
1415
*
1516
* @return T
1617
*
1718
* @template T of object
1819
*/
19-
public function hydrate(ClassMetadata $metadata, array $data, Stack $stack): object;
20+
public function hydrate(ClassMetadata $metadata, array $data, array $context, Stack $stack): object;
2021

2122
/**
22-
* @param ClassMetadata<T> $metadata
23-
* @param T $object
23+
* @param ClassMetadata<T> $metadata
24+
* @param T $object
25+
* @param array<string, mixed> $context
2426
*
2527
* @return array<string, mixed>
2628
*
2729
* @template T of object
2830
*/
29-
public function extract(ClassMetadata $metadata, object $object, Stack $stack): array;
31+
public function extract(ClassMetadata $metadata, object $object, array $context, Stack $stack): array;
3032
}

src/Middleware/TransformMiddleware.php

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Patchlevel\Hydrator\DenormalizationFailure;
99
use Patchlevel\Hydrator\Metadata\ClassMetadata;
1010
use Patchlevel\Hydrator\NormalizationFailure;
11+
use Patchlevel\Hydrator\Normalizer\ContextAwareNormalizer;
1112
use Patchlevel\Hydrator\TypeMismatch;
1213
use ReflectionParameter;
1314
use Throwable;
@@ -25,12 +26,13 @@ final class TransformMiddleware implements Middleware
2526
/**
2627
* @param ClassMetadata<T> $metadata
2728
* @param array<string, mixed> $data
29+
* @param array<string, mixed> $context
2830
*
2931
* @return T
3032
*
3133
* @template T of object
3234
*/
33-
public function hydrate(ClassMetadata $metadata, array $data, Stack $stack): object
35+
public function hydrate(ClassMetadata $metadata, array $data, array $context, Stack $stack): object
3436
{
3537
$object = $metadata->newInstance();
3638

@@ -58,17 +60,20 @@ public function hydrate(ClassMetadata $metadata, array $data, Stack $stack): obj
5860
continue;
5961
}
6062

61-
$normalizer = $propertyMetadata->normalizer;
62-
63-
if ($normalizer) {
63+
if ($propertyMetadata->normalizer) {
6464
try {
65-
/** @psalm-suppress MixedAssignment */
66-
$value = $normalizer->denormalize($data[$propertyMetadata->fieldName]);
65+
if ($propertyMetadata->normalizer instanceof ContextAwareNormalizer) {
66+
/** @psalm-suppress MixedAssignment */
67+
$value = $propertyMetadata->normalizer->denormalize($data[$propertyMetadata->fieldName], $context);
68+
} else {
69+
/** @psalm-suppress MixedAssignment */
70+
$value = $propertyMetadata->normalizer->denormalize($data[$propertyMetadata->fieldName]);
71+
}
6772
} catch (Throwable $e) {
6873
throw new DenormalizationFailure(
6974
$metadata->className,
7075
$propertyMetadata->propertyName,
71-
$normalizer::class,
76+
$propertyMetadata->normalizer::class,
7277
$e,
7378
);
7479
}
@@ -90,8 +95,12 @@ public function hydrate(ClassMetadata $metadata, array $data, Stack $stack): obj
9095
return $object;
9196
}
9297

93-
/** @return array<string, mixed> */
94-
public function extract(ClassMetadata $metadata, object $object, Stack $stack): array
98+
/**
99+
* @param array<string, mixed> $context
100+
*
101+
* @return array<string, mixed>
102+
*/
103+
public function extract(ClassMetadata $metadata, object $object, array $context, Stack $stack): array
95104
{
96105
$objectId = spl_object_id($object);
97106

@@ -110,10 +119,18 @@ public function extract(ClassMetadata $metadata, object $object, Stack $stack):
110119
foreach ($metadata->properties as $propertyMetadata) {
111120
if ($propertyMetadata->normalizer) {
112121
try {
113-
/** @psalm-suppress MixedAssignment */
114-
$data[$propertyMetadata->fieldName] = $propertyMetadata->normalizer->normalize(
115-
$propertyMetadata->getValue($object),
116-
);
122+
if ($propertyMetadata->normalizer instanceof ContextAwareNormalizer) {
123+
/** @psalm-suppress MixedAssignment */
124+
$data[$propertyMetadata->fieldName] = $propertyMetadata->normalizer->normalize(
125+
$propertyMetadata->getValue($object),
126+
$context,
127+
);
128+
} else {
129+
/** @psalm-suppress MixedAssignment */
130+
$data[$propertyMetadata->fieldName] = $propertyMetadata->normalizer->normalize(
131+
$propertyMetadata->getValue($object),
132+
);
133+
}
117134
} catch (CircularReference $e) {
118135
throw $e;
119136
} catch (Throwable $e) {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Patchlevel\Hydrator\Normalizer;
6+
7+
interface ContextAwareNormalizer extends Normalizer
8+
{
9+
/**
10+
* @param array<string, mixed> $context
11+
*
12+
* @throws InvalidArgument
13+
*/
14+
public function normalize(mixed $value, array $context = []): mixed;
15+
16+
/**
17+
* @param array<string, mixed> $context
18+
*
19+
* @throws InvalidArgument
20+
*/
21+
public function denormalize(mixed $value, array $context = []): mixed;
22+
}

src/Normalizer/ObjectNormalizer.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use function is_array;
1616

1717
#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_CLASS)]
18-
final class ObjectNormalizer implements Normalizer, TypeAwareNormalizer, HydratorAwareNormalizer
18+
final class ObjectNormalizer implements ContextAwareNormalizer, TypeAwareNormalizer, HydratorAwareNormalizer
1919
{
2020
private Hydrator|null $hydrator = null;
2121

@@ -25,8 +25,12 @@ public function __construct(
2525
) {
2626
}
2727

28-
/** @return array<string, mixed>|null */
29-
public function normalize(mixed $value): array|null
28+
/**
29+
* @param array<string, mixed> $context
30+
*
31+
* @return array<string, mixed>|null
32+
*/
33+
public function normalize(mixed $value, array $context = []): array|null
3034
{
3135
if (!$this->hydrator) {
3236
throw new MissingHydrator();
@@ -42,10 +46,11 @@ public function normalize(mixed $value): array|null
4246
throw InvalidArgument::withWrongType($className . '|null', $value);
4347
}
4448

45-
return $this->hydrator->extract($value);
49+
return $this->hydrator->extract($value, $context);
4650
}
4751

48-
public function denormalize(mixed $value): object|null
52+
/** @param array<string, mixed> $context */
53+
public function denormalize(mixed $value, array $context = []): object|null
4954
{
5055
if (!$this->hydrator) {
5156
throw new MissingHydrator();
@@ -61,7 +66,7 @@ public function denormalize(mixed $value): object|null
6166

6267
$className = $this->getClassName();
6368

64-
return $this->hydrator->hydrate($className, $value);
69+
return $this->hydrator->hydrate($className, $value, $context);
6570
}
6671

6772
public function setHydrator(Hydrator $hydrator): void

tests/Unit/Cryptography/CryptographyMiddlewareTest.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ public function testHydrate(): void
3232

3333
$stack = new Stack([$otherMiddleware]);
3434

35-
$otherMiddleware->expects($this->once())->method('hydrate')->with($metadata, ['name' => 'bar'], $stack)->willReturn($object);
35+
$otherMiddleware->expects($this->once())->method('hydrate')->with($metadata, ['name' => 'bar'], [], $stack)->willReturn($object);
3636

37-
$result = $cryptographyMiddleware->hydrate($metadata, ['name' => 'foo'], $stack);
37+
$result = $cryptographyMiddleware->hydrate($metadata, ['name' => 'foo'], [], $stack);
3838

3939
self::assertSame($object, $result);
4040
}
@@ -54,9 +54,9 @@ public function testExtract(): void
5454

5555
$stack = new Stack([$otherMiddleware]);
5656

57-
$otherMiddleware->expects($this->once())->method('extract')->with($metadata, $object, $stack)->willReturn(['name' => 'foo']);
57+
$otherMiddleware->expects($this->once())->method('extract')->with($metadata, $object, [], $stack)->willReturn(['name' => 'foo']);
5858

59-
$result = $cryptographyMiddleware->extract($metadata, $object, $stack);
59+
$result = $cryptographyMiddleware->extract($metadata, $object, [], $stack);
6060

6161
self::assertSame(['name' => 'bar'], $result);
6262
}

tests/Unit/MetadataHydratorTest.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -498,27 +498,29 @@ public function guess(ObjectType $type): Normalizer|null
498498
/**
499499
* @param ClassMetadata<T> $metadata
500500
* @param array<string, mixed> $data
501+
* @param array<string, mixed> $context
501502
*
502503
* @return T
503504
*
504505
* @template T of object
505506
*/
506-
public function hydrate(ClassMetadata $metadata, array $data, Stack $stack): object
507+
public function hydrate(ClassMetadata $metadata, array $data, array $context, Stack $stack): object
507508
{
508-
return $stack->next()->hydrate($metadata, $data, $stack);
509+
return $stack->next()->hydrate($metadata, $data, $context, $stack);
509510
}
510511

511512
/**
512-
* @param ClassMetadata<T> $metadata
513-
* @param T $object
513+
* @param ClassMetadata<T> $metadata
514+
* @param T $object
515+
* @param array<string, mixed> $context
514516
*
515517
* @return array<string, mixed>
516518
*
517519
* @template T of object
518520
*/
519-
public function extract(ClassMetadata $metadata, object $object, Stack $stack): array
521+
public function extract(ClassMetadata $metadata, object $object, array $context, Stack $stack): array
520522
{
521-
return $stack->next()->extract($metadata, $object, $stack);
523+
return $stack->next()->extract($metadata, $object, $context, $stack);
522524
}
523525
},
524526
],

tests/Unit/Middleware/TransformerMiddlewareTest.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public function testHydrate(): void
2929
$event = $middleware->hydrate(
3030
$this->classMetadata(ProfileCreated::class),
3131
['profileId' => '1', 'email' => 'info@patchlevel.de'],
32+
[],
3233
new Stack([]),
3334
);
3435

@@ -47,6 +48,7 @@ public function testExtract(): void
4748
ProfileId::fromString('1'),
4849
Email::fromString('info@patchlevel.de'),
4950
),
51+
[],
5052
new Stack([]),
5153
);
5254

0 commit comments

Comments
 (0)