Completed
Push — 14.x ( 497b27...3dca04 )
by Tim
01:44
created

Serializer::serialize()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 9.568
c 0
b 0
f 0
cc 3
nc 3
nop 3
1
<?php
2
3
/*
4
 * Copyright 2013 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 TechDivision\Import\Configuration\Jms\Serializer;
20
21
use JMS\Serializer\Construction\ObjectConstructorInterface;
22
use JMS\Serializer\Handler\HandlerRegistryInterface;
23
use JMS\Serializer\EventDispatcher\EventDispatcherInterface;
24
use JMS\Serializer\Exception\UnsupportedFormatException;
25
use Metadata\MetadataFactoryInterface;
26
use PhpCollection\MapInterface;
27
use JMS\Serializer\SerializerInterface;
28
use JMS\Serializer\TypeParser;
29
use JMS\Serializer\GraphNavigator;
30
use JMS\Serializer\SerializationContext;
31
use JMS\Serializer\DeserializationContext;
32
use JMS\Serializer\JsonDeserializationVisitor;
33
use JMS\Serializer\VisitorInterface;
34
use JMS\Serializer\Context;
35
use JMS\Serializer\JsonSerializationVisitor;
36
use JMS\Serializer\Exception\RuntimeException;
37
38
/**
39
 * Serializer Implementation.
40
 *
41
 * @author Johannes M. Schmitt <[email protected]>
42
 */
