Passed
Pull Request — master (#7)
by Vincent
05:41
created

Serializer   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 191
Duplicated Lines 0 %

Test Coverage

Coverage 90.16%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 52
c 1
b 0
f 0
dl 0
loc 191
ccs 55
cts 61
cp 0.9016
rs 10
wmc 27

13 Methods

Rating   Name   Duplication   Size   Complexity  
A getLoader() 0 3 1
A toJson() 0 5 1
A toBinary() 0 3 1
A serialize() 0 11 3
A supports() 0 3 1
A fromJson() 0 5 1
A deserialize() 0 11 3
A denormalize() 0 29 6
A toArray() 0 3 1
A fromArray() 0 3 1
A __construct() 0 3 1
A normalize() 0 26 6
A fromBinary() 0 3 1
1
<?php
2
3
namespace Bdf\Serializer;
4
5
use Bdf\Serializer\Context\DenormalizationContext;
6
use Bdf\Serializer\Context\NormalizationContext;
7
use Bdf\Serializer\Normalizer\NormalizerInterface;
8
use Bdf\Serializer\Normalizer\NormalizerLoaderInterface;
9
use Bdf\Serializer\Type\Type;
10
use Bdf\Serializer\Type\TypeFactory;
11
12
/**
13
 * Serializer
14
 * 
15
 * @author  Seb
16
 *
17
 * @implements NormalizerInterface<mixed>
18
 */
19
class Serializer implements SerializerInterface, NormalizerInterface, BinarySerializerInterface
20
{
21
    /**
22
     * The loader of normalizers
23
     *
24
     * @var NormalizerLoaderInterface
25
     */
26
    private $loader;
27
28
    /**
29
     * Serializer constructor.
30
     *
31
     * @param NormalizerLoaderInterface $loader
32
     */
33 81
    public function __construct(NormalizerLoaderInterface $loader)
34
    {
35 81
        $this->loader = $loader;
36 81
    }
37
38
    /**
39
     * {@inheritdoc}
40
     */
41 13
    public function serialize($data, $format, array $context = [])
42
    {
43 13
        switch ($format) {
44 13
            case 'json':
45 12
                return $this->toJson($data, $context);
46
47 1
            case 'binary':
48
                return $this->toBinary($data, $context);
49
50
            default:
51 1
                return $this->toArray($data, $context);
52
        }
53
    }
54
55
    /**
56
     * {@inheritdoc}
57
     */
58 15
    public function toJson($data, array $context = [])
59
    {
60 15
        $context = new NormalizationContext($this, $context);
61
62 15
        return json_encode($this->normalize($data, $context), $context->option('json_options', 0));
0 ignored issues
show
Bug introduced by
0 of type integer is incompatible with the type Bdf\Serializer\Context\T expected by parameter $default of Bdf\Serializer\Context\Context::option(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

62
        return json_encode($this->normalize($data, $context), $context->option('json_options', /** @scrutinizer ignore-type */ 0));
Loading history...
63
    }
64
65
    /**
66
     * {@inheritdoc}
67
     */
68
    public function toBinary($data, array $context = [])
69
    {
70
        return igbinary_serialize($this->normalize($data, new NormalizationContext($this, $context)));
71
    }
72
73
    /**
74
     * {@inheritdoc}
75
     */
76 33
    public function toArray($data, array $context = [])
77
    {
78 33
        return $this->normalize($data, new NormalizationContext($this, $context));
79
    }
80
81
    /**
82
     * {@inheritdoc}
83
     */
84 48
    public function normalize($data, NormalizationContext $context)
85
    {
86 48
        if (null === $data || is_scalar($data)) {
87 42
            return $data;
88
        }
89
90 47
        if (is_array($data)) {
91 6
            $normalized = [];
92
93 6
            foreach ($data as $key => $value) {
94 6
                $normalized[$key] = $this->normalize($value, $context);
95
            }
96
97 6
            return $normalized;
98
        }
99
100 46
        $normalized = $this->loader->getNormalizer($data)->normalize($data, $context);
101
102 44
        if ($context->includeMetaType()) {
103
            return [
104 4
                '@type' => get_class($data),
105 4
                'data'  => $normalized,
106
            ];
107
        }
108
109 40
        return $normalized;
110
    }
111
112
    /**
113
     * {@inheritdoc}
114
     */
115 4
    public function deserialize($data, $type, $format, array $context = [])
116
    {
117 4
        switch ($format) {
118 4
            case 'json':
119 3
                return $this->fromJson($data, $type, $context);
120
121 1
            case 'binary':
122
                return $this->fromBinary($data, $type, $context);
123
124
            default:
125 1
                return $this->fromArray($data, $type, $context);
126
        }
127
    }
128
129
    /**
130
     * {@inheritdoc}
131
     */
132 28
    public function fromArray(array $data, $type, array $context = [])
133
    {
134 28
        return $this->denormalize($data, TypeFactory::createType($type), new DenormalizationContext($this, $context));
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140 6
    public function fromJson(string $json, $type, array $context = [])
141
    {
142 6
        $context = new DenormalizationContext($this, $context);
143
144 6
        return $this->denormalize(json_decode($json, true, 512, $context->option('json_options', 0)), TypeFactory::createType($type), $context);
0 ignored issues
show
Bug introduced by
0 of type integer is incompatible with the type Bdf\Serializer\Context\T expected by parameter $default of Bdf\Serializer\Context\Context::option(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

144
        return $this->denormalize(json_decode($json, true, 512, $context->option('json_options', /** @scrutinizer ignore-type */ 0)), TypeFactory::createType($type), $context);
Loading history...
145
    }
146
147
    /**
148
     * {@inheritdoc}
149
     */
150
    public function fromBinary(string $raw, $type, array $context = [])
151
    {
152
        return $this->denormalize(igbinary_unserialize($raw), TypeFactory::createType($type), new DenormalizationContext($this, $context));
153
    }
154
155
    /**
156
     * {@inheritdoc}
157
     *
158
     * @template T
159
     * @param mixed $data
160
     * @param Type<T> $type
161
     * @return T|T[]
162
     */
163 34
    public function denormalize($data, Type $type, DenormalizationContext $context)
164
    {
165 34
        if (!is_scalar($data) && !is_array($data)) {
166 2
            return $data;
167
        }
168
169 34
        $type = $type->hint($data);
170
171 34
        if ($type->isArray()) {
172 10
            $denormalized = [];
173
174 10
            foreach ((array)$data as $key => $value) {
175 10
                $denormalized[$key] = $this->denormalize($value, $type->subType() ?? TypeFactory::mixedType(), $context);
176
            }
177
178 10
            return $denormalized;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $denormalized returns the type array which is incompatible with the return type mandated by Bdf\Serializer\Normalize...nterface::denormalize() of Bdf\Serializer\Normalizer\T.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
179
        }
180
181 34
        if ($type->isBuildin()) {
182 26
            return $type->convert($data);
183
        }
184
185
        /**
186
         * @var NormalizerInterface<T> $normalizer
187
         * @psalm-suppress ArgumentTypeCoercion
188
         */
189 32
        $normalizer = $this->loader->getNormalizer($type->name());
190
191 31
        return $normalizer->denormalize($data, $type, $context);
192
    }
193
194
    /**
195
     * {@inheritdoc}
196
     */
197 1
    public function supports(string $className): bool
198
    {
199 1
        return true;
200
    }
201
202
    /**
203
     * Get the normalizer loader
204
     *
205
     * @return NormalizerLoaderInterface
206
     */
207 7
    public function getLoader(): NormalizerLoaderInterface
208
    {
209 7
        return $this->loader;
210
    }
211
}
212