Completed
Pull Request — master (#859)
by
unknown
04:25
created

GenericDeserializationVisitor::getNavigator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 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\Exception\RuntimeException;
22
use JMS\Serializer\Metadata\ClassMetadata;
23
use JMS\Serializer\Metadata\PropertyMetadata;
24
use JMS\Serializer\Naming\AdvancedNamingStrategyInterface;
25
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
26
27
/**
28
 * Generic Deserialization Visitor.
29
 *
30
 * @author Johannes M. Schmitt <[email protected]>
31
 */
32
abstract class GenericDeserializationVisitor extends AbstractVisitor
33
{
34
    private $navigator;
35
    private $result;
36
    private $objectStack;
37
    private $currentObject;
38
39 60
    public function setNavigator(GraphNavigator $navigator)
40
    {
41 60
        $this->navigator = $navigator;
42 60
        $this->result = null;
43 60
        $this->objectStack = new \SplStack;
44 60
    }
45
46 1
    public function getNavigator()
47
    {
48 1
        return $this->navigator;
49
    }
50
51 58
    public function prepare($data)
52
    {
53 58
        return $this->decode($data);
54
    }
55
56 1
    public function visitNull($data, array $type, Context $context)
57
    {
58 1
        return null;
59
    }
60
61 24
    public function visitString($data, array $type, Context $context)
62
    {
63 24
        $data = (string)$data;
64
65 24
        if (null === $this->result) {
66 3
            $this->result = $data;
67 3
        }
68
69 24
        return $data;
70
    }
71
72 5
    public function visitBoolean($data, array $type, Context $context)
73
    {
74 5
        $data = (Boolean)$data;
75
76 5
        if (null === $this->result) {
77 2
            $this->result = $data;
78 2
        }
79
80 5
        return $data;
81
    }
82
83 8
    public function visitInteger($data, array $type, Context $context)
84
    {
85 8
        $data = (integer)$data;
86
87 8
        if (null === $this->result) {
88 2
            $this->result = $data;
89 2
        }
90
91 8
        return $data;
92
    }
93
94 13
    public function visitDouble($data, array $type, Context $context)
95
    {
96 13
        $data = (double)$data;
97
98 13
        if (null === $this->result) {
99 6
            $this->result = $data;
100 6
        }
101
102 13
        return $data;
103
    }
104
105 19
    public function visitArray($data, array $type, Context $context)
106
    {
107 19
        if (!is_array($data)) {
108
            throw new RuntimeException(sprintf('Expected array, but got %s: %s', gettype($data), json_encode($data)));
109
        }
110
111
        // If no further parameters were given, keys/values are just passed as is.
112 19
        if (!$type['params']) {
113 4
            if (null === $this->result) {
114 4
                $this->result = $data;
115 4
            }
116
117 4
            return $data;
118
        }
119
120 15
        switch (count($type['params'])) {
121 15
            case 1: // Array is a list.
122 13
                $listType = $type['params'][0];
123
124 13
                $result = array();
125 13
                if (null === $this->result) {
126 5
                    $this->result = &$result;
127 5
                }
128
129 13
                foreach ($data as $v) {
130 12
                    $result[] = $this->navigator->accept($v, $listType, $context);
131 13
                }
132
133 13
                return $result;
134
135 5
            case 2: // Array is a map.
136 5
                list($keyType, $entryType) = $type['params'];
137
138 5
                $result = array();
139 5
                if (null === $this->result) {
140
                    $this->result = &$result;
141
                }
142
143 5
                foreach ($data as $k => $v) {
144 5
                    $result[$this->navigator->accept($k, $keyType, $context)] = $this->navigator->accept($v, $entryType, $context);
145 5
                }
146
147 5
                return $result;
148
149
            default:
150
                throw new RuntimeException(sprintf('Array type cannot have more than 2 parameters, but got %s.', json_encode($type['params'])));
151
        }
152
    }
153
154 31
    public function startVisitingObject(ClassMetadata $metadata, $object, array $type, Context $context)
155
    {
156 31
        $this->setCurrentObject($object);
157
158 31
        if (null === $this->result) {
159 30
            $this->result = $this->currentObject;
160 30
        }
161 31
    }
162
163 31
    public function visitProperty(PropertyMetadata $metadata, $data, Context $context)
164
    {
165 31
        if ($this->namingStrategy instanceof AdvancedNamingStrategyInterface) {
166 1
            $name = $this->namingStrategy->getPropertyName($metadata, $context);
167 1
        } else {
168 30
            $name = $this->namingStrategy->translateName($metadata);
169
        }
170
171 31
        if (null === $data) {
172
            return;
173
        }
174
175 31
        if (!is_array($data)) {
176 1
            throw new RuntimeException(sprintf('Invalid data "%s"(%s), expected "%s".', $data, $metadata->type['name'], $metadata->reflection->class));
177
        }
178
179 31
        if (!array_key_exists($name, $data)) {
180 4
            return;
181
        }
182
183 29
        if (!$metadata->type) {
184
            throw new RuntimeException(sprintf('You must define a type for %s::$%s.', $metadata->reflection->class, $metadata->name));
185
        }
186
187 29
        $v = $data[$name] !== null ? $this->navigator->accept($data[$name], $metadata->type, $context) : null;
188
189 29
        $this->accessor->setValue($this->currentObject, $v, $metadata);
190
191 29
    }
192
193 30
    public function endVisitingObject(ClassMetadata $metadata, $data, array $type, Context $context)
194
    {
195 30
        $obj = $this->currentObject;
196 30
        $this->revertCurrentObject();
197
198 30
        return $obj;
199
    }
200
201 58
    public function getResult()
202
    {
203 58
        return $this->result;
204
    }
205
206 31
    public function setCurrentObject($object)
207
    {
208 31
        $this->objectStack->push($this->currentObject);
209 31
        $this->currentObject = $object;
210 31
    }
211
212
    public function getCurrentObject()
213
    {
214
        return $this->currentObject;
215
    }
216
217 30
    public function revertCurrentObject()
218
    {
219 30
        return $this->currentObject = $this->objectStack->pop();
220
    }
221
222
    abstract protected function decode($str);
223
}
224