Completed
Push — master ( 9c5fdf...27a5d2 )
by John
7s
created

ObjectSerializer::serialize()   C

Complexity

Conditions 9
Paths 1

Size

Total Lines 50
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 50
rs 6
c 0
b 0
f 0
cc 9
eloc 33
nc 1
nop 2
1
<?php declare(strict_types = 1);
2
/*
3
 * This file is part of the KleijnWeb\SwaggerBundle package.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace KleijnWeb\SwaggerBundle\Serialize\Serializer;
10
11
use KleijnWeb\SwaggerBundle\Document\Specification;
12
use KleijnWeb\SwaggerBundle\Request\ParameterCoercer;
13
use KleijnWeb\SwaggerBundle\Serialize\SerializationTypeResolver;
14
use KleijnWeb\SwaggerBundle\Serialize\Serializer;
15
16
/**
17
 * (De-) Serializes objects using JSON Schema
18
 *
19
 * @author John Kleijn <[email protected]>
20
 */
21
class ObjectSerializer implements Serializer
22
{
23
    /**
24
     * @var SerializationTypeResolver
25
     */
26
    private $serializationTypeResolver;
27
28
    /**
29
     * ObjectSerializer constructor.
30
     *
31
     * @param SerializationTypeResolver $serializationTypeResolver
32
     */
33
    public function __construct(SerializationTypeResolver $serializationTypeResolver)
34
    {
35
        $this->serializationTypeResolver = $serializationTypeResolver;
36
    }
37
38
    /**
39
     * @param mixed         $data
40
     * @param Specification $specification
41
     *
42
     * @return string
43
     */
44
    public function serialize($data, Specification $specification): string
45
    {
46
        $export = function ($item, \stdClass $schema) use (&$export) {
47
            if ($item instanceof \DateTimeInterface) {
48
                if ($schema->format == 'date') {
49
                    return $item->format('Y-m-d');
50
                }
51
                if ($schema->format == 'date-time') {
52
                    return $item->format(\DateTime::ISO8601);
53
                }
54
                throw new \UnexpectedValueException;
55
            }
56
            switch ($schema->type) {
57
                case 'array':
58
                    return array_map(function ($value) use (&$export, $schema) {
59
                        return $export($value, $schema->items);
60
                    }, $item);
61
                case 'object':
62
                    $class  = get_class($item);
63
                    $data   = (array)$item;
64
                    $offset = strlen($class) + 2;
65
66
                    $array = array_filter(array_combine(array_map(function ($k) use ($offset) {
67
                        return substr($k, $offset);
68
                    }, array_keys($data)), array_values($data)));
69
70
                    foreach ($array as $name => $value) {
71
                        $array[$name] = isset($schema->properties->$name)
72
                            ? $export($value, $schema->properties->$name)
73
                            : $value;
74
                    }
75
76
                    return $array;
77
                default:
78
                    if (!is_scalar($item)) {
79
                        throw new \UnexpectedValueException;
80
                    }
81
82
                    return $item;
83
            }
84
85
        };
86
87
        return json_encode(
88
            $export(
89
                $data,
90
                $specification->getResourceDefinition($this->serializationTypeResolver->reverseLookup(get_class($data)))
91
            )
92
        );
93
    }
94
95
    /**
96
     * @param mixed         $data
97
     * @param string        $type
98
     * @param Specification $specification
99
     *
100
     * @return mixed
101
     */
102
    public function deserialize($data, string $type, Specification $specification)
103
    {
104
        $import = function ($item, \stdClass $schema) use (&$import) {
105
            switch ($schema->type) {
106
                case 'array':
107
                    return array_map(function ($value) use (&$import, $schema) {
108
                        return $import($value, $schema->items);
109
                    }, $item);
110
                case 'object':
111
                    $fqcn      = $this->serializationTypeResolver->resolveUsingSchema($schema);
112
                    $object    = unserialize(sprintf('O:%d:"%s":0:{}', strlen($fqcn), $fqcn));
113
                    $reflector = new \ReflectionObject($object);
114
115
                    foreach ($item as $name => $value) {
116
                        if (!$reflector->hasProperty($name)) {
117
                            continue;
118
                        }
119
                        $value = isset($schema->properties->$name)
120
                            ? $import($value, $schema->properties->$name)
121
                            : $value;
122
123
                        $attribute = $reflector->getProperty($name);
124
                        $attribute->setAccessible(true);
125
                        $attribute->setValue($object, $value);
126
                    }
127
128
                    return $object;
129
                default:
130
                    return ParameterCoercer::coerceParameter($schema, $item);
131
            }
132
        };
133
134
        return $import(
135
            json_decode($data, true),
136
            $specification->getResourceDefinition($this->serializationTypeResolver->reverseLookup($type))
137
        );
138
    }
139
}
140