Skip to content

Commit 13d7da9

Browse files
committed
Adjusted serializers to account for already serialized data
1 parent 04ea37a commit 13d7da9

File tree

4 files changed

+97
-9
lines changed

4 files changed

+97
-9
lines changed

docs/Quickstart.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ The package allows you to hydrate these data objects from other types, for examp
5454
$todo = Todo::from([
5555
'title' => 'Learn PHP DTO',
5656
'content' => 'Learn how to use PHP DTO',
57-
'status' => 'ready',
57+
'status' => 'ready', // Or Status::READY
5858
'dueDate' => '2025-01-01T00:00:00+00:00'
5959
]);
6060
```

src/Serializers/DataSerializer.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
use Exception;
66
use Nuxtifyts\PhpDto\Concerns\SerializesArrayOfItems;
77
use Nuxtifyts\PhpDto\Contexts\PropertyContext;
8+
use Nuxtifyts\PhpDto\Contexts\TypeContext;
89
use Nuxtifyts\PhpDto\Contracts\BaseData as BaseDataContract;
910
use Nuxtifyts\PhpDto\Contracts\SerializesArrayOfItems as SerializesArrayOfItemsContract;
11+
use Nuxtifyts\PhpDto\Data;
1012
use Nuxtifyts\PhpDto\Enums\Property\Type;
1113
use Nuxtifyts\PhpDto\Exceptions\DeserializeException;
1214
use Nuxtifyts\PhpDto\Exceptions\SerializeException;
@@ -43,10 +45,10 @@ protected function serializeItem(mixed $item, PropertyContext $property, object
4345
*/
4446
protected function deserializeItem(mixed $item, PropertyContext $property): ?BaseDataContract
4547
{
46-
if (is_array($item)) {
47-
$typeContexts = $property->getFilteredTypeContexts(...self::supportedTypes())
48-
?: $property->getFilteredSubTypeContexts(...self::supportedTypes());
48+
$typeContexts = $property->getFilteredTypeContexts(...self::supportedTypes())
49+
?: $property->getFilteredSubTypeContexts(...self::supportedTypes());
4950

51+
if (is_array($item)) {
5052
foreach ($typeContexts as $typeContext) {
5153
try {
5254
if (!$typeContext->reflection?->implementsInterface(BaseDataContract::class)) {
@@ -70,6 +72,15 @@ protected function deserializeItem(mixed $item, PropertyContext $property): ?Bas
7072
}
7173
// @codeCoverageIgnoreEnd
7274
}
75+
} elseif ($item instanceof Data) {
76+
if (
77+
array_any(
78+
$typeContexts,
79+
static fn (TypeContext $type) => (bool) $type->reflection?->isInstance($item)
80+
)
81+
) {
82+
return $item;
83+
}
7384
}
7485

7586
return is_null($item) && $property->isNullable

src/Serializers/DateTimeSerializer.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
namespace Nuxtifyts\PhpDto\Serializers;
44

5-
use ArrayAccess;
65
use DateTimeImmutable;
76
use DateTimeInterface;
87
use Exception;
98
use Nuxtifyts\PhpDto\Contexts\PropertyContext;
9+
use Nuxtifyts\PhpDto\Contexts\TypeContext;
1010
use Nuxtifyts\PhpDto\Contracts\SerializesArrayOfItems as SerializesArrayOfItemsContract;
1111
use Nuxtifyts\PhpDto\Concerns\SerializesArrayOfItems;
1212
use Nuxtifyts\PhpDto\Enums\Property\Type;
@@ -43,10 +43,10 @@ protected function serializeItem(mixed $item, PropertyContext $property, object
4343
*/
4444
protected function deserializeItem(mixed $item, PropertyContext $property): ?DateTimeInterface
4545
{
46-
if (is_string($item)) {
47-
$typeContexts = $property->getFilteredTypeContexts(...self::supportedTypes())
48-
?: $property->getFilteredSubTypeContexts(...self::supportedTypes());
46+
$typeContexts = $property->getFilteredTypeContexts(...self::supportedTypes())
47+
?: $property->getFilteredSubTypeContexts(...self::supportedTypes());
4948

49+
if (is_string($item)) {
5050
foreach ($typeContexts as $typeContext) {
5151
try {
5252
if (!$typeContext->reflection?->implementsInterface(DateTimeInterface::class)) {
@@ -71,7 +71,12 @@ protected function deserializeItem(mixed $item, PropertyContext $property): ?Dat
7171
// @codeCoverageIgnoreEnd
7272
}
7373
} elseif ($item instanceof DateTimeInterface) {
74-
return $item;
74+
if (array_any(
75+
$typeContexts,
76+
static fn(TypeContext $typeContext) => (bool) $typeContext->reflection?->isInstance($item)
77+
)) {
78+
return $item;
79+
}
7580
}
7681

7782
return is_null($item) && $property->isNullable

tests/Unit/Concerns/BaseDataTest.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
use Nuxtifyts\PhpDto\Exceptions\SerializeException;
99
use Nuxtifyts\PhpDto\Pipelines\DeserializePipeline\DeserializePipelinePassable;
1010
use Nuxtifyts\PhpDto\Pipelines\DeserializePipeline\RefineDataPipe;
11+
use Nuxtifyts\PhpDto\Serializers\BackedEnumSerializer;
12+
use Nuxtifyts\PhpDto\Serializers\DataSerializer;
13+
use Nuxtifyts\PhpDto\Serializers\DateTimeSerializer;
1114
use Nuxtifyts\PhpDto\Support\Passable;
1215
use Nuxtifyts\PhpDto\Support\Pipe;
1316
use Nuxtifyts\PhpDto\Support\Pipeline;
@@ -32,6 +35,7 @@
3235
use PHPUnit\Framework\Attributes\Test;
3336
use PHPUnit\Framework\Attributes\UsesClass;
3437
use Throwable;
38+
use DateTimeInterface;
3539

3640
#[CoversClass(Data::class)]
3741
#[CoversClass(DeserializeException::class)]
@@ -41,6 +45,9 @@
4145
#[CoversClass(DeserializePipelinePassable::class)]
4246
#[CoversClass(RefineDataPipe::class)]
4347
#[CoversClass(Passable::class)]
48+
#[CoversClass(DateTimeSerializer::class)]
49+
#[CoversClass(DataSerializer::class)]
50+
#[CoversClass(BackedEnumSerializer::class)]
4451
#[UsesClass(PersonData::class)]
4552
#[UsesClass(UnionTypedData::class)]
4653
#[UsesClass(YesOrNoData::class)]
@@ -271,6 +278,41 @@ public static function will_perform_serialization_and_deserialization_data_provi
271278
],
272279
'expectedSerializedData' => $data
273280
],
281+
'Refundable item data 3' => [
282+
'dtoClass' => RefundableItemData::class,
283+
'data' => $data = [
284+
'id' => 'id2',
285+
'refundable' => YesNoBackedEnum::NO,
286+
'refundableUntil' => null
287+
],
288+
'expectedProperties' => [
289+
'id' => 'id2',
290+
'refundable' => YesNoBackedEnum::NO,
291+
'refundableUntil' => null
292+
],
293+
'expectedSerializedData' => [
294+
...$data,
295+
'refundable' => YesNoBackedEnum::NO->value
296+
]
297+
],
298+
'Refundable item data 4' => [
299+
'dtoClass' => RefundableItemData::class,
300+
'data' => $data = [
301+
'id' => 'id',
302+
'refundable' => YesNoBackedEnum::YES->value,
303+
'refundableUntil' => new DateTimeImmutable('2021-01-01T00:00:00+00:00')
304+
],
305+
'expectedProperties' => [
306+
'id' => 'id',
307+
'refundable' => YesNoBackedEnum::YES,
308+
'refundableUntil' => new DateTimeImmutable('2021-01-01T00:00:00+00:00')
309+
],
310+
'expectedSerializedData' => [
311+
...$data,
312+
'refundableUntil' => new DateTimeImmutable('2021-01-01T00:00:00+00:00')
313+
->format(DateTimeInterface::ATOM)
314+
]
315+
],
274316
'Address data 1' => [
275317
'dtoClass' => AddressData::class,
276318
'data' => $data = [
@@ -469,6 +511,36 @@ public static function will_perform_serialization_and_deserialization_data_provi
469511
],
470512
'expectedSerializedData' => $data
471513
],
514+
'User group data 3' => [
515+
'dtoClass' => UserGroupData::class,
516+
'data' => $data = [
517+
'name' => 'Group name 2',
518+
'users' => [
519+
new UserData('John', 'Doe'),
520+
new UserData('Jane', 'Doe')
521+
]
522+
],
523+
'expectedProperties' => [
524+
'name' => 'Group name 2',
525+
'users' => [
526+
new UserData('John', 'Doe'),
527+
new UserData('Jane', 'Doe')
528+
]
529+
],
530+
'expectedSerializedData' => [
531+
...$data,
532+
'users' => [
533+
[
534+
'firstName' => 'John',
535+
'lastName' => 'Doe'
536+
],
537+
[
538+
'firstName' => 'Jane',
539+
'lastName' => 'Doe'
540+
]
541+
]
542+
]
543+
],
472544
'Computed properties data' => [
473545
'dtoClass' => ComputedPropertiesData::class,
474546
'data' => $data = [

0 commit comments

Comments
 (0)