Completed
Pull Request — master (#743)
by Asmir
03:52
created

Serializer::getMetadataFactory()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 0
cts 2
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
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\Parser\AbstractParser;
22
use JMS\Serializer\Construction\ObjectConstructorInterface;
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\EventDispatcher\EventDispatcher;
28
use JMS\Serializer\EventDispatcher\EventDispatcherInterface;
29
use JMS\Serializer\Exception\InvalidArgumentException;
30
use JMS\Serializer\Exception\RuntimeException;
31
use JMS\Serializer\Exception\UnsupportedFormatException;
32
use JMS\Serializer\Expression\ExpressionEvaluatorInterface;
33
use JMS\Serializer\Handler\HandlerRegistryInterface;
34
use Metadata\MetadataFactoryInterface;
35
36
/**
37
 * Serializer Implementation.
38
 *
39
 * @author Johannes M. Schmitt <[email protected]>
40
 */
41
final class Serializer implements SerializerInterface, ArrayTransformerInterface
42
{
43
    private $factory;
44
    private $handlerRegistry;
45
    private $objectConstructor;
46
    private $dispatcher;
47
    private $typeParser;
48
49
    private $serializationVisitors = array();
50
51
    private $deserializationVisitors = array();
52
53
    private $serializationNavigator;
54
    private $deserializationNavigator;
55
56
    /**
57
     * @var SerializationContextFactoryInterface
58
     */
59
    private $serializationContextFactory;
60
61
    /**
62
     * @var DeserializationContextFactoryInterface
63
     */
64
    private $deserializationContextFactory;
65
66
    /**
67
     * @param \Metadata\MetadataFactoryInterface $factory
68
     * @param Handler\HandlerRegistryInterface $handlerRegistry
69
     * @param Construction\ObjectConstructorInterface $objectConstructor
70
     * @param SerializationVisitorInterface[] $serializationVisitors
71
     * @param DeserializationVisitorInterface[] $deserializationVisitors
72
     * @param EventDispatcherInterface|null $dispatcher
73
     * @param AbstractParser|null $typeParser
74
     * @param ExpressionEvaluatorInterface|null $expressionEvaluator
75
     * @param SerializationContextFactoryInterface|null $serializationContextFactory
76
     * @param DeserializationContextFactoryInterface|null $deserializationContextFactory
77
     */
78 395
    public function __construct(
79
        MetadataFactoryInterface $factory,
80
        HandlerRegistryInterface $handlerRegistry,
81
        ObjectConstructorInterface $objectConstructor,
82
        array $serializationVisitors,
83
        array $deserializationVisitors,
84
        EventDispatcherInterface $dispatcher = null,
85
        AbstractParser $typeParser = null,
86
        ExpressionEvaluatorInterface $expressionEvaluator = null,
87
        SerializationContextFactoryInterface $serializationContextFactory = null,
88
        DeserializationContextFactoryInterface $deserializationContextFactory = null
89
90
    )
91
    {
92 395
        $this->factory = $factory;
93 395
        $this->handlerRegistry = $handlerRegistry;
94 395
        $this->objectConstructor = $objectConstructor;
95 395
        $this->dispatcher = $dispatcher ?: new EventDispatcher();
96 395
        $this->typeParser = $typeParser ?: new TypeParser();
97 395
        $this->serializationVisitors = $serializationVisitors;
98 395
        $this->deserializationVisitors = $deserializationVisitors;
99
100 395
        $this->serializationNavigator = new SerializationGraphNavigator($this->factory, $this->handlerRegistry, $this->dispatcher, $expressionEvaluator);
101 395
        $this->deserializationNavigator = new DeserializationGraphNavigator($this->factory, $this->handlerRegistry, $this->objectConstructor, $this->dispatcher, $expressionEvaluator);
102
103 395
        $this->serializationContextFactory = $serializationContextFactory ?: new DefaultSerializationContextFactory();
104 395
        $this->deserializationContextFactory = $deserializationContextFactory ?: new DefaultDeserializationContextFactory();
105 395
    }
106
107
    /**
108
     * Parses a direction string to one of the direction constants.
109
     *
110
     * @param string $dirStr
111
     *
112
     * @return integer
113
     */
114
    public static function parseDirection($dirStr)
115
    {
116
        switch (strtolower($dirStr)) {
117
            case 'serialization':
118
                return GraphNavigatorInterface::DIRECTION_SERIALIZATION;
119
120
            case 'deserialization':
121
                return GraphNavigatorInterface::DIRECTION_DESERIALIZATION;
122
123
            default:
124
                throw new InvalidArgumentException(sprintf('The direction "%s" does not exist.', $dirStr));
125
        }
126
    }
127
128 345
    private function findInitialType($type, SerializationContext $context)
129
    {
130 345
        if ($type !== null) {
131
            return $this->typeParser->parse($type);
132 345
        } elseif ($context->hasAttribute('initial_type')) {
133 37
            return $this->typeParser->parse($context->getAttribute('initial_type'));
134
        }
135 308
        return null;
136
    }
137
138 338
    public function serialize($data, $format, SerializationContext $context = null, $type = null)
139
    {
140 338
        if (null === $context) {
141 264
            $context = $this->serializationContextFactory->createSerializationContext();
142
        }
143
144 338
        if (!isset($this->serializationVisitors[$format])) {
145 1
            throw new UnsupportedFormatException(sprintf('The format "%s" is not supported for serialization.', $format));
146
        }
147
148 337
        $type = $this->findInitialType($type, $context);
149
150 337
        $visitor = $this->serializationVisitors[$format];
151
152 337
        $preparedData = $visitor->prepare($data);
153 337
        $result = $this->visit($this->serializationNavigator, $visitor, $context, $preparedData, $format, $type);
154 326
        return $visitor->getResult($result);
155
    }
156
157 167
    public function deserialize($data, $type, $format, DeserializationContext $context = null)
158
    {
159 167
        if (null === $context) {
160 161
            $context = $this->deserializationContextFactory->createDeserializationContext();
161
        }
162
163 167
        if (!isset($this->deserializationVisitors[$format])) {
164
            throw new UnsupportedFormatException(sprintf('The format "%s" is not supported for deserialization.', $format));
165
        }
166
167 167
        $visitor = $this->deserializationVisitors[$format];
168 167
        $preparedData = $visitor->prepare($data);
169 164
        $result = $this->visit($this->deserializationNavigator, $visitor, $context, $preparedData, $format, $this->typeParser->parse($type));
170
171 160
        return $visitor->getResult($result);
172
    }
173
174
    /**
175
     * {@InheritDoc}
176
     */
177 8
    public function toArray($data, SerializationContext $context = null, $type = null)
178
    {
179 8
        if (null === $context) {
180 8
            $context = $this->serializationContextFactory->createSerializationContext();
181
        }
182
183 8
        if (!isset($this->serializationVisitors['json'])) {
184
            throw new UnsupportedFormatException(sprintf('The format "%s" is not supported for fromArray.', 'json'));
185
        }
186
187 8
        $visitor = $this->serializationVisitors['json'];
188
189 8
        $type = $this->findInitialType($type, $context);
190
191 8
        $preparedData = $visitor->prepare($data);
192 8
        $result = $this->visit($this->serializationNavigator, $visitor, $context, $preparedData, 'json', $type);
193 8
        $result = $this->convertArrayObjects($result);
194
195 8
        if (!\is_array($result)) {
196 4
            throw new RuntimeException(sprintf(
197 4
                'The input data of type "%s" did not convert to an array, but got a result of type "%s".',
198 4
                \is_object($data) ? \get_class($data) : \gettype($data),
199 4
                \is_object($result) ? \get_class($result) : \gettype($result)
200
            ));
201
        }
202
203 4
        return $result;
204
    }
205
206
    /**
207
     * {@InheritDoc}
208
     */
209 2
    public function fromArray(array $data, $type, DeserializationContext $context = null)
210
    {
211 2
        if (null === $context) {
212 2
            $context = $this->deserializationContextFactory->createDeserializationContext();
213
        }
214
215 2
        if (!isset($this->deserializationVisitors['json'])) {
216
            throw new UnsupportedFormatException(sprintf('The format "%s" is not supported for fromArray.', 'json'));
217
        }
218 2
        $visitor = $this->deserializationVisitors['json'];
219
220 2
        return $this->visit($this->deserializationNavigator, $visitor, $context, $data, 'json', $this->typeParser->parse($type));
221
    }
222
223 371
    private function visit(GraphNavigatorInterface $navigator, $visitor, Context $context, $data, $format, array $type = null)
224
    {
225 371
        $context->initialize(
226 371
            $format,
227 371
            $visitor,
228 371
            $navigator,
229 371
            $this->factory
230
        );
231
232 371
        $visitor->setNavigator($navigator);
233
234 371
        return $navigator->accept($data, $type, $context);
235
    }
236
237 8
    private function convertArrayObjects($data)
238
    {
239 8
        if ($data instanceof \ArrayObject || $data instanceof \stdClass) {
240 2
            $data = (array)$data;
241
        }
242 8
        if (\is_array($data)) {
243 4
            foreach ($data as $k => $v) {
244 3
                $data[$k] = $this->convertArrayObjects($v);
245
            }
246
        }
247
248 8
        return $data;
249
    }
250
251
    /**
252
     * @return MetadataFactoryInterface
253
     */
254
    public function getMetadataFactory()
255
    {
256
        return $this->factory;
257
    }
258
}
259