Completed
Push — master ( a11a2f...a1ae8b )
by Asmir
03:55
created

Serializer   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 213
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 15

Test Coverage

Coverage 97.78%

Importance

Changes 0
Metric Value
wmc 27
lcom 1
cbo 15
dl 0
loc 213
ccs 88
cts 90
cp 0.9778
rs 9.1666
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 24 2
A serialize() 0 16 3
A deserialize() 0 15 2
B toArray() 0 25 6
A fromArray() 0 14 2
A handleDeserializeResult() 0 9 3
B convertArrayObjects() 0 13 5
A getMetadataFactory() 0 4 1
A setSerializationContextFactory() 0 6 1
A setDeserializationContextFactory() 0 6 1
A visit() 0 13 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\EventDispatcherInterface;
27
use JMS\Serializer\Exception\RuntimeException;
28
use JMS\Serializer\Exception\UnsupportedFormatException;
29
use JMS\Serializer\Expression\ExpressionEvaluatorInterface;
30
use JMS\Serializer\Handler\HandlerRegistryInterface;
31
use Metadata\MetadataFactoryInterface;
32
use PhpCollection\MapInterface;
33
34
/**
35
 * Serializer Implementation.
36
 *
37
 * @author Johannes M. Schmitt <[email protected]>
38
 */
