Completed
Pull Request — master (#619)
by Ivan
14:45
created

GenericDeserializationVisitor::visitString()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4

Importance

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