Completed
Push — master ( 7bd689...f00989 )
by Asmir
15s queued 13s
created

Serializer::serialize()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 4
dl 0
loc 13
ccs 8
cts 8
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * Copyright 2016 Johannes M. Schmitt <[email protected]>
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
namespace JMS\Serializer;
22
23
use JMS\Serializer\ContextFactory\DefaultDeserializationContextFactory;
24
use JMS\Serializer\ContextFactory\DefaultSerializationContextFactory;
25
use JMS\Serializer\ContextFactory\DeserializationContextFactoryInterface;
26
use JMS\Serializer\ContextFactory\SerializationContextFactoryInterface;
27
use JMS\Serializer\Exception\InvalidArgumentException;
28
use JMS\Serializer\Exception\RuntimeException;
29
use JMS\Serializer\Exception\UnsupportedFormatException;
30
use JMS\Serializer\GraphNavigator\Factory\GraphNavigatorFactoryInterface;
31
use JMS\Serializer\Visitor\Factory\DeserializationVisitorFactory;
32
use JMS\Serializer\Visitor\Factory\SerializationVisitorFactory;
33
use JMS\Serializer\Type\Parser;
34
use JMS\Serializer\Type\ParserInterface;
35
use Metadata\MetadataFactoryInterface;
36
37
/**
38
 * Serializer Implementation.
39
 *
40
 * @author Johannes M. Schmitt <[email protected]>
41
 */
