Completed
Push — master ( 3e05ae...99069b )
by Asmir
12s
created

YamlDriver::loadMetadataFromFile()   F

Complexity

Conditions 70
Paths 593

Size

Total Lines 235
Code Lines 131

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 106
CRAP Score 97.7747

Importance

Changes 0
Metric Value
cc 70
eloc 131
nc 593
nop 2
dl 0
loc 235
ccs 106
cts 129
cp 0.8217
crap 97.7747
rs 2.0687
c 0
b 0
f 0

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
declare(strict_types=1);
4
5
/*
6
 * Copyright 2016 Johannes M. Schmitt <[email protected]>
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
namespace JMS\Serializer\Metadata\Driver;
22
23
use JMS\Serializer\Annotation\ExclusionPolicy;
24
use JMS\Serializer\Exception\RuntimeException;
25
use JMS\Serializer\Metadata\ClassMetadata;
26
use JMS\Serializer\Metadata\ExpressionPropertyMetadata;
27
use JMS\Serializer\Metadata\PropertyMetadata;
28
use JMS\Serializer\Metadata\VirtualPropertyMetadata;
29
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
30
use JMS\Serializer\Type\Parser;
31
use JMS\Serializer\Type\ParserInterface;
32
use Metadata\Driver\AbstractFileDriver;
33
use Metadata\Driver\FileLocatorInterface;
34
use Metadata\MethodMetadata;
35
use Symfony\Component\Yaml\Yaml;
36
37
class YamlDriver extends AbstractFileDriver
38
{
39
    private $typeParser;
40
    /**
41
     * @var PropertyNamingStrategyInterface
42
     */
43
    private $namingStrategy;
44
45 30
    public function __construct(FileLocatorInterface $locator, PropertyNamingStrategyInterface $namingStrategy, ParserInterface $typeParser = null)
46
    {
47 30
        parent::__construct($locator);
48 30
        $this->typeParser = $typeParser ?? new Parser();
49 30
        $this->namingStrategy = $namingStrategy;
50 30
    }
51
52 30
    protected function loadMetadataFromFile(\ReflectionClass $class, string $file):?\Metadata\ClassMetadata
