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