Completed
Pull Request — master (#743)
by Asmir
07:41
created

Serializer   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 216
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 14

Test Coverage

Coverage 84.71%

Importance

Changes 0
Metric Value
wmc 33
lcom 1
cbo 14
dl 0
loc 216
ccs 72
cts 85
cp 0.8471
rs 9.3999
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 28 5
A parseDirection() 0 13 3
A findInitialType() 0 9 3
A serialize() 0 18 3
A deserialize() 0 16 3
B toArray() 0 28 6
A fromArray() 0 13 3
A visit() 0 13 1
B convertArrayObjects() 0 13 5
A getMetadataFactory() 0 4 1
1
<?php
2
3
/*
4
 * Copyright 2016 Johannes M. Schmitt <[email protected]>
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace JMS\Serializer;
20
21
use JMS\Serializer\Construction\ObjectConstructorInterface;
22
use JMS\Serializer\ContextFactory\DefaultDeserializationContextFactory;
23
use JMS\Serializer\ContextFactory\DefaultSerializationContextFactory;
24
use JMS\Serializer\ContextFactory\DeserializationContextFactoryInterface;
25
use JMS\Serializer\ContextFactory\SerializationContextFactoryInterface;
26
use JMS\Serializer\EventDispatcher\EventDispatcher;
27
use JMS\Serializer\EventDispatcher\EventDispatcherInterface;
28
use JMS\Serializer\Exception\InvalidArgumentException;
29
use JMS\Serializer\Exception\RuntimeException;
30
use JMS\Serializer\Exception\UnsupportedFormatException;
31
use JMS\Serializer\Expression\ExpressionEvaluatorInterface;
32
use JMS\Serializer\Handler\HandlerRegistryInterface;
33
use Metadata\MetadataFactoryInterface;
34
35
/**
36
 * Serializer Implementation.
37
 *
38
 * @author Johannes M. Schmitt <[email protected]>
39
 */
40
final class Serializer implements SerializerInterface, ArrayTransformerInterface
41
{
42
    private $factory;
43
    private $handlerRegistry;
44
    private $objectConstructor;
45
    private $dispatcher;
46
    private $typeParser;
47
48
    private $serializationVisitors = array();
49
50
    private $deserializationVisitors = array();
51
52
    private $serializationNavigator;
53
    private $deserializationNavigator;
54
55
    /**
56
     * @var SerializationContextFactoryInterface
57
     */
58
    private $serializationContextFactory;
59
60
    /**
61
     * @var DeserializationContextFactoryInterface
62
     */
63
    private $deserializationContextFactory;
64
65
    /**
66
     * @param \Metadata\MetadataFactoryInterface $factory
67
     * @param Handler\HandlerRegistryInterface $handlerRegistry
68
     * @param Construction\ObjectConstructorInterface $objectConstructor
69
     * @param SerializationVisitorInterface[] $serializationVisitors
70
     * @param DeserializationVisitorInterface[] $deserializationVisitors
71
     * @param EventDispatcherInterface|null $dispatcher
72
     * @param TypeParser|null $typeParser
73
     * @param ExpressionEvaluatorInterface|null $expressionEvaluator
74
     */
75 394
    public function __construct(
76
        MetadataFactoryInterface $factory,
77
        HandlerRegistryInterface $handlerRegistry,
78
        ObjectConstructorInterface $objectConstructor,
79
        array $serializationVisitors,
80
        array $deserializationVisitors,
81
        EventDispatcherInterface $dispatcher = null,
82
        TypeParser $typeParser = null,
83
        ExpressionEvaluatorInterface $expressionEvaluator = null,
84
        SerializationContextFactoryInterface $serializationContextFactory = null,
85
        DeserializationContextFactoryInterface $deserializationContextFactory = null
86
87
    )
88
    {
89 394
        $this->factory = $factory;
90 394
        $this->handlerRegistry = $handlerRegistry;
91 394
        $this->objectConstructor = $objectConstructor;
92 394
        $this->dispatcher = $dispatcher ?: new EventDispatcher();
93 394
        $this->typeParser = $typeParser ?: new TypeParser();
94 394
        $this->serializationVisitors = $serializationVisitors;
95 394
        $this->deserializationVisitors = $deserializationVisitors;
96
97 394
        $this->serializationNavigator = new SerializationGraphNavigator($this->factory, $this->handlerRegistry, $this->dispatcher, $expressionEvaluator);
98 394
        $this->deserializationNavigator = new DeserializationGraphNavigator($this->factory, $this->handlerRegistry, $this->objectConstructor, $this->dispatcher, $expressionEvaluator);
99
100 394
        $this->serializationContextFactory = $serializationContextFactory ?: new DefaultSerializationContextFactory();
101 394
        $this->deserializationContextFactory = $deserializationContextFactory ?: new DefaultDeserializationContextFactory();
102 394
    }
103
104
    /**
105
     * Parses a direction string to one of the direction constants.
106
     *
107
     * @param string $dirStr
108
     *
109
     * @return integer
110
     */
111
    public static function parseDirection($dirStr)
112
    {
113
        switch (strtolower($dirStr)) {
114
            case 'serialization':
115
                return GraphNavigatorInterface::DIRECTION_SERIALIZATION;
116
117
            case 'deserialization':
118
                return GraphNavigatorInterface::DIRECTION_DESERIALIZATION;
119
120
            default:
121
                throw new InvalidArgumentException(sprintf('The direction "%s" does not exist.', $dirStr));
122
        }
123
    }
124
125 345
    private function findInitialType($type, SerializationContext $context)
126
    {
127 345
        if ($type !== null) {
128
            return $this->typeParser->parse($type);
129 345
        } elseif ($context->hasAttribute('initial_type')) {
130 37
            return $this->typeParser->parse($context->getAttribute('initial_type'));
131
        }
132 308
        return null;
133
    }
134
135 338
    public function serialize($data, $format, SerializationContext $context = null, $type = null)
136
    {
137 338
        if (null === $context) {
138 264
            $context = $this->serializationContextFactory->createSerializationContext();
139
        }
140
141 338
        if (!isset($this->serializationVisitors[$format])) {
142 1
            throw new UnsupportedFormatException(sprintf('The format "%s" is not supported for serialization.', $format));
143
        }
144
145 337
        $type = $this->findInitialType($type, $context);
146
147 337
        $visitor = $this->serializationVisitors[$format];
148
149 337
        $preparedData = $visitor->prepare($data);
150 337
        $result = $this->visit($this->serializationNavigator, $visitor, $context, $preparedData, $format, $type);
151 326
        return $visitor->getResult($result);
152
    }
153
154 166
    public function deserialize($data, $type, $format, DeserializationContext $context = null)
155
    {
156 166
        if (null === $context) {
157 160
            $context = $this->deserializationContextFactory->createDeserializationContext();
158
        }
159
160 166
        if (!isset($this->deserializationVisitors[$format])) {
161
            throw new UnsupportedFormatException(sprintf('The format "%s" is not supported for deserialization.', $format));
162
        }
163
164 166
        $visitor = $this->deserializationVisitors[$format];
165 166
        $preparedData = $visitor->prepare($data);
166 163
        $result = $this->visit($this->deserializationNavigator, $visitor, $context, $preparedData, $format, $this->typeParser->parse($type));
167
168 159
        return $visitor->getResult($result);
169
    }
170
171
    /**
172
     * {@InheritDoc}
173
     */
174 8
    public function toArray($data, SerializationContext $context = null, $type = null)
175
    {
176 8
        if (null === $context) {
177 8
            $context = $this->serializationContextFactory->createSerializationContext();
178
        }
179
180 8
        if (!isset($this->serializationVisitors['json'])) {
181
            throw new UnsupportedFormatException(sprintf('The format "%s" is not supported for fromArray.', 'json'));
182
        }
183
184 8
        $visitor = $this->serializationVisitors['json'];
185
186 8
        $type = $this->findInitialType($type, $context);
187
188 8
        $preparedData = $visitor->prepare($data);
189 8
        $result = $this->visit($this->serializationNavigator, $visitor, $context, $preparedData, 'json', $type);
190 8
        $result = $this->convertArrayObjects($result);
191
192 8
        if (!\is_array($result)) {
193 4
            throw new RuntimeException(sprintf(
194 4
                'The input data of type "%s" did not convert to an array, but got a result of type "%s".',
195 4
                \is_object($data) ? \get_class($data) : \gettype($data),
196 4
                \is_object($result) ? \get_class($result) : \gettype($result)
197
            ));
198
        }
199
200 4
        return $result;
201
    }
202
203
    /**
204
     * {@InheritDoc}
205
     */
206 2
    public function fromArray(array $data, $type, DeserializationContext $context = null)
207
    {
208 2
        if (null === $context) {
209 2
            $context = $this->deserializationContextFactory->createDeserializationContext();
210
        }
211
212 2
        if (!isset($this->deserializationVisitors['json'])) {
213
            throw new UnsupportedFormatException(sprintf('The format "%s" is not supported for fromArray.', 'json'));
214
        }
215 2
        $visitor = $this->deserializationVisitors['json'];
216
217 2
        return $this->visit($this->deserializationNavigator, $visitor, $context, $data, 'json', $this->typeParser->parse($type));
218
    }
219
220 370
    private function visit(GraphNavigatorInterface $navigator, $visitor, Context $context, $data, $format, array $type = null)
221
    {
222 370
        $context->initialize(
223 370
            $format,
224 370
            $visitor,
225 370
            $navigator,
226 370
            $this->factory
227
        );
228
229 370
        $visitor->setNavigator($navigator);
230
231 370
        return $navigator->accept($data, $type, $context);
232
    }
233
234 8
    private function convertArrayObjects($data)
235
    {
236 8
        if ($data instanceof \ArrayObject || $data instanceof \stdClass) {
237 2
            $data = (array)$data;
238
        }
239 8
        if (\is_array($data)) {
240 4
            foreach ($data as $k => $v) {
241 3
                $data[$k] = $this->convertArrayObjects($v);
242
            }
243
        }
244
245 8
        return $data;
246
    }
247
248
    /**
249
     * @return MetadataFactoryInterface
250
     */
251
    public function getMetadataFactory()
252
    {
253
        return $this->factory;
254
    }
255
}
256