Completed
Push — master ( a7a790...5c4323 )
by Eric
03:39
created

XmlDeserializationVisitor::doVisitObjectProperty()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 6
cts 6
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 10
nc 2
nop 4
crap 2
1
<?php
2
3
/*
4
 * This file is part of the Ivory Serializer package.
5
 *
6
 * (c) Eric GELOEN <[email protected]>
7
 *
8
 * For the full copyright and license information, please read the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Ivory\Serializer\Visitor\Xml;
13
14
use Ivory\Serializer\Context\ContextInterface;
15
use Ivory\Serializer\Instantiator\InstantiatorInterface;
16
use Ivory\Serializer\Mapping\PropertyMetadataInterface;
17
use Ivory\Serializer\Mapping\TypeMetadata;
18
use Ivory\Serializer\Mapping\TypeMetadataInterface;
19
use Ivory\Serializer\Mutator\MutatorInterface;
20
use Ivory\Serializer\Type\Type;
21
use Ivory\Serializer\Visitor\AbstractDeserializationVisitor;
22
23
/**
24
 * @author GeLo <[email protected]>
25
 */
26
class XmlDeserializationVisitor extends AbstractDeserializationVisitor
27
{
28
    /**
29
     * @var string
30
     */
31
    private $entry;
32
33
    /**
34
     * @var string
35
     */
36
    private $entryAttribute;
37
38
    /**
39
     * @param InstantiatorInterface $instantiator
40
     * @param MutatorInterface      $mutator
41
     * @param string                $entry
42
     * @param string                $entryAttribute
43
     */
44 738
    public function __construct(
45
        InstantiatorInterface $instantiator,
46
        MutatorInterface $mutator,
47
        $entry = 'entry',
48
        $entryAttribute = 'key'
49
    ) {
50 738
        parent::__construct($instantiator, $mutator);
51
52 738
        $this->entry = $entry;
53 738
        $this->entryAttribute = $entryAttribute;
54 738
    }
55
56
    /**
57
     * {@inheritdoc}
58
     */
59 99
    protected function decode($data)
60
    {
61 99
        $internalErrors = libxml_use_internal_errors(true);
62 99
        $disableEntityLoader = libxml_disable_entity_loader(true);
63
64 99
        $document = simplexml_load_string($data);
65
66 99
        libxml_use_internal_errors($internalErrors);
67 99
        libxml_disable_entity_loader($disableEntityLoader);
68
69 99
        if ($document === false) {
70
            throw new \InvalidArgumentException(libxml_get_last_error());
71
        }
72
73 99
        return $document;
74
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79 6
    protected function doVisitArray($data, TypeMetadataInterface $type, ContextInterface $context)
80
    {
81 6
        $this->result = [];
82
83 6
        if (isset($data[$this->entry])) {
84 6
            $entries = $data[$this->entry];
85 6
            $entries = is_array($entries) ? $entries : [$entries];
86
87 6
            foreach ($entries as $key => $value) {
88 6
                $this->visitArrayItem($key, $value, $type, $context);
89 4
            }
90 4
        }
91
92 6
        foreach ($data as $key => $value) {
93 6
            if ($key !== $this->entry) {
94 6
                $this->visitArrayItem($key, $value, $type, $context);
95 4
            }
96 4
        }
97
98 6
        return $this->result;
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104 72
    protected function doVisitObjectProperty(
105
        $data,
106
        $name,
107
        PropertyMetadataInterface $property,
108
        ContextInterface $context
109
    ) {
110 72
        $data = $this->visitNode($data, new TypeMetadata(Type::ARRAY_));
111
112 72
        if (!isset($data[$name])) {
113 6
            return false;
114
        }
115
116 72
        $data[$name] = $this->visitNode($data[$name], $property->getType());
117
118 72
        return parent::doVisitObjectProperty($data, $name, $property, $context);
119
    }
120
121
    /**
122
     * @param mixed                 $key
123
     * @param mixed                 $value
124
     * @param TypeMetadataInterface $type
125
     * @param ContextInterface      $context
126
     */
127 6
    private function visitArrayItem($key, $value, TypeMetadataInterface $type, ContextInterface $context)
128
    {
129 6
        $result = $this->navigator->navigate(
130 6
            $this->visitNode($value, $valueType = $type->getOption('value')),
131 4
            $context,
132
            $valueType
133 4
        );
134
135 6
        if ($result === null && $context->isNullIgnored()) {
136
            return;
137
        }
138
139 6
        if ($value instanceof \SimpleXMLElement) {
140 6
            $key = $value->getName();
141
142 6
            if ($key === $this->entry) {
143 3
                $attributes = $value->attributes();
144 4
                $key = isset($attributes[$this->entryAttribute]) ? $attributes[$this->entryAttribute] : null;
145 2
            }
146 6
        } elseif ($key === $this->entry) {
147
            $key = null;
148
        }
149
150 6
        $key = $this->navigator->navigate(
151 6
            $this->visitNode($key, $keyType = $type->getOption('key')),
152 4
            $context,
153
            $keyType
154 4
        );
155
156 6
        if ($key === null) {
157
            $this->result[] = $result;
158
        } else {
159 6
            $this->result[$key] = $result;
160
        }
161 6
    }
162
163
    /**
164
     * @param mixed                      $data
165
     * @param TypeMetadataInterface|null $type
166
     *
167
     * @return mixed
168
     */
169 75
    private function visitNode($data, TypeMetadataInterface $type = null)
170
    {
171 75
        if (!$data instanceof \SimpleXMLElement) {
172 54
            return $data;
173
        }
174
175 75
        if (count($data)) {
176 75
            return (array) $data;
177
        }
178
179 30
        $data = (string) $data;
180
181 30
        if ($data !== '') {
182 3
            return $data;
183
        }
184
185 30
        if ($type !== null && $type->getName() === Type::ARRAY_) {
186 9
            return [];
187
        }
188 24
    }
189
}
190