53
    {
54 30
        $config = Yaml::parse(file_get_contents($file));
55
56 30
        if (!isset($config[$name = $class->name])) {
57
            throw new RuntimeException(sprintf('Expected metadata for class %s to be defined in %s.', $class->name, $file));
58
        }
59
60 30
        $config = $config[$name];
61 30
        $metadata = new ClassMetadata($name);
62 30
        $metadata->fileResources[] = $file;
63 30
        $metadata->fileResources[] = $class->getFileName();
64 30
        $exclusionPolicy = isset($config['exclusion_policy']) ? strtoupper($config['exclusion_policy']) : 'NONE';
65 30
        $excludeAll = isset($config['exclude']) ? (Boolean)$config['exclude'] : false;
66 30
        $classAccessType = isset($config['access_type']) ? $config['access_type'] : PropertyMetadata::ACCESS_TYPE_PROPERTY;
67 30
        $readOnlyClass = isset($config['read_only']) ? (Boolean)$config['read_only'] : false;
68 30
        $this->addClassProperties($metadata, $config);
69
70 30
        $propertiesMetadata = [];
71 30
        if (array_key_exists('virtual_properties', $config)) {
72 5
            foreach ($config['virtual_properties'] as $methodName => $propertySettings) {
73 5
                if (isset($propertySettings['exp'])) {
74 2
                    $virtualPropertyMetadata = new ExpressionPropertyMetadata($name, $methodName, $propertySettings['exp']);
75 2
                    unset($propertySettings['exp']);
76
                } else {
77
78 4
                    if (!$class->hasMethod($methodName)) {
79
                        throw new RuntimeException('The method ' . $methodName . ' not found in class ' . $class->name);
80
                    }
81 4
                    $virtualPropertyMetadata = new VirtualPropertyMetadata($name, $methodName);
82
                }
83
84 5
                $pName = !empty($propertySettings["name"]) ? $propertySettings["name"] : $virtualPropertyMetadata->name;
85
86 5
                $propertiesMetadata[$pName] = $virtualPropertyMetadata;
87 5
                $config['properties'][$pName] = $propertySettings;
88
            }
89
        }
90
91 30
        if (!$excludeAll) {
92 30
            foreach ($class->getProperties() as $property) {
93 25
                if ($property->class !== $name || (isset($property->info) && $property->info['class'] !== $name)) {
0 ignored issues
show
Bug introduced by
The property info does not seem to exist on ReflectionProperty.
Loading history...
94 2
                    continue;
95
                }
96
97 24
                $pName = $property->getName();
98 24
                $propertiesMetadata[$pName] = new PropertyMetadata($name, $pName);
99
            }
100
101 30
            foreach ($propertiesMetadata as $pName => $pMetadata) {
102 26
                $isExclude = false;
103 26
                $isExpose = $pMetadata instanceof VirtualPropertyMetadata
104 25
                    || $pMetadata instanceof ExpressionPropertyMetadata
105 26
                    || (isset($config['properties']) && array_key_exists($pName, $config['properties']));
106
107 26
                if (isset($config['properties'][$pName])) {
108 23
                    $pConfig = $config['properties'][$pName];
109
110 23
                    if (isset($pConfig['exclude'])) {
111 2
                        $isExclude = (Boolean)$pConfig['exclude'];
112
                    }
113
114 23
                    if ($isExclude) {
115 2
                        continue;
116
                    }
117
118 21
                    if (isset($pConfig['expose'])) {
119 3
                        $isExpose = (Boolean)$pConfig['expose'];
120
                    }
121
122 21
                    if (isset($pConfig['skip_when_empty'])) {
123 1
                        $pMetadata->skipWhenEmpty = (Boolean)$pConfig['skip_when_empty'];
124
                    }
125
126 21
                    if (isset($pConfig['since_version'])) {
127
                        $pMetadata->sinceVersion = (string)$pConfig['since_version'];
128
                    }
129
130 21
                    if (isset($pConfig['until_version'])) {
131
                        $pMetadata->untilVersion = (string)$pConfig['until_version'];
132
                    }
133
134 21
                    if (isset($pConfig['exclude_if'])) {
135 1
                        $pMetadata->excludeIf = (string)$pConfig['exclude_if'];
136
                    }
137
138 21
                    if (isset($pConfig['expose_if'])) {
139 1
                        $pMetadata->excludeIf = "!(" . $pConfig['expose_if'] . ")";
140
                    }
141
142 21
                    if (isset($pConfig['serialized_name'])) {
143 4
                        $pMetadata->serializedName = (string)$pConfig['serialized_name'];
144
                    }
145
146 21
                    if (isset($pConfig['type'])) {
147 15
                        $pMetadata->setType($this->typeParser->parse((string)$pConfig['type']));
148
                    }
149
150 21
                    if (isset($pConfig['groups'])) {
151 1
                        $pMetadata->groups = $pConfig['groups'];
152
                    }
153
154 21
                    if (isset($pConfig['xml_list'])) {
155 2
                        $pMetadata->xmlCollection = true;
156
157 2
                        $colConfig = $pConfig['xml_list'];
158 2
                        if (isset($colConfig['inline'])) {
159 2
                            $pMetadata->xmlCollectionInline = (Boolean)$colConfig['inline'];
160
                        }
161
162 2
                        if (isset($colConfig['entry_name'])) {
163 1
                            $pMetadata->xmlEntryName = (string)$colConfig['entry_name'];
164
                        }
165
166 2
                        if (isset($colConfig['skip_when_empty'])) {
167 1
                            $pMetadata->xmlCollectionSkipWhenEmpty = (Boolean)$colConfig['skip_when_empty'];
168
                        } else {
169 2
                            $pMetadata->xmlCollectionSkipWhenEmpty = true;
170
                        }
171
172 2
                        if (isset($colConfig['namespace'])) {
173
                            $pMetadata->xmlEntryNamespace = (string)$colConfig['namespace'];
174
                        }
175
                    }
176
177 21
                    if (isset($pConfig['xml_map'])) {
178
                        $pMetadata->xmlCollection = true;
179
180
                        $colConfig = $pConfig['xml_map'];
181
                        if (isset($colConfig['inline'])) {
182
                            $pMetadata->xmlCollectionInline = (Boolean)$colConfig['inline'];
183
                        }
184
185
                        if (isset($colConfig['entry_name'])) {
186
                            $pMetadata->xmlEntryName = (string)$colConfig['entry_name'];
187
                        }
188
189
                        if (isset($colConfig['namespace'])) {
190
                            $pMetadata->xmlEntryNamespace = (string)$colConfig['namespace'];
191
                        }
192
193
                        if (isset($colConfig['key_attribute_name'])) {
194
                            $pMetadata->xmlKeyAttribute = $colConfig['key_attribute_name'];
195
                        }
196
                    }
197
198 21
                    if (isset($pConfig['xml_element'])) {
199 4
                        $colConfig = $pConfig['xml_element'];
200 4
                        if (isset($colConfig['cdata'])) {
201 2
                            $pMetadata->xmlElementCData = (Boolean)$colConfig['cdata'];
202
                        }
203
204 4
                        if (isset($colConfig['namespace'])) {
205 3
                            $pMetadata->xmlNamespace = (string)$colConfig['namespace'];
206
                        }
207
                    }
208
209 21
                    if (isset($pConfig['xml_attribute'])) {
210 4
                        $pMetadata->xmlAttribute = (Boolean)$pConfig['xml_attribute'];
211
                    }
212
213 21
                    if (isset($pConfig['xml_attribute_map'])) {
214
                        $pMetadata->xmlAttributeMap = (Boolean)$pConfig['xml_attribute_map'];
215
                    }
216
217 21
                    if (isset($pConfig['xml_value'])) {
218 2
                        $pMetadata->xmlValue = (Boolean)$pConfig['xml_value'];
219
                    }
220
221 21
                    if (isset($pConfig['xml_key_value_pairs'])) {
222 1
                        $pMetadata->xmlKeyValuePairs = (Boolean)$pConfig['xml_key_value_pairs'];
223
                    }
224
225
                    //we need read_only before setter and getter set, because that method depends on flag being set
226 21
                    if (isset($pConfig['read_only'])) {
227 1
                        $pMetadata->readOnly = (Boolean)$pConfig['read_only'];
228
                    } else {
229 20
                        $pMetadata->readOnly = $pMetadata->readOnly || $readOnlyClass;
230
                    }
231
232 21
                    $pMetadata->setAccessor(
233 21
                        isset($pConfig['access_type']) ? $pConfig['access_type'] : $classAccessType,
234 21
                        isset($pConfig['accessor']['getter']) ? $pConfig['accessor']['getter'] : null,
235 21
                        isset($pConfig['accessor']['setter']) ? $pConfig['accessor']['setter'] : null
236
                    );
237
238 21
                    if (isset($pConfig['inline'])) {
239 2
                        $pMetadata->inline = (Boolean)$pConfig['inline'];
240
                    }
241
242 21
                    if (isset($pConfig['max_depth'])) {
243 1
                        $pMetadata->maxDepth = (int)$pConfig['max_depth'];
244
                    }
245
                }
246
247 26
                if (!$pMetadata->serializedName) {
248 26
                    $pMetadata->serializedName = $this->namingStrategy->translateName($pMetadata);
249
                }
250
251 26
                if ($pMetadata->inline) {
252 2
                    $metadata->isList = $metadata->isList || PropertyMetadata::isCollectionList($pMetadata->type);
253 2
                    $metadata->isMap = $metadata->isMap || PropertyMetadata::isCollectionMap($pMetadata->type);
254
                }
255
256 26
                if (isset($config['properties'][$pName])) {
257 21
                    $pConfig = $config['properties'][$pName];
258
259 21
                    if (isset($pConfig['name'])) {
260 1
                        $pMetadata->name = (string)$pConfig['name'];
261
                    }
262
                }
263
264 26
                if ((ExclusionPolicy::NONE === $exclusionPolicy && !$isExclude)
265 26
                    || (ExclusionPolicy::ALL === $exclusionPolicy && $isExpose)
266
                ) {
267 26
                    $metadata->addPropertyMetadata($pMetadata);
268
                }
269
            }
270
        }
271
272 30
        if (isset($config['callback_methods'])) {
273
            $cConfig = $config['callback_methods'];
274
275
            if (isset($cConfig['pre_serialize'])) {
276
                $metadata->preSerializeMethods = $this->getCallbackMetadata($class, $cConfig['pre_serialize']);
277
            }
278
            if (isset($cConfig['post_serialize'])) {
279
                $metadata->postSerializeMethods = $this->getCallbackMetadata($class, $cConfig['post_serialize']);
280
            }
281
            if (isset($cConfig['post_deserialize'])) {
282
                $metadata->postDeserializeMethods = $this->getCallbackMetadata($class, $cConfig['post_deserialize']);
283
            }
284
        }
285
286 30
        return $metadata;
287
    }
288
289 30
    protected function getExtension():string
290
    {
291 30
        return 'yml';
292
    }
293
294 30
    private function addClassProperties(ClassMetadata $metadata, array $config)
295
    {
296 30
        if (isset($config['custom_accessor_order']) && !isset($config['accessor_order'])) {
297 1
            $config['accessor_order'] = 'custom';
298
        }
299
300 30
        if (isset($config['accessor_order'])) {
301 1
            $metadata->setAccessorOrder($config['accessor_order'], isset($config['custom_accessor_order']) ? $config['custom_accessor_order'] : []);
302
        }
303
304 30
        if (isset($config['xml_root_name'])) {
305 9
            $metadata->xmlRootName = (string)$config['xml_root_name'];
306
        }
307
308 30
        if (isset($config['xml_root_prefix'])) {
309 1
            $metadata->xmlRootPrefix = (string)$config['xml_root_prefix'];
310
        }
311
312 30
        if (isset($config['xml_root_namespace'])) {
313 1
            $metadata->xmlRootNamespace = (string)$config['xml_root_namespace'];
314
        }
315
316 30
        if (array_key_exists('xml_namespaces', $config)) {
317
318 3
            foreach ($config['xml_namespaces'] as $prefix => $uri) {
319 3
                $metadata->registerNamespace($uri, $prefix);
320
            }
321
        }
322
323 30
        if (isset($config['discriminator'])) {
324 5
            if (isset($config['discriminator']['disabled']) && true === $config['discriminator']['disabled']) {
325
                $metadata->discriminatorDisabled = true;
326
            } else {
327 5
                if (!isset($config['discriminator']['field_name'])) {
328
                    throw new RuntimeException('The "field_name" attribute must be set for discriminators.');
329
                }
330
331 5
                if (!isset($config['discriminator']['map']) || !\is_array($config['discriminator']['map'])) {
332
                    throw new RuntimeException('The "map" attribute must be set, and be an array for discriminators.');
333
                }
334 5
                $groups = isset($config['discriminator']['groups']) ? $config['discriminator']['groups'] : [];
335 5
                $metadata->setDiscriminator($config['discriminator']['field_name'], $config['discriminator']['map'], $groups);
336
337 5
                if (isset($config['discriminator']['xml_attribute'])) {
338 2
                    $metadata->xmlDiscriminatorAttribute = (bool)$config['discriminator']['xml_attribute'];
339
                }
340 5
                if (isset($config['discriminator']['xml_element'])) {
341 3
                    if (isset($config['discriminator']['xml_element']['cdata'])) {
342 1
                        $metadata->xmlDiscriminatorCData = (bool)$config['discriminator']['xml_element']['cdata'];
343
                    }
344 3
                    if (isset($config['discriminator']['xml_element']['namespace'])) {
345 2
                        $metadata->xmlDiscriminatorNamespace = (string)$config['discriminator']['xml_element']['namespace'];
346
                    }
347
                }
348
            }
349
        }
350 30
    }
351
352
    private function getCallbackMetadata(\ReflectionClass $class, $config)
353
    {
354
        if (\is_string($config)) {
355
            $config = [$config];
356
        } elseif (!\is_array($config)) {
357
            throw new RuntimeException(sprintf('callback methods expects a string, or an array of strings that represent method names, but got %s.', json_encode($config['pre_serialize'])));
358
        }
359
360
        $methods = [];
361
        foreach ($config as $name) {
362
            if (!$class->hasMethod($name)) {
363
                throw new RuntimeException(sprintf('The method %s does not exist in class %s.', $name, $class->name));
364
            }
365
366
            $methods[] = new MethodMetadata($class->name, $name);
367
        }
368
369
        return $methods;
370
    }
371
}
372