Completed
Push — master ( 6b2ea7...c30cd0 )
by Asmir
06:14 queued 03:19
created

AnnotationDriver::__construct()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 1
nop 3
dl 0
loc 5
ccs 4
cts 4
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
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 Doctrine\Common\Annotations\Reader;
24
use JMS\Serializer\Annotation\Accessor;
25
use JMS\Serializer\Annotation\AccessorOrder;
26
use JMS\Serializer\Annotation\AccessType;
27
use JMS\Serializer\Annotation\Discriminator;
28
use JMS\Serializer\Annotation\Exclude;
29
use JMS\Serializer\Annotation\ExcludeIf;
0 ignored issues
show
Bug introduced by
The type JMS\Serializer\Annotation\ExcludeIf was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

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