43
class Serializer implements SerializerInterface
44
{
45
    private $factory;
46
    private $handlerRegistry;
47
    private $objectConstructor;
48
    private $dispatcher;
49
    private $typeParser;
50
51
    /** @var \PhpCollection\MapInterface */
52
    private $serializationVisitors;
53
54
    /** @var \PhpCollection\MapInterface */
55
    private $deserializationVisitors;
56
57
    private $navigator;
58
59
    /**
60
     * Constructor.
61
     *
62
     * @param \Metadata\MetadataFactoryInterface $factory
63
     * @param \JMS\Serializer\Handler\HandlerRegistryInterface $handlerRegistry
64
     * @param \JMS\Serializer\Construction\ObjectConstructorInterface  $objectConstructor
65
     * @param \PhpCollection\MapInterface<VisitorInterface> $serializationVisitors
0 ignored issues
show
Documentation introduced by
The doc-type \PhpCollection\MapInterface<VisitorInterface> could not be parsed: Expected "|" or "end of type", but got "<" at position 27. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
66
     * @param \PhpCollection\MapInterface<VisitorInterface> $deserializationVisitors
0 ignored issues
show
Documentation introduced by
The doc-type \PhpCollection\MapInterface<VisitorInterface> could not be parsed: Expected "|" or "end of type", but got "<" at position 27. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
67
     * @param \JMS\Serializer\EventDispatcher\EventDispatcherInterface $dispatcher
68
     * @param \JMS\Serializer\TypeParser $typeParser
69
     */
70
    public function __construct(
71
        MetadataFactoryInterface $factory,
72
        HandlerRegistryInterface $handlerRegistry,
73
        ObjectConstructorInterface $objectConstructor,
74
        MapInterface $serializationVisitors,
75
        MapInterface $deserializationVisitors,
76
        EventDispatcherInterface $dispatcher = null,
77
        TypeParser $typeParser = null
78
    ) {
79
        $this->factory = $factory;
80
        $this->handlerRegistry = $handlerRegistry;
81
        $this->objectConstructor = $objectConstructor;
82
        $this->dispatcher = $dispatcher;
83
        $this->typeParser = $typeParser ?: new TypeParser();
84
        $this->serializationVisitors = $serializationVisitors;
85
        $this->deserializationVisitors = $deserializationVisitors;
86
87
        $this->navigator = new GraphNavigator($this->factory, $this->handlerRegistry, $this->objectConstructor, $this->dispatcher);
88
    }
89
90
    public function serialize($data, $format, SerializationContext $context = null)
91
    {
92
        if ( ! $this->serializationVisitors->containsKey($format)) {
93
            throw new UnsupportedFormatException(sprintf('The format "%s" is not supported for serialization.', $format));
94
        }
95
96
        if (null === $context) {
97
            $context = new SerializationContext();
98
        }
99
100
        $context->initialize(
101
            $format,
102
            $visitor = $this->serializationVisitors->get($format)->get(),
103
            $this->navigator,
104
            $this->factory
105
        );
106
107
        $visitor->setNavigator($this->navigator);
108
        $this->navigator->accept($visitor->prepare($data), null, $context);
109
110
        return $visitor->getResult();
111
    }
112
113
    public function deserialize($data, $type, $format, DeserializationContext $context = null)
114
    {
115
        if ( ! $this->deserializationVisitors->containsKey($format)) {
116
            throw new UnsupportedFormatException(sprintf('The format "%s" is not supported for deserialization.', $format));
117
        }
118
119
        if (null === $context) {
120
            $context = new DeserializationContext();
121
        }
122
123
        $context->initialize(
124
            $format,
125
            $visitor = $this->deserializationVisitors->get($format)->get(),
126
            $this->navigator,
127
            $this->factory
128
        );
129
130
        $visitor->setNavigator($this->navigator);
131
        $navigatorResult = $this->navigator->accept($visitor->prepare($data), $this->typeParser->parse($type), $context);
132
133
        // This is a special case if the root is handled by a callback on the object iself.
134
        if ((null === $visitorResult = $visitor->getResult()) && null !== $navigatorResult) {
135
            return $navigatorResult;
136
        }
137
138
        return $visitorResult;
139
    }
140
    /**
141
     * Converts objects to an array structure.
142
     *
143
     * This is useful when the data needs to be passed on to other methods which expect array data.
144
     *
145
     * @param mixed $data anything that converts to an array, typically an object or an array of objects
146
     *
147
     * @return array
148
     */
149
    public function toArray($data, SerializationContext $context = null)
150
    {
151
        if (null === $context) {
152
            $context = new SerializationContext();
153
        }
154
        return $this->serializationVisitors->get('json')
155
        ->map(function(JsonSerializationVisitor $visitor) use ($context, $data) {
156
            $this->visit($visitor, $context, $data, 'json');
157
            $result = $this->convertArrayObjects($visitor->getRoot());
158
            if ( ! is_array($result)) {
159
                throw new RuntimeException(sprintf(
160
                    'The input data of type "%s" did not convert to an array, but got a result of type "%s".',
161
                    is_object($data) ? get_class($data) : gettype($data),
162
                    is_object($result) ? get_class($result) : gettype($result)
163
                    ));
164
            }
165
            return $result;
166
        })
167
        ->get();
168
    }
169
    /**
170
     * Restores objects from an array structure.
171
     *
172
     * @param array $data
173
     * @param string $type
174
     *
175
     * @return mixed this returns whatever the passed type is, typically an object or an array of objects
176
     */
177
    public function fromArray(array $data, $type, DeserializationContext $context = null)
178
    {
179
        if (null === $context) {
180
            $context = new DeserializationContext();
181
        }
182
        return $this->deserializationVisitors->get('json')
183
        ->map(function(JsonDeserializationVisitor $visitor) use ($data, $type, $context) {
184
            $navigatorResult = $this->visit($visitor, $context, $data, 'json', $this->typeParser->parse($type));
185
            return $this->handleDeserializeResult($visitor->getResult(), $navigatorResult);
186
        })
187
        ->get();
188
    }
189
190
    private function visit(VisitorInterface $visitor, Context $context, $data, $format, array $type = null)
191
    {
192
        $context->initialize(
193
            $format,
194
            $visitor,
195
            $this->navigator,
196
            $this->factory
197
            );
198
        $visitor->setNavigator($this->navigator);
199
        return $this->navigator->accept($data, $type, $context);
200
    }
201
202
    private function handleDeserializeResult($visitorResult, $navigatorResult)
203
    {
204
        // This is a special case if the root is handled by a callback on the object itself.
205
        if (null === $visitorResult && null !== $navigatorResult) {
206
            return $navigatorResult;
207
        }
208
        return $visitorResult;
209
    }
210
211
    private function convertArrayObjects($data)
212
    {
213
        if ($data instanceof \ArrayObject) {
214
            $data = (array) $data;
215
        }
216
        if (is_array($data)) {
217
            foreach ($data as $k => $v) {
218
                $data[$k] = $this->convertArrayObjects($v);
219
            }
220
        }
221
        return $data;
222
    }
223
224
    /**
225
     * @return MetadataFactoryInterface
226
     */
227
    public function getMetadataFactory()
228
    {
229
        return $this->factory;
230
    }
231
}
232