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

AnnotationDriver   F

Complexity

Total Complexity 52

Size/Duplication

Total Lines 170
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 27

Test Coverage

Coverage 96.53%

Importance

Changes 9
Bugs 2 Features 3
Metric Value
wmc 52
c 9
b 2
f 3
lcom 1
cbo 27
dl 0
loc 170
ccs 139
cts 144
cp 0.9653
rs 2.2961

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
F loadMetadataForClass() 0 160 51

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