forked from Crell/Serde
-
Notifications
You must be signed in to change notification settings - Fork 0
/
NativeSerializeExporter.php
82 lines (64 loc) · 2.66 KB
/
NativeSerializeExporter.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<?php
declare(strict_types=1);
namespace Crell\Serde\PropertyHandler;
use Crell\Serde\Attributes\Field;
use Crell\Serde\CollectionItem;
use Crell\Serde\Deserializer;
use Crell\Serde\Dict;
use Crell\Serde\DeformatterResult;
use Crell\Serde\Serializer;
use Crell\Serde\TypeCategory;
class NativeSerializeExporter implements Exporter, Importer
{
public function exportValue(Serializer $serializer, Field $field, mixed $value, mixed $runningValue): mixed
{
$propValues = $value->__serialize();
$dict = new Dict();
$dict->items = [];
foreach ($propValues as $k => $v) {
$dict->items[] = new CollectionItem(
field: Field::create(serializedName: "$k", phpType: \get_debug_type($v)),
value: $v,
);
}
if ($map = $serializer->typeMapper->typeMapForField($field)) {
$f = Field::create(serializedName: $map->keyField(), phpType: 'string');
// The type map field MUST come first so that streaming deformatters
// can know their context.
$dict->items = [new CollectionItem(field: $f, value: $map->findIdentifier($value::class)), ...$dict->items];
}
return $serializer->formatter->serializeDictionary($runningValue, $field, $dict, $serializer);
}
public function canExport(Field $field, mixed $value, string $format): bool
{
return $field->typeCategory === TypeCategory::Object && method_exists($value, '__serialize');
}
public function importValue(Deserializer $deserializer, Field $field, mixed $source): mixed
{
// The data may not have any relation at all to the original object's
// properties. So deserialize as a basic dictionary instead.
$dict = $deserializer->deformatter->deserializeDictionary($source, $field, $deserializer);
if ($dict instanceof DeformatterResult) {
return null;
}
if ($dict === null) {
return null;
}
$class = $deserializer->typeMapper->getTargetClass($field, $dict);
if (is_null($class)) {
return null;
}
// Make an empty instance of the target class.
$rClass = new \ReflectionClass($class);
$new = $rClass->newInstanceWithoutConstructor();
// We wouldn't have gotten here unless this method is defined, but PHPStan
// can't know that.
// @phpstan-ignore-next-line
$new->__unserialize($dict);
return $new;
}
public function canImport(Field $field, string $format): bool
{
return $field->typeCategory === TypeCategory::Object && method_exists($field->phpType, '__unserialize');
}
}