42
final class Serializer implements SerializerInterface, ArrayTransformerInterface
43
{
44
    /**
45
     * @var MetadataFactoryInterface
46
     */
47
    private $factory;
48
49
    /**
50
     * @var TypeParser
0 ignored issues
show
Bug introduced by
The type JMS\Serializer\TypeParser was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
51
     */
52
    private $typeParser;
53
54
    /**
55
     * @var SerializationVisitorFactory[]
56
     */
57
    private $serializationVisitors = [];
58
59
    /**
60
     * @var DeserializationVisitorFactory[]
61
     */
62
    private $deserializationVisitors = [];
63
64
    /**
65
     * @var SerializationContextFactoryInterface
66
     */
67
    private $serializationContextFactory;
68
69
    /**
70
     * @var DeserializationContextFactoryInterface
71
     */
72
    private $deserializationContextFactory;
73
74
    /**
75
     * @var GraphNavigatorFactoryInterface[]
76
     */
77
    private $graphNavigators;
78
79
    /**
80
     * @param MetadataFactoryInterface $factory
81
     * @param GraphNavigatorFactoryInterface[] $graphNavigators
82
     * @param SerializationVisitorFactory[] $serializationVisitors
83
     * @param DeserializationVisitorFactory[] $deserializationVisitors
84
     * @param SerializationContextFactoryInterface|null $serializationContextFactory
85
     * @param DeserializationContextFactoryInterface|null $deserializationContextFactory
86
     * @param ParserInterface|null $typeParser
87
     */
88 323
    public function __construct(
89
        MetadataFactoryInterface $factory,
90
        array $graphNavigators,
91
        array $serializationVisitors,
92
        array $deserializationVisitors,
93
        SerializationContextFactoryInterface $serializationContextFactory = null,
94
        DeserializationContextFactoryInterface $deserializationContextFactory = null,
95
        ParserInterface $typeParser = null
96
    ) {
97 323
        $this->factory = $factory;
98 323
        $this->graphNavigators = $graphNavigators;
99 323
        $this->serializationVisitors = $serializationVisitors;
100 323
        $this->deserializationVisitors = $deserializationVisitors;
101
102 323
        $this->typeParser = $typeParser ?? new Parser();
0 ignored issues
show
Documentation Bug introduced by
It seems like $typeParser ?? new JMS\Serializer\Type\Parser() of type JMS\Serializer\Type\ParserInterface or JMS\Serializer\Type\Parser is incompatible with the declared type JMS\Serializer\TypeParser of property $typeParser.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
103
104 323
        $this->serializationContextFactory = $serializationContextFactory ?: new DefaultSerializationContextFactory();
105 323
        $this->deserializationContextFactory = $deserializationContextFactory ?: new DefaultDeserializationContextFactory();
106 323
    }
107
108
    /**
109
     * Parses a direction string to one of the direction constants.
110
     *
111
     * @param string $dirStr
112
     *
113
     * @return integer
114
     */
115
    public static function parseDirection(string $dirStr): int
116
    {
117
        switch (strtolower($dirStr)) {
118
            case 'serialization':
119
                return GraphNavigatorInterface::DIRECTION_SERIALIZATION;
120
121
            case 'deserialization':
122
                return GraphNavigatorInterface::DIRECTION_DESERIALIZATION;
123
124
            default:
125
                throw new InvalidArgumentException(sprintf('The direction "%s" does not exist.', $dirStr));
126
        }
127
    }
128
129 281
    private function findInitialType(?string $type, SerializationContext $context)
130
    {
131 281
        if ($type !== null) {
132 2
            return $type;
133 279
        } elseif ($context->hasAttribute('initial_type')) {
134 27
            return $context->getAttribute('initial_type');
135
        }
136 252
        return null;
137
    }
138
139 306
    private function getNavigator(int $direction): GraphNavigatorInterface
140
    {
141 306
        if (!isset($this->graphNavigators[$direction])) {
142
            throw new RuntimeException(
143
                sprintf(
144
                    'Can not find a graph navigator for the direction "%s".',
145
                    $direction === GraphNavigatorInterface::DIRECTION_SERIALIZATION ? 'serialization' : 'deserialization'
146
                )
147
            );
148
        }
149
150 306
        return $this->graphNavigators[$direction]->getGraphNavigator();
151
    }
152
153 307
    private function getVisitor(int $direction, string $format): VisitorInterface
154
    {
155 307
        $factories = $direction === GraphNavigatorInterface::DIRECTION_SERIALIZATION
156 282
            ? $this->serializationVisitors
157 307
            : $this->deserializationVisitors;
158
159 307
        if (!isset($factories[$format])) {
160 1
            throw new UnsupportedFormatException(
161 1
                sprintf(
162 1
                    'The format "%s" is not supported for %s.', $format,
163 1
                    $direction === GraphNavigatorInterface::DIRECTION_SERIALIZATION ? 'serialization' : 'deserialization'
164
                ));
165
        }
166
167 306
        return $factories[$format]->getVisitor();
168
    }
169
170 274
    public function serialize($data, string $format, SerializationContext $context = null, string $type = null): string
171
    {
172 274
        if (null === $context) {
173 191
            $context = $this->serializationContextFactory->createSerializationContext();
174
        }
175
176 274
        $visitor = $this->getVisitor(GraphNavigatorInterface::DIRECTION_SERIALIZATION, $format);
177 273
        $navigator = $this->getNavigator(GraphNavigatorInterface::DIRECTION_SERIALIZATION);
178
179 273
        $type = $this->findInitialType($type, $context);
180
181 273
        $result = $this->visit($navigator, $visitor, $context, $data, $format, $type);
182 253
        return $visitor->getResult($result);
183
    }
184
185 131
    public function deserialize(string $data, string $type, string $format, DeserializationContext $context = null)
186
    {
187 131
        if (null === $context) {
188 127
            $context = $this->deserializationContextFactory->createDeserializationContext();
189
        }
190
191 131
        $visitor = $this->getVisitor(GraphNavigatorInterface::DIRECTION_DESERIALIZATION, $format);
192 131
        $navigator = $this->getNavigator(GraphNavigatorInterface::DIRECTION_DESERIALIZATION);
193
194 131
        $result = $this->visit($navigator, $visitor, $context, $data, $format, $type);
195
196 125
        return $visitor->getResult($result);
197
    }
198
199
    /**
200
     * {@InheritDoc}
201
     */
202 8
    public function toArray($data, SerializationContext $context = null, string $type = null): array
203
    {
204 8
        if (null === $context) {
205 8
            $context = $this->serializationContextFactory->createSerializationContext();
206
        }
207
208 8
        $visitor = $this->getVisitor(GraphNavigatorInterface::DIRECTION_SERIALIZATION, 'json');
209 8
        $navigator = $this->getNavigator(GraphNavigatorInterface::DIRECTION_SERIALIZATION);
210
211 8
        $type = $this->findInitialType($type, $context);
212 8
        $result = $this->visit($navigator, $visitor, $context, $data, 'json', $type);
213 8
        $result = $this->convertArrayObjects($result);
214
215 8
        if (!\is_array($result)) {
216 4
            throw new RuntimeException(sprintf(
217 4
                'The input data of type "%s" did not convert to an array, but got a result of type "%s".',
218 4
                \is_object($data) ? \get_class($data) : \gettype($data),
219 4
                \is_object($result) ? \get_class($result) : \gettype($result)
220
            ));
221
        }
222
223 4
        return $result;
224
    }
225
226
    /**
227
     * {@InheritDoc}
228
     */
229 2
    public function fromArray(array $data, string $type, DeserializationContext $context = null)
230
    {
231 2
        if (null === $context) {
232 2
            $context = $this->deserializationContextFactory->createDeserializationContext();
233
        }
234
235 2
        $visitor = $this->getVisitor(GraphNavigatorInterface::DIRECTION_DESERIALIZATION, 'json');
236 2
        $navigator = $this->getNavigator(GraphNavigatorInterface::DIRECTION_DESERIALIZATION);
237
238 2
        return $this->visit($navigator, $visitor, $context, $data, 'json', $type, false);
239
    }
240
241 306
    private function visit(GraphNavigatorInterface $navigator, VisitorInterface $visitor, Context $context, $data, string $format, string $type = null, bool $prepare = true)
242
    {
243 306
        $context->initialize(
244 306
            $format,
245 306
            $visitor,
246 306
            $navigator,
247 306
            $this->factory
248
        );
249
250 306
        $visitor->setNavigator($navigator);
251 306
        $navigator->initialize($visitor, $context);
252
253 306
        if ($prepare) {
254 304
            $data = $visitor->prepare($data);
255
        }
256
257 303
        if ($type !== null) {
258 159
            $type = $this->typeParser->parse($type);
259
        }
260 303
        return $navigator->accept($data, $type);
261
    }
262
263 8
    private function convertArrayObjects($data)
264
    {
265 8
        if ($data instanceof \ArrayObject || $data instanceof \stdClass) {
266 2
            $data = (array)$data;
267
        }
268 8
        if (\is_array($data)) {
269 4
            foreach ($data as $k => $v) {
270 3
                $data[$k] = $this->convertArrayObjects($v);
271
            }
272
        }
273
274 8
        return $data;
275
    }
276
}
277