Completed
Push — master ( e1c4bf...7b4b35 )
by Johannes
10s
created

XmlDriver::loadMetadataFromFile()   F

Complexity

Conditions 70
Paths > 20000

Size

Total Lines 278
Code Lines 158

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 140
CRAP Score 193.1271

Importance

Changes 10
Bugs 2 Features 3
Metric Value
c 10
b 2
f 3
dl 0
loc 278
ccs 140
cts 198
cp 0.707
rs 2
cc 70
eloc 158
nc 4294967295
nop 2
crap 193.1271

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Metadata\Driver;
20
21
use JMS\Serializer\GraphNavigator;
22
use JMS\Serializer\Exception\RuntimeException;
23
use JMS\Serializer\Exception\XmlErrorException;
24
use JMS\Serializer\Annotation\ExclusionPolicy;
25
use JMS\Serializer\Metadata\PropertyMetadata;
26
use JMS\Serializer\Metadata\VirtualPropertyMetadata;
27
use Metadata\MethodMetadata;
28
use JMS\Serializer\Metadata\ClassMetadata;
29
use Metadata\Driver\AbstractFileDriver;
30
31
class XmlDriver extends AbstractFileDriver
32
{
33 17
    protected function loadMetadataFromFile(\ReflectionClass $class, $path)
34
    {
35 17
        $previous = libxml_use_internal_errors(true);
36 17
        $elem = simplexml_load_file($path);
37 17
        libxml_use_internal_errors($previous);
38
39 17
        if (false === $elem) {
40 1
            throw new XmlErrorException(libxml_get_last_error());
41
        }
42
43 16
        $metadata = new ClassMetadata($name = $class->name);
44 16
        if ( ! $elems = $elem->xpath("./class[@name = '".$name."']")) {
45
            throw new RuntimeException(sprintf('Could not find class %s inside XML element.', $name));
46
        }
47 16
        $elem = reset($elems);
48
49 16
        $metadata->fileResources[] = $path;
50 16
        $metadata->fileResources[] = $class->getFileName();
51 16
        $exclusionPolicy = strtoupper($elem->attributes()->{'exclusion-policy'}) ?: 'NONE';
52 16
        $excludeAll = null !== ($exclude = $elem->attributes()->exclude) ? 'true' === strtolower($exclude) : false;
53 16
        $classAccessType = (string) ($elem->attributes()->{'access-type'} ?: PropertyMetadata::ACCESS_TYPE_PROPERTY);
54
55 16
        $propertiesMetadata = array();
56 16
        $propertiesNodes = array();
57
58 16
        if (null !== $accessorOrder = $elem->attributes()->{'accessor-order'}) {
59
            $metadata->setAccessorOrder((string) $accessorOrder, preg_split('/\s*,\s*/', (string) $elem->attributes()->{'custom-accessor-order'}));
60
        }
61
62 16
        if (null !== $xmlRootName = $elem->attributes()->{'xml-root-name'}) {
63 7
            $metadata->xmlRootName = (string) $xmlRootName;
64 7
        }
65
66 16
        if (null !== $xmlRootNamespace = $elem->attributes()->{'xml-root-namespace'}) {
67 1
            $metadata->xmlRootNamespace = (string) $xmlRootNamespace;
68 1
        }
69
70 16
        $readOnlyClass = 'true' === strtolower($elem->attributes()->{'read-only'});
71
72 16
        $discriminatorFieldName = (string) $elem->attributes()->{'discriminator-field-name'};
73 16
        $discriminatorMap = array();
74 16
        foreach ($elem->xpath('./discriminator-class') as $entry) {
75 1
            if ( ! isset($entry->attributes()->value)) {
76
                throw new RuntimeException('Each discriminator-class element must have a "value" attribute.');
77
            }
78
79 1
            $discriminatorMap[(string) $entry->attributes()->value] = (string) $entry;
80 16
        }
81
82 16
        if ('true' === (string) $elem->attributes()->{'discriminator-disabled'}) {
83
            $metadata->discriminatorDisabled = true;
84 16
        } elseif ( ! empty($discriminatorFieldName) || ! empty($discriminatorMap)) {
85 1
            $metadata->setDiscriminator($discriminatorFieldName, $discriminatorMap);
86 1
        }
87
88 16
        foreach ($elem->xpath('./xml-namespace') as $xmlNamespace) {
89 3
            if ( ! isset($xmlNamespace->attributes()->uri)) {
90
                throw new RuntimeException('The prefix attribute must be set for all xml-namespace elements.');
91
            }
92
93 3
            if (isset($xmlNamespace->attributes()->prefix)) {
94 3
                $prefix = (string) $xmlNamespace->attributes()->prefix;
95 3
            } else {
96 2
                $prefix = null;
97
            }
98
99 3
            $metadata->registerNamespace((string) $xmlNamespace->attributes()->uri, $prefix);
100 16
        }
101
102 16
        foreach ($elem->xpath('./virtual-property') as $method) {
103 2
            if ( ! isset($method->attributes()->method)) {
104
                throw new RuntimeException('The method attribute must be set for all virtual-property elements.');
105
            }
106
107 2
            $virtualPropertyMetadata = new VirtualPropertyMetadata($name, (string) $method->attributes()->method);
108
109 2
            $propertiesMetadata[] = $virtualPropertyMetadata;
110 2
            $propertiesNodes[] = $method;
111 16
        }
112
113 16
        if ( ! $excludeAll) {
114
115 16
            foreach ($class->getProperties() as $property) {
116 15
                if ($name !== $property->class) {
117 2
                    continue;
118
                }
119
120 14
                $propertiesMetadata[] = new PropertyMetadata($name, $pName = $property->getName());
121 14
                $pElems = $elem->xpath("./property[@name = '".$pName."']");
122
123 14
                $propertiesNodes[] = $pElems ? reset($pElems) : null;
124 16
            }
125
126 16
            foreach ($propertiesMetadata as $propertyKey => $pMetadata) {
127
128 15
                $isExclude = false;
129 15
                $isExpose = $pMetadata instanceof VirtualPropertyMetadata;
130
131 15
                $pElem = $propertiesNodes[$propertyKey];
132 15
                if ( ! empty($pElem)) {
133
134 15
                    if (null !== $exclude = $pElem->attributes()->exclude) {
135 1
                        $isExclude = 'true' === strtolower($exclude);
136 1
                    }
137
138 15
                    if (null !== $expose = $pElem->attributes()->expose) {
139 2
                        $isExpose = 'true' === strtolower($expose);
140 2
                    }
141
142 15
                    if (null !== $version = $pElem->attributes()->{'since-version'}) {
143
                        $pMetadata->sinceVersion = (string) $version;
144
                    }
145
146 15
                    if (null !== $version = $pElem->attributes()->{'until-version'}) {
147
                        $pMetadata->untilVersion = (string) $version;
148
                    }
149
150 15
                    if (null !== $serializedName = $pElem->attributes()->{'serialized-name'}) {
151 3
                        $pMetadata->serializedName = (string) $serializedName;
152 3
                    }
153
154 15
                    if (null !== $type = $pElem->attributes()->type) {
155 11
                        $pMetadata->setType((string) $type);
156 15
                    } elseif (isset($pElem->type)) {
157 2
                        $pMetadata->setType((string) $pElem->type);
158 2
                    }
159
160 15
                    if (null !== $groups = $pElem->attributes()->groups) {
161 1
                        $pMetadata->groups = preg_split('/\s*,\s*/', (string) $groups);
162 1
                    }
163
164 15
                    if (isset($pElem->{'xml-list'})) {
165
166 2
                        $pMetadata->xmlCollection = true;
167
168 2
                        $colConfig = $pElem->{'xml-list'};
169 2
                        if (isset($colConfig->attributes()->inline)) {
170 1
                            $pMetadata->xmlCollectionInline = 'true' === (string) $colConfig->attributes()->inline;
171 1
                        }
172
173 2
                        if (isset($colConfig->attributes()->{'entry-name'})) {
174 1
                            $pMetadata->xmlEntryName = (string) $colConfig->attributes()->{'entry-name'};
175 1
                        }
176
                        
177 2
                        if (isset($colConfig->attributes()->{'skip-when-empty'})) {
178 1
                            $pMetadata->xmlCollectionSkipWhenEmpty = 'true' === (string) $colConfig->attributes()->{'skip-when-empty'};
179 1
                        } else {
180 1
                            $pMetadata->xmlCollectionSkipWhenEmpty = true;
181
                        }
182
183 2
                        if (isset($colConfig->attributes()->namespace)) {
184
                            $pMetadata->xmlEntryNamespace = (string) $colConfig->attributes()->namespace;
185
                        }
186 2
                    }
187
188 15
                    if (isset($pElem->{'xml-map'})) {
189
                        $pMetadata->xmlCollection = true;
190
191
                        $colConfig = $pElem->{'xml-map'};
192
                        if (isset($colConfig->attributes()->inline)) {
193
                            $pMetadata->xmlCollectionInline = 'true' === (string) $colConfig->attributes()->inline;
194
                        }
195
196
                        if (isset($colConfig->attributes()->{'entry-name'})) {
197
                            $pMetadata->xmlEntryName = (string) $colConfig->attributes()->{'entry-name'};
198
                        }
199
200
                        if (isset($colConfig->attributes()->namespace)) {
201
                            $pMetadata->xmlEntryNamespace = (string) $colConfig->attributes()->namespace;
202
                        }
203
204
                        if (isset($colConfig->attributes()->{'key-attribute-name'})) {
205
                            $pMetadata->xmlKeyAttribute = (string) $colConfig->attributes()->{'key-attribute-name'};
206
                        }
207
                    }
208
209 15
                    if (isset($pElem->{'xml-element'})) {
210 4
                        $colConfig = $pElem->{'xml-element'};
211 4
                        if (isset($colConfig->attributes()->cdata)) {
212 2
                            $pMetadata->xmlElementCData = 'true' === (string) $colConfig->attributes()->cdata;
213 2
                        }
214
215 4
                        if (isset($colConfig->attributes()->namespace)) {
216 3
                            $pMetadata->xmlNamespace = (string) $colConfig->attributes()->namespace;
217 3
                        }
218 4
                    }
219
220 15
                    if (isset($pElem->attributes()->{'xml-attribute'})) {
221 4
                        $pMetadata->xmlAttribute = 'true' === (string) $pElem->attributes()->{'xml-attribute'};
222 4
                    }
223
224 15
                    if (isset($pElem->attributes()->{'xml-attribute-map'})) {
225
                        $pMetadata->xmlAttribute = 'true' === (string) $pElem->attributes()->{'xml-attribute-map'};
226
                    }
227
228 15
                    if (isset($pElem->attributes()->{'xml-value'})) {
229 2
                        $pMetadata->xmlValue = 'true' === (string) $pElem->attributes()->{'xml-value'};
230 2
                    }
231
232 15
                    if (isset($pElem->attributes()->{'xml-key-value-pairs'})) {
233 1
                        $pMetadata->xmlKeyValuePairs = 'true' === (string) $pElem->attributes()->{'xml-key-value-pairs'};
234 1
                    }
235
236 15
                    if (isset($pElem->attributes()->{'max-depth'})) {
237 1
                        $pMetadata->maxDepth = (int) $pElem->attributes()->{'max-depth'};
238 1
                    }
239
240
                    //we need read-only before setter and getter set, because that method depends on flag being set
241 15
                    if (null !== $readOnly = $pElem->attributes()->{'read-only'}) {
242 1
                        $pMetadata->readOnly = 'true' === strtolower($readOnly);
243 1
                    } else {
244 14
                        $pMetadata->readOnly = $pMetadata->readOnly || $readOnlyClass;
245
                    }
246
247 15
                    $getter = $pElem->attributes()->{'accessor-getter'};
248 15
                    $setter = $pElem->attributes()->{'accessor-setter'};
249 15
                    $pMetadata->setAccessor(
250 15
                        (string) ($pElem->attributes()->{'access-type'} ?: $classAccessType),
251 15
                        $getter ? (string) $getter : null,
252 15
                        $setter ? (string) $setter : null
253 15
                    );
254
255 15
                    if (null !== $inline = $pElem->attributes()->inline) {
256
                        $pMetadata->inline = 'true' === strtolower($inline);
257
                    }
258
259 15
                }
260
261 15
                if ((ExclusionPolicy::NONE === (string) $exclusionPolicy && ! $isExclude)
262 15
                    || (ExclusionPolicy::ALL === (string) $exclusionPolicy && $isExpose)) {
263
264 15
                    $metadata->addPropertyMetadata($pMetadata);
265 15
                }
266 16
            }
267 16
        }
268
269 16
        foreach ($elem->xpath('./callback-method') as $method) {
270
            if ( ! isset($method->attributes()->type)) {
271
                throw new RuntimeException('The type attribute must be set for all callback-method elements.');
272
            }
273
            if ( ! isset($method->attributes()->name)) {
274
                throw new RuntimeException('The name attribute must be set for all callback-method elements.');
275
            }
276
277
            switch ((string) $method->attributes()->type) {
278
                case 'pre-serialize':
279
                    $metadata->addPreSerializeMethod(new MethodMetadata($name, (string) $method->attributes()->name));
280
                    break;
281
282
                case 'post-serialize':
283
                    $metadata->addPostSerializeMethod(new MethodMetadata($name, (string) $method->attributes()->name));
284
                    break;
285
286
                case 'post-deserialize':
287
                    $metadata->addPostDeserializeMethod(new MethodMetadata($name, (string) $method->attributes()->name));
288
                    break;
289
290
                case 'handler':
291
                    if ( ! isset($method->attributes()->format)) {
292
                        throw new RuntimeException('The format attribute must be set for "handler" callback methods.');
293
                    }
294
                    if ( ! isset($method->attributes()->direction)) {
295
                        throw new RuntimeException('The direction attribute must be set for "handler" callback methods.');
296
                    }
297
298
                    $direction = GraphNavigator::parseDirection((string) $method->attributes()->direction);
299
                    $format = (string) $method->attributes()->format;
300
                    $metadata->addHandlerCallback($direction, $format, (string) $method->attributes()->name);
301
302
                    break;
303
304
                default:
305
                    throw new RuntimeException(sprintf('The type "%s" is not supported.', $method->attributes()->name));
306
            }
307 16
        }
308
309 16
        return $metadata;
310
    }
311
312 16
    protected function getExtension()
313
    {
314 16
        return 'xml';
315
    }
316
}
317