Skip to content

Commit 2fb3ff1

Browse files
authored
Merge pull request #174 from patchlevel/object-to-populate
add object to populate feature
2 parents dba0dff + 7a2c491 commit 2fb3ff1

7 files changed

Lines changed: 87 additions & 2 deletions

File tree

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,24 @@ $oldEvent == $event // true
125125
> [!WARNING]
126126
> It is important to know that the constructor is not called!
127127
128+
#### Object to populate
129+
130+
If you want to hydrate an object that already exists, you can specify the object to populate.
131+
This is useful if you want to update an existing object.
132+
133+
```php
134+
$dto = new Dto();
135+
136+
$event = $hydrator->hydrate(
137+
$dto::class,
138+
[
139+
'name' => 'patchlevel',
140+
], [
141+
MetadataHydrator::OBJECT_TO_POPULATE => $dto,
142+
],
143+
);
144+
```
145+
128146
### Normalizer
129147

130148
For more complex structures, i.e. non-scalar data types, we use normalizers.

phpstan-baseline.neon

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,36 @@ parameters:
114114
count: 3
115115
path: src/Metadata/AttributeMetadataFactory.php
116116

117+
-
118+
message: '#^Method Patchlevel\\Hydrator\\MetadataHydrator\:\:doHydrate\(\) should return T of object but returns mixed\.$#'
119+
identifier: return.type
120+
count: 1
121+
path: src/MetadataHydrator.php
122+
123+
-
124+
message: '#^Parameter \#1 \$object of method Patchlevel\\Hydrator\\Metadata\\CallbackMetadata\:\:invoke\(\) expects object, mixed given\.$#'
125+
identifier: argument.type
126+
count: 1
127+
path: src/MetadataHydrator.php
128+
129+
-
130+
message: '#^Parameter \#1 \$object of method Patchlevel\\Hydrator\\Metadata\\PropertyMetadata\:\:setValue\(\) expects object, mixed given\.$#'
131+
identifier: argument.type
132+
count: 2
133+
path: src/MetadataHydrator.php
134+
135+
-
136+
message: '#^Method Patchlevel\\Hydrator\\Middleware\\TransformMiddleware\:\:hydrate\(\) should return T of object but returns mixed\.$#'
137+
identifier: return.type
138+
count: 1
139+
path: src/Middleware/TransformMiddleware.php
140+
141+
-
142+
message: '#^Parameter \#1 \$object of method Patchlevel\\Hydrator\\Metadata\\PropertyMetadata\:\:setValue\(\) expects object, mixed given\.$#'
143+
identifier: argument.type
144+
count: 2
145+
path: src/Middleware/TransformMiddleware.php
146+
117147
-
118148
message: '#^Property Patchlevel\\Hydrator\\Normalizer\\EnumNormalizer\:\:\$enum \(class\-string\<BackedEnum\>\|null\) does not accept string\.$#'
119149
identifier: assign.propertyType

src/HydratorWithContext.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
interface HydratorWithContext extends Hydrator
88
{
9+
public const OBJECT_TO_POPULATE = 'object_to_populate';
10+
911
/**
1012
* @param class-string<T> $class
1113
* @param array<string, mixed> $data

src/MetadataHydrator.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ private function doHydrate(ClassMetadata $metadata, array $data, array $context
104104
$data = $this->eventDispatcher->dispatch(new PreHydrate($data, $metadata))->data;
105105
}
106106

107-
$object = $metadata->newInstance();
107+
$object = $context[self::OBJECT_TO_POPULATE] ?? $metadata->newInstance();
108+
unset($context[self::OBJECT_TO_POPULATE]);
108109

109110
$constructorParameters = null;
110111

src/Middleware/TransformMiddleware.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Patchlevel\Hydrator\CircularReference;
88
use Patchlevel\Hydrator\DenormalizationFailure;
9+
use Patchlevel\Hydrator\HydratorWithContext;
910
use Patchlevel\Hydrator\Metadata\ClassMetadata;
1011
use Patchlevel\Hydrator\NormalizationFailure;
1112
use Patchlevel\Hydrator\Normalizer\NormalizerWithContext;
@@ -34,7 +35,8 @@ final class TransformMiddleware implements Middleware
3435
*/
3536
public function hydrate(ClassMetadata $metadata, array $data, array $context, Stack $stack): object
3637
{
37-
$object = $metadata->newInstance();
38+
$object = $context[HydratorWithContext::OBJECT_TO_POPULATE] ?? $metadata->newInstance();
39+
unset($context[HydratorWithContext::OBJECT_TO_POPULATE]);
3840

3941
$constructorParameters = null;
4042

tests/Unit/MetadataHydratorTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,22 @@ public function testHydrateWithInlineNormalizer(): void
291291
self::assertEquals($expected, $event);
292292
}
293293

294+
public function testHydrateWithObjectToPopulate(): void
295+
{
296+
$id = ProfileId::fromString('1');
297+
$dto = new ProfileCreated($id, Email::fromString('foo@patchlevel.de'));
298+
299+
$processedDto = $this->hydrator->hydrate(
300+
$dto::class,
301+
['email' => 'other@patchlevel.de'],
302+
[MetadataHydrator::OBJECT_TO_POPULATE => $dto],
303+
);
304+
305+
self::assertSame($dto, $processedDto);
306+
self::assertSame($id, $processedDto->profileId);
307+
self::assertEquals(Email::fromString('other@patchlevel.de'), $processedDto->email);
308+
}
309+
294310
public function testDenormalizationFailure(): void
295311
{
296312
$this->expectException(DenormalizationFailure::class);

tests/Unit/StackHydratorTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,22 @@ public function testHydrateWithContext(): void
311311
self::assertEquals($expect, $object);
312312
}
313313

314+
public function testHydrateWithObjectToPopulate(): void
315+
{
316+
$id = ProfileId::fromString('1');
317+
$dto = new ProfileCreated($id, Email::fromString('foo@patchlevel.de'));
318+
319+
$processedDto = $this->hydrator->hydrate(
320+
$dto::class,
321+
['email' => 'other@patchlevel.de'],
322+
[StackHydrator::OBJECT_TO_POPULATE => $dto],
323+
);
324+
325+
self::assertSame($dto, $processedDto);
326+
self::assertSame($id, $processedDto->profileId);
327+
self::assertEquals(Email::fromString('other@patchlevel.de'), $processedDto->email);
328+
}
329+
314330
#[RequiresPhp('>=8.5')]
315331
public function testHydrateWithInlineNormalizer(): void
316332
{

0 commit comments

Comments
 (0)