39
class Serializer implements SerializerInterface, ArrayTransformerInterface
40
{
41
    private $factory;
42
    private $handlerRegistry;
43
    private $objectConstructor;
44
    private $dispatcher;
45
    private $typeParser;
46
47
    /** @var \PhpCollection\MapInterface */
48
    private $serializationVisitors;
49
50
    /** @var \PhpCollection\MapInterface */
51
    private $deserializationVisitors;
52
53
    private $navigator;
54
55
    /**
56
     * @var SerializationContextFactoryInterface
57
     */
58
    private $serializationContextFactory;
59
60
    /**
61
     * @var DeserializationContextFactoryInterface
62
     */
63
    private $deserializationContextFactory;
64
65
    /**
66
     * Constructor.
67
     *
68
     * @param \Metadata\MetadataFactoryInterface $factory
69
     * @param Handler\HandlerRegistryInterface $handlerRegistry
70
     * @param Construction\ObjectConstructorInterface $objectConstructor
71
     * @param \PhpCollection\MapInterface $serializationVisitors of VisitorInterface
72
     * @param \PhpCollection\MapInterface $deserializationVisitors of VisitorInterface
73
     * @param EventDispatcher\EventDispatcherInterface $dispatcher
74
     * @param TypeParser $typeParser
75
     * @param ExpressionEvaluatorInterface|null $expressionEvaluator
76
     */
77 392
    public function __construct(
78
        MetadataFactoryInterface $factory,
79
        HandlerRegistryInterface $handlerRegistry,
80
        ObjectConstructorInterface $objectConstructor,
81
        MapInterface $serializationVisitors,
82
        MapInterface $deserializationVisitors,
83
        EventDispatcherInterface $dispatcher = null,
84
        TypeParser $typeParser = null,
85
        ExpressionEvaluatorInterface $expressionEvaluator = null
86
    )
87
    {
88 392
        $this->factory = $factory;
89 392
        $this->handlerRegistry = $handlerRegistry;
90 392
        $this->objectConstructor = $objectConstructor;
91 392
        $this->dispatcher = $dispatcher;
92 392
        $this->typeParser = $typeParser ?: new TypeParser();
93 392
        $this->serializationVisitors = $serializationVisitors;
94 392
        $this->deserializationVisitors = $deserializationVisitors;
95
96 392
        $this->navigator = new GraphNavigator($this->factory, $this->handlerRegistry, $this->objectConstructor, $this->dispatcher, $expressionEvaluator);
97
98 392
        $this->serializationContextFactory = new DefaultSerializationContextFactory();
99 392
        $this->deserializationContextFactory = new DefaultDeserializationContextFactory();
100 392
    }
101
102 340
    public function serialize($data, $format, SerializationContext $context = null)
103
    {
104 340
        if (null === $context) {
105 266
            $context = $this->serializationContextFactory->createSerializationContext();
106 266
        }
107
108 340
        return $this->serializationVisitors->get($format)
109
            ->map(function (VisitorInterface $visitor) use ($context, $data, $format) {
110 339
                $type = $context->getInitialType() !== null ? $this->typeParser->parse($context->getInitialType()) : null;
111
112 339
                $this->visit($visitor, $context, $visitor->prepare($data), $format, $type);
113
114 328
                return $visitor->getResult();
115 340
            })
116 327
            ->getOrThrow(new UnsupportedFormatException(sprintf('The format "%s" is not supported for serialization.', $format)));
117
    }
118
119 115
    public function deserialize($data, $type, $format, DeserializationContext $context = null)
120
    {
121 115
        if (null === $context) {
122 111
            $context = $this->deserializationContextFactory->createDeserializationContext();
123 111
        }
124
125 115
        return $this->deserializationVisitors->get($format)
126
            ->map(function (VisitorInterface $visitor) use ($context, $data, $format, $type) {
127 115
                $preparedData = $visitor->prepare($data);
128 112
                $navigatorResult = $this->visit($visitor, $context, $preparedData, $format, $this->typeParser->parse($type));
129
130 109
                return $this->handleDeserializeResult($visitor->getResult(), $navigatorResult);
131 115
            })
132 109
            ->getOrThrow(new UnsupportedFormatException(sprintf('The format "%s" is not supported for deserialization.', $format)));
133
    }
134
135
    /**
136
     * {@InheritDoc}
137
     */
138 8
    public function toArray($data, SerializationContext $context = null)
139
    {
140 8
        if (null === $context) {
141 8
            $context = $this->serializationContextFactory->createSerializationContext();
142 8
        }
143
144 8
        return $this->serializationVisitors->get('json')
145
            ->map(function (JsonSerializationVisitor $visitor) use ($context, $data) {
146 8
                $type = $context->getInitialType() !== null ? $this->typeParser->parse($context->getInitialType()) : null;
147
148 8
                $this->visit($visitor, $context, $data, 'json', $type);
149 8
                $result = $this->convertArrayObjects($visitor->getRoot());
150
151 8
                if (!is_array($result)) {
152 4
                    throw new RuntimeException(sprintf(
153 4
                        'The input data of type "%s" did not convert to an array, but got a result of type "%s".',
154 4
                        is_object($data) ? get_class($data) : gettype($data),
155 4
                        is_object($result) ? get_class($result) : gettype($result)
156 4
                    ));
157
                }
158
159 4
                return $result;
160 8
            })
161 4
            ->get();
162
    }
163
164
    /**
165
     * {@InheritDoc}
166
     */
167 2
    public function fromArray(array $data, $type, DeserializationContext $context = null)
168
    {
169 2
        if (null === $context) {
170 2
            $context = $this->deserializationContextFactory->createDeserializationContext();
171 2
        }
172
173 2
        return $this->deserializationVisitors->get('json')
174 2
            ->map(function (JsonDeserializationVisitor $visitor) use ($data, $type, $context) {
175 2
                $navigatorResult = $this->visit($visitor, $context, $data, 'json', $this->typeParser->parse($type));
176
177 2
                return $this->handleDeserializeResult($visitor->getResult(), $navigatorResult);
178 2
            })
179 2
            ->get();
180
    }
181
182 366
    private function visit(VisitorInterface $visitor, Context $context, $data, $format, array $type = null)
183
    {
184 366
        $context->initialize(
185 366
            $format,
186 366
            $visitor,
187 366
            $this->navigator,
188 366
            $this->factory
189 366
        );
190
191 366
        $visitor->setNavigator($this->navigator);
192
193 366
        return $this->navigator->accept($data, $type, $context);
194
    }
195
196 111
    private function handleDeserializeResult($visitorResult, $navigatorResult)
197
    {
198
        // This is a special case if the root is handled by a callback on the object itself.
199 111
        if (null === $visitorResult && null !== $navigatorResult) {
200 10
            return $navigatorResult;
201
        }
202
203 101
        return $visitorResult;
204
    }
205
206 8
    private function convertArrayObjects($data)
207
    {
208 8
        if ($data instanceof \ArrayObject || $data instanceof \stdClass) {
209 3
            $data = (array)$data;
210 2
        }
211 8
        if (is_array($data)) {
212 4
            foreach ($data as $k => $v) {
213 3
                $data[$k] = $this->convertArrayObjects($v);
214 4
            }
215 4
        }
216
217 8
        return $data;
218
    }
219
220
    /**
221
     * @return MetadataFactoryInterface
222
     */
223
    public function getMetadataFactory()
224
    {
225
        return $this->factory;
226
    }
227
228
    /**
229
     * @param SerializationContextFactoryInterface $serializationContextFactory
230
     *
231
     * @return self
232
     */
233 5
    public function setSerializationContextFactory(SerializationContextFactoryInterface $serializationContextFactory)
234
    {
235 5
        $this->serializationContextFactory = $serializationContextFactory;
236
237 5
        return $this;
238
    }
239
240
    /**
241
     * @param DeserializationContextFactoryInterface $deserializationContextFactory
242
     *
243
     * @return self
244
     */
245 3
    public function setDeserializationContextFactory(DeserializationContextFactoryInterface $deserializationContextFactory)
246
    {
247 3
        $this->deserializationContextFactory = $deserializationContextFactory;
248
249 3
        return $this;
250
    }
251
}
252