Completed
Pull Request — master (#787)
by
unknown
03:32
created

AnnotationDriver   F

Complexity

Total Complexity 62

Size/Duplication

Total Lines 191
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 33

Test Coverage

Coverage 97.55%

Importance

Changes 0
Metric Value
wmc 62
c 0
b 0
f 0
lcom 1
cbo 33
dl 0
loc 191
ccs 159
cts 163
cp 0.9755
rs 1.3043

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
F loadMetadataForClass() 0 181 61

How to fix   Complexity   

Complex Class

Complex classes like AnnotationDriver often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use AnnotationDriver, and based on these observations, apply Extract Interface, too.

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\DeserializeType;
26
use JMS\Serializer\Annotation\Discriminator;
27
use JMS\Serializer\Annotation\Exclude;
28
use JMS\Serializer\Annotation\ExcludeIf;
29
use JMS\Serializer\Annotation\ExclusionPolicy;
30
use JMS\Serializer\Annotation\Expose;
31
use JMS\Serializer\Annotation\Groups;
32
use JMS\Serializer\Annotation\HandlerCallback;
33
use JMS\Serializer\Annotation\Inline;
34
use JMS\Serializer\Annotation\MaxDepth;
35
use JMS\Serializer\Annotation\PostDeserialize;
36
use JMS\Serializer\Annotation\PostSerialize;
37
use JMS\Serializer\Annotation\PreSerialize;
38
use JMS\Serializer\Annotation\ReadOnly;
39
use JMS\Serializer\Annotation\SerializedName;
40
use JMS\Serializer\Annotation\Since;
41
use JMS\Serializer\Annotation\SkipWhenEmpty;
42
use JMS\Serializer\Annotation\Type;
43
use JMS\Serializer\Annotation\Until;
44
use JMS\Serializer\Annotation\VirtualProperty;
45
use JMS\Serializer\Annotation\XmlAttribute;
46
use JMS\Serializer\Annotation\XmlAttributeMap;
47
use JMS\Serializer\Annotation\XmlDiscriminator;
48
use JMS\Serializer\Annotation\XmlElement;
49
use JMS\Serializer\Annotation\XmlKeyValuePairs;
50
use JMS\Serializer\Annotation\XmlList;
51
use JMS\Serializer\Annotation\XmlMap;
52
use JMS\Serializer\Annotation\XmlNamespace;
53
use JMS\Serializer\Annotation\XmlRoot;
54
use JMS\Serializer\Annotation\XmlValue;
55
use JMS\Serializer\Exception\InvalidArgumentException;
56
use JMS\Serializer\GraphNavigator;
57
use JMS\Serializer\Metadata\ClassMetadata;
58
use JMS\Serializer\Metadata\ExpressionPropertyMetadata;
59
use JMS\Serializer\Metadata\PropertyMetadata;
60
use JMS\Serializer\Metadata\VirtualPropertyMetadata;
61
use Metadata\Driver\DriverInterface;
62
use Metadata\MethodMetadata;
63
64
class AnnotationDriver implements DriverInterface
65
{
66
    private $reader;
67
68 429
    public function __construct(Reader $reader)
69
    {
70 429
        $this->reader = $reader;
71 429
    }
72
73 263
    public function loadMetadataForClass(\ReflectionClass $class)
74
    {
75 263
        $classMetadata = new ClassMetadata($name = $class->name);
76 263
        $classMetadata->fileResources[] = $class->getFilename();
77
78 263
        $propertiesMetadata = array();
79 263
        $propertiesAnnotations = array();
80
81 263
        $exclusionPolicy = 'NONE';
82 263
        $excludeAll = false;
83 263
        $classAccessType = PropertyMetadata::ACCESS_TYPE_PROPERTY;
84 263
        $readOnlyClass = false;
85 263
        foreach ($this->reader->getClassAnnotations($class) as $annot) {
86 150
            if ($annot instanceof ExclusionPolicy) {
87 35
                $exclusionPolicy = $annot->policy;
88 150
            } elseif ($annot instanceof XmlRoot) {
89 65
                $classMetadata->xmlRootName = $annot->name;
90 65
                $classMetadata->xmlRootNamespace = $annot->namespace;
91 149
            } elseif ($annot instanceof XmlNamespace) {
92 23
                $classMetadata->registerNamespace($annot->uri, $annot->prefix);
93 115
            } elseif ($annot instanceof Exclude) {
94
                $excludeAll = true;
95 94
            } elseif ($annot instanceof AccessType) {
96 3
                $classAccessType = $annot->type;
97 94
            } elseif ($annot instanceof ReadOnly) {
98 3
                $readOnlyClass = true;
99 91
            } elseif ($annot instanceof AccessorOrder) {
100 46
                $classMetadata->setAccessorOrder($annot->order, $annot->custom);
101 88
            } elseif ($annot instanceof Discriminator) {
102 21
                if ($annot->disabled) {
103
                    $classMetadata->discriminatorDisabled = true;
104
                } else {
105 21
                    $classMetadata->setDiscriminator($annot->field, $annot->map, $annot->groups);
106
                }
107 42
            } elseif ($annot instanceof XmlDiscriminator) {
108 5
                $classMetadata->xmlDiscriminatorAttribute = (bool)$annot->attribute;
109 5
                $classMetadata->xmlDiscriminatorCData = (bool)$annot->cdata;
110 5
                $classMetadata->xmlDiscriminatorNamespace = $annot->namespace ? (string)$annot->namespace : null;
111 26
            } elseif ($annot instanceof VirtualProperty) {
112 8
                $virtualPropertyMetadata = new ExpressionPropertyMetadata($name, $annot->name, $annot->exp);
113 8
                $propertiesMetadata[] = $virtualPropertyMetadata;
114 8
                $propertiesAnnotations[] = $annot->options;
115 8
            }
116 263
        }
117
118 263
        foreach ($class->getMethods() as $method) {
119 205
            if ($method->class !== $name) {
120 16
                continue;
121
            }
122
123 204
            $methodAnnotations = $this->reader->getMethodAnnotations($method);
124
125 204
            foreach ($methodAnnotations as $annot) {
126 50
                if ($annot instanceof PreSerialize) {
127 3
                    $classMetadata->addPreSerializeMethod(new MethodMetadata($name, $method->name));
128 3
                    continue 2;
129 50
                } elseif ($annot instanceof PostDeserialize) {
130 6
                    $classMetadata->addPostDeserializeMethod(new MethodMetadata($name, $method->name));
131 6
                    continue 2;
132 47
                } elseif ($annot instanceof PostSerialize) {
133 3
                    $classMetadata->addPostSerializeMethod(new MethodMetadata($name, $method->name));
134 3
                    continue 2;
135 44
                } elseif ($annot instanceof VirtualProperty) {
136 40
                    $virtualPropertyMetadata = new VirtualPropertyMetadata($name, $method->name);
137 40
                    $propertiesMetadata[] = $virtualPropertyMetadata;
138 40
                    $propertiesAnnotations[] = $methodAnnotations;
139 40
                    continue 2;
140 7
                } elseif ($annot instanceof HandlerCallback) {
141 4
                    $classMetadata->addHandlerCallback(GraphNavigator::parseDirection($annot->direction), $annot->format, $method->name);
142 4
                    continue 2;
143
                }
144 176
            }
145 263
        }
146
147 263
        if (!$excludeAll) {
148 263
            foreach ($class->getProperties() as $property) {
149 242
                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...
150 18
                    continue;
151
                }
152 241
                $propertiesMetadata[] = new PropertyMetadata($name, $property->getName());
153 241
                $propertiesAnnotations[] = $this->reader->getPropertyAnnotations($property);
154 263
            }
155
156 263
            foreach ($propertiesMetadata as $propertyKey => $propertyMetadata) {
157 250
                $isExclude = false;
158
                $isExpose = $propertyMetadata instanceof VirtualPropertyMetadata
159 250
                    || $propertyMetadata instanceof ExpressionPropertyMetadata;
160 250
                $propertyMetadata->readOnly = $propertyMetadata->readOnly || $readOnlyClass;
161 250
                $accessType = $classAccessType;
162 250
                $accessor = array(null, null);
163
164 250
                $propertyAnnotations = $propertiesAnnotations[$propertyKey];
165
166 250
                foreach ($propertyAnnotations as $annot) {
167 242
                    if ($annot instanceof Since) {
168 7
                        $propertyMetadata->sinceVersion = $annot->version;
169 242
                    } elseif ($annot instanceof Until) {
170 7
                        $propertyMetadata->untilVersion = $annot->version;
171 242
                    } elseif ($annot instanceof SerializedName) {
172 82
                        $propertyMetadata->serializedName = $annot->name;
173 242
                    } elseif ($annot instanceof SkipWhenEmpty) {
174 7
                        $propertyMetadata->skipWhenEmpty = true;
175 242
                    } elseif ($annot instanceof Expose) {
176 36
                        $isExpose = true;
177 36
                        if (null !== $annot->if) {
178 33
                            $propertyMetadata->excludeIf = "!(" . $annot->if . ")";
179 33
                        }
180 241
                    } elseif ($annot instanceof Exclude) {
181 40
                        if (null !== $annot->if) {
182 21
                            $propertyMetadata->excludeIf = $annot->if;
183 21
                        } else {
184 25
                            $isExclude = true;
185
                        }
186 241
                    } elseif ($annot instanceof Type) {
187 199
                        $propertyMetadata->setType($annot->name);
188 241
                    } else if ($annot instanceof DeserializeType) {
189 8
                        $propertyMetadata->setDeserializeType($annot->name);
190 161
                    } elseif ($annot instanceof XmlElement) {
191 21
                        $propertyMetadata->xmlAttribute = false;
192 21
                        $propertyMetadata->xmlElementCData = $annot->cdata;
193 21
                        $propertyMetadata->xmlNamespace = $annot->namespace;
194 161
                    } elseif ($annot instanceof XmlList) {
195 43
                        $propertyMetadata->xmlCollection = true;
196 43
                        $propertyMetadata->xmlCollectionInline = $annot->inline;
197 43
                        $propertyMetadata->xmlEntryName = $annot->entry;
198 43
                        $propertyMetadata->xmlEntryNamespace = $annot->namespace;
199 43
                        $propertyMetadata->xmlCollectionSkipWhenEmpty = $annot->skipWhenEmpty;
200 155
                    } elseif ($annot instanceof XmlMap) {
201 23
                        $propertyMetadata->xmlCollection = true;
202 23
                        $propertyMetadata->xmlCollectionInline = $annot->inline;
203 23
                        $propertyMetadata->xmlEntryName = $annot->entry;
204 23
                        $propertyMetadata->xmlEntryNamespace = $annot->namespace;
205 23
                        $propertyMetadata->xmlKeyAttribute = $annot->keyAttribute;
206 147
                    } elseif ($annot instanceof XmlKeyValuePairs) {
207 7
                        $propertyMetadata->xmlKeyValuePairs = true;
208 139
                    } elseif ($annot instanceof XmlAttribute) {
209 41
                        $propertyMetadata->xmlAttribute = true;
210 41
                        $propertyMetadata->xmlNamespace = $annot->namespace;
211 132
                    } elseif ($annot instanceof XmlValue) {
212 26
                        $propertyMetadata->xmlValue = true;
213 26
                        $propertyMetadata->xmlElementCData = $annot->cdata;
214 126
                    } elseif ($annot instanceof XmlElement) {
215
                        $propertyMetadata->xmlElementCData = $annot->cdata;
216 106
                    } elseif ($annot instanceof AccessType) {
217 3
                        $accessType = $annot->type;
218 106
                    } elseif ($annot instanceof ReadOnly) {
219 10
                        $propertyMetadata->readOnly = $annot->readOnly;
220 106
                    } elseif ($annot instanceof Accessor) {
221 11
                        $accessor = array($annot->getter, $annot->setter);
222 103
                    } elseif ($annot instanceof Groups) {
223 42
                        $propertyMetadata->groups = $annot->groups;
224 42
                        foreach ((array)$propertyMetadata->groups as $groupName) {
225 42
                            if (false !== strpos($groupName, ',')) {
226 3
                                throw new InvalidArgumentException(sprintf(
227 3
                                    'Invalid group name "%s" on "%s", did you mean to create multiple groups?',
228 3
                                    implode(', ', $propertyMetadata->groups),
229 3
                                    $propertyMetadata->class . '->' . $propertyMetadata->name
230 3
                                ));
231
                            }
232 39
                        }
233 89
                    } elseif ($annot instanceof Inline) {
234 7
                        $propertyMetadata->inline = true;
235 67
                    } elseif ($annot instanceof XmlAttributeMap) {
236 4
                        $propertyMetadata->xmlAttributeMap = true;
237 60
                    } elseif ($annot instanceof MaxDepth) {
238 9
                        $propertyMetadata->maxDepth = $annot->depth;
239 9
                    }
240 247
                }
241
242
243 247
                if ((ExclusionPolicy::NONE === $exclusionPolicy && !$isExclude)
244 39
                    || (ExclusionPolicy::ALL === $exclusionPolicy && $isExpose)
245 247
                ) {
246 247
                    $propertyMetadata->setAccessor($accessType, $accessor[0], $accessor[1]);
247 247
                    $classMetadata->addPropertyMetadata($propertyMetadata);
248 247
                }
249 260
            }
250 260
        }
251
252 260
        return $classMetadata;
253
    }
254
}
255