Completed
Pull Request — master (#743)
by Asmir
07:41
created

AnnotationDriver::loadMetadataForClass()   F

Complexity

Conditions 59
Paths 672

Size

Total Lines 176
Code Lines 142

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 137
CRAP Score 59.0341

Importance

Changes 0
Metric Value
dl 0
loc 176
ccs 137
cts 140
cp 0.9786
rs 2
c 0
b 0
f 0
cc 59
eloc 142
nc 672
nop 1
crap 59.0341

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 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\Metadata\Driver;
20
21
use Doctrine\Common\Annotations\Reader;
22
use JMS\Serializer\Annotation\Accessor;
23
use JMS\Serializer\Annotation\AccessorOrder;
24
use JMS\Serializer\Annotation\AccessType;
25
use JMS\Serializer\Annotation\Discriminator;
26
use JMS\Serializer\Annotation\Exclude;
27
use JMS\Serializer\Annotation\ExcludeIf;
28
use JMS\Serializer\Annotation\ExclusionPolicy;
29
use JMS\Serializer\Annotation\Expose;
30
use JMS\Serializer\Annotation\Groups;
31
use JMS\Serializer\Annotation\Inline;
32
use JMS\Serializer\Annotation\MaxDepth;
33
use JMS\Serializer\Annotation\PostDeserialize;
34
use JMS\Serializer\Annotation\PostSerialize;
35
use JMS\Serializer\Annotation\PreSerialize;
36
use JMS\Serializer\Annotation\ReadOnly;
37
use JMS\Serializer\Annotation\SerializedName;
38
use JMS\Serializer\Annotation\Since;
39
use JMS\Serializer\Annotation\SkipWhenEmpty;
40
use JMS\Serializer\Annotation\Type;
41
use JMS\Serializer\Annotation\Until;
42
use JMS\Serializer\Annotation\VirtualProperty;
43
use JMS\Serializer\Annotation\XmlAttribute;
44
use JMS\Serializer\Annotation\XmlAttributeMap;
45
use JMS\Serializer\Annotation\XmlDiscriminator;
46
use JMS\Serializer\Annotation\XmlElement;
47
use JMS\Serializer\Annotation\XmlKeyValuePairs;
48
use JMS\Serializer\Annotation\XmlList;
49
use JMS\Serializer\Annotation\XmlMap;
50
use JMS\Serializer\Annotation\XmlNamespace;
51
use JMS\Serializer\Annotation\XmlRoot;
52
use JMS\Serializer\Annotation\XmlValue;
53
use JMS\Serializer\Exception\InvalidArgumentException;
54
use JMS\Serializer\GraphNavigatorInterface;
55
use JMS\Serializer\Metadata\ClassMetadata;
56
use JMS\Serializer\Metadata\ExpressionPropertyMetadata;
57
use JMS\Serializer\Metadata\PropertyMetadata;
58
use JMS\Serializer\Metadata\VirtualPropertyMetadata;
59
use Metadata\Driver\DriverInterface;
60
use Metadata\MethodMetadata;
61
62
class AnnotationDriver implements DriverInterface
63
{
64
    private $reader;
65
66 431
    public function __construct(Reader $reader)
67
    {
68 431
        $this->reader = $reader;
69 431
    }
70
71 269
    public function loadMetadataForClass(\ReflectionClass $class)
72
    {
73 269
        $classMetadata = new ClassMetadata($name = $class->name);
74 269
        $classMetadata->fileResources[] = $class->getFilename();
75
76 269
        $propertiesMetadata = array();
77 269
        $propertiesAnnotations = array();
78
79 269
        $exclusionPolicy = 'NONE';
80 269
        $excludeAll = false;
81 269
        $classAccessType = PropertyMetadata::ACCESS_TYPE_PROPERTY;
82 269
        $readOnlyClass = false;
83 269
        foreach ($this->reader->getClassAnnotations($class) as $annot) {
84 157
            if ($annot instanceof ExclusionPolicy) {
85 35
                $exclusionPolicy = $annot->policy;
86 156
            } elseif ($annot instanceof XmlRoot) {
87 69
                $classMetadata->xmlRootName = $annot->name;
88 69
                $classMetadata->xmlRootNamespace = $annot->namespace;
89 120
            } elseif ($annot instanceof XmlNamespace) {
90 24
                $classMetadata->registerNamespace($annot->uri, $annot->prefix);
91 98
            } elseif ($annot instanceof Exclude) {
92
                $excludeAll = true;
93 98
            } elseif ($annot instanceof AccessType) {
94 5
                $classAccessType = $annot->type;
95 95
            } elseif ($annot instanceof ReadOnly) {
96 5
                $readOnlyClass = true;
97 90
            } elseif ($annot instanceof AccessorOrder) {
98 46
                $classMetadata->setAccessorOrder($annot->order, $annot->custom);
99 44
            } elseif ($annot instanceof Discriminator) {
100 22
                if ($annot->disabled) {
101
                    $classMetadata->discriminatorDisabled = true;
102
                } else {
103 22
                    $classMetadata->setDiscriminator($annot->field, $annot->map, $annot->groups);
104
                }
105 27
            } elseif ($annot instanceof XmlDiscriminator) {
106 5
                $classMetadata->xmlDiscriminatorAttribute = (bool)$annot->attribute;
107 5
                $classMetadata->xmlDiscriminatorCData = (bool)$annot->cdata;
108 5
                $classMetadata->xmlDiscriminatorNamespace = $annot->namespace ? (string)$annot->namespace : null;
109 22
            } elseif ($annot instanceof VirtualProperty) {
110 8
                $virtualPropertyMetadata = new ExpressionPropertyMetadata($name, $annot->name, $annot->exp);
111 8
                $propertiesMetadata[] = $virtualPropertyMetadata;
112 157
                $propertiesAnnotations[] = $annot->options;
113
            }
114
        }
115
116 269
        foreach ($class->getMethods() as $method) {
117 212
            if ($method->class !== $name) {
118 19
                continue;
119
            }
120
121 211
            $methodAnnotations = $this->reader->getMethodAnnotations($method);
122
123 211
            foreach ($methodAnnotations as $annot) {
124 47
                if ($annot instanceof PreSerialize) {
125 3
                    $classMetadata->addPreSerializeMethod(new MethodMetadata($name, $method->name));
126 3
                    continue 2;
127 47
                } elseif ($annot instanceof PostDeserialize) {
128 6
                    $classMetadata->addPostDeserializeMethod(new MethodMetadata($name, $method->name));
129 6
                    continue 2;
130 44
                } elseif ($annot instanceof PostSerialize) {
131 3
                    $classMetadata->addPostSerializeMethod(new MethodMetadata($name, $method->name));
132 3
                    continue 2;
133 41
                } elseif ($annot instanceof VirtualProperty) {
134 41
                    $virtualPropertyMetadata = new VirtualPropertyMetadata($name, $method->name);
135 41
                    $propertiesMetadata[] = $virtualPropertyMetadata;
136 41
                    $propertiesAnnotations[] = $methodAnnotations;
137 211
                    continue 2;
138
                }
139
            }
140
        }
141
142 269
        if (!$excludeAll) {
143 269
            foreach ($class->getProperties() as $property) {
144 249
                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 in ReflectionProperty.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
145 21
                    continue;
146
                }
147 248
                $propertiesMetadata[] = new PropertyMetadata($name, $property->getName());
148 248
                $propertiesAnnotations[] = $this->reader->getPropertyAnnotations($property);
149
            }
150
151 269
            foreach ($propertiesMetadata as $propertyKey => $propertyMetadata) {
152 257
                $isExclude = false;
153 257
                $isExpose = $propertyMetadata instanceof VirtualPropertyMetadata
154 257
                    || $propertyMetadata instanceof ExpressionPropertyMetadata;
155 257
                $propertyMetadata->readOnly = $propertyMetadata->readOnly || $readOnlyClass;
156 257
                $accessType = $classAccessType;
157 257
                $accessor = array(null, null);
158
159 257
                $propertyAnnotations = $propertiesAnnotations[$propertyKey];
160
161 257
                foreach ($propertyAnnotations as $annot) {
162 254
                    if ($annot instanceof Since) {
163 7
                        $propertyMetadata->sinceVersion = $annot->version;
164 254
                    } elseif ($annot instanceof Until) {
165 7
                        $propertyMetadata->untilVersion = $annot->version;
166 254
                    } elseif ($annot instanceof SerializedName) {
167 87
                        $propertyMetadata->serializedName = $annot->name;
168 254
                    } elseif ($annot instanceof SkipWhenEmpty) {
169 7
                        $propertyMetadata->skipWhenEmpty = true;
170 253
                    } elseif ($annot instanceof Expose) {
171 37
                        $isExpose = true;
172 37
                        if (null !== $annot->if) {
173 37
                            $propertyMetadata->excludeIf = "!(" . $annot->if . ")";
174
                        }
175 253
                    } elseif ($annot instanceof Exclude) {
176 43
                        if (null !== $annot->if) {
177 21
                            $propertyMetadata->excludeIf = $annot->if;
178
                        } else {
179 43
                            $isExclude = true;
180
                        }
181 251
                    } elseif ($annot instanceof Type) {
182 210
                        $propertyMetadata->setType($annot->name);
183 166
                    } elseif ($annot instanceof XmlElement) {
184 21
                        $propertyMetadata->xmlAttribute = false;
185 21
                        $propertyMetadata->xmlElementCData = $annot->cdata;
186 21
                        $propertyMetadata->xmlNamespace = $annot->namespace;
187 160
                    } elseif ($annot instanceof XmlList) {
188 45
                        $propertyMetadata->xmlCollection = true;
189 45
                        $propertyMetadata->xmlCollectionInline = $annot->inline;
190 45
                        $propertyMetadata->xmlEntryName = $annot->entry;
191 45
                        $propertyMetadata->xmlEntryNamespace = $annot->namespace;
192 45
                        $propertyMetadata->xmlCollectionSkipWhenEmpty = $annot->skipWhenEmpty;
193 152
                    } elseif ($annot instanceof XmlMap) {
194 23
                        $propertyMetadata->xmlCollection = true;
195 23
                        $propertyMetadata->xmlCollectionInline = $annot->inline;
196 23
                        $propertyMetadata->xmlEntryName = $annot->entry;
197 23
                        $propertyMetadata->xmlEntryNamespace = $annot->namespace;
198 23
                        $propertyMetadata->xmlKeyAttribute = $annot->keyAttribute;
199 144
                    } elseif ($annot instanceof XmlKeyValuePairs) {
200 9
                        $propertyMetadata->xmlKeyValuePairs = true;
201 135
                    } elseif ($annot instanceof XmlAttribute) {
202 44
                        $propertyMetadata->xmlAttribute = true;
203 44
                        $propertyMetadata->xmlNamespace = $annot->namespace;
204 129
                    } elseif ($annot instanceof XmlValue) {
205 29
                        $propertyMetadata->xmlValue = true;
206 29
                        $propertyMetadata->xmlElementCData = $annot->cdata;
207 106
                    } elseif ($annot instanceof XmlElement) {
208
                        $propertyMetadata->xmlElementCData = $annot->cdata;
209 106
                    } elseif ($annot instanceof AccessType) {
210 3
                        $accessType = $annot->type;
211 106
                    } elseif ($annot instanceof ReadOnly) {
212 10
                        $propertyMetadata->readOnly = $annot->readOnly;
213 103
                    } elseif ($annot instanceof Accessor) {
214 11
                        $accessor = array($annot->getter, $annot->setter);
215 92
                    } elseif ($annot instanceof Groups) {
216 40
                        $propertyMetadata->groups = $annot->groups;
217 40
                        foreach ((array)$propertyMetadata->groups as $groupName) {
218 40
                            if (false !== strpos($groupName, ',')) {
219 3
                                throw new InvalidArgumentException(sprintf(
220 3
                                    'Invalid group name "%s" on "%s", did you mean to create multiple groups?',
221 3
                                    implode(', ', $propertyMetadata->groups),
222 40
                                    $propertyMetadata->class . '->' . $propertyMetadata->name
223
                                ));
224
                            }
225
                        }
226 70
                    } elseif ($annot instanceof Inline) {
227 7
                        $propertyMetadata->inline = true;
228 63
                    } elseif ($annot instanceof XmlAttributeMap) {
229 4
                        $propertyMetadata->xmlAttributeMap = true;
230 59
                    } elseif ($annot instanceof MaxDepth) {
231 251
                        $propertyMetadata->maxDepth = $annot->depth;
232
                    }
233
                }
234
235
236 254
                if ((ExclusionPolicy::NONE === $exclusionPolicy && !$isExclude)
237 254
                    || (ExclusionPolicy::ALL === $exclusionPolicy && $isExpose)
238
                ) {
239 254
                    $propertyMetadata->setAccessor($accessType, $accessor[0], $accessor[1]);
240 254
                    $classMetadata->addPropertyMetadata($propertyMetadata);
241
                }
242
            }
243
        }
244
245 266
        return $classMetadata;
246
    }
247
}
248