Passed
Branch master (bf85d9)
by Johannes
05:40
created

Serializer::__construct()   B

Complexity

Conditions 5
Paths 1

Size

Total Lines 28
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 5

Importance

Changes 0
Metric Value
cc 5
eloc 12
nc 1
nop 11
dl 0
loc 28
ccs 13
cts 13
cp 1
crap 5
rs 8.439
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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