Completed
Pull Request — master (#1757)
by Maciej
15:59
created

AnnotationDriver::loadMetadataForClass()   F

Complexity

Conditions 60
Paths > 20000

Size

Total Lines 174
Code Lines 113

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 108
CRAP Score 60.3108

Importance

Changes 0
Metric Value
dl 0
loc 174
ccs 108
cts 113
cp 0.9558
rs 2
c 0
b 0
f 0
cc 60
eloc 113
nc 9676842
nop 2
crap 60.3108

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
declare(strict_types=1);
4
5
namespace Doctrine\ODM\MongoDB\Mapping\Driver;
6
7
use Doctrine\Common\Annotations\AnnotationReader;
8
use Doctrine\Common\Annotations\Reader;
9
use Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver;
10
use Doctrine\ODM\MongoDB\Events;
11
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
12
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
13
use Doctrine\ODM\MongoDB\Mapping\MappingException;
14
use const E_USER_DEPRECATED;
15
use function array_merge;
16
use function array_replace;
17
use function constant;
18
use function get_class;
19
use function is_array;
20
use function ksort;
21
use function reset;
22
use function trigger_error;
23
24
/**
25
 * The AnnotationDriver reads the mapping metadata from docblock annotations.
26
 *
27
 */
28
class AnnotationDriver extends AbstractAnnotationDriver
29
{
30
    protected $entityAnnotationClasses = [
31
        ODM\Document::class            => 1,
32
        ODM\MappedSuperclass::class    => 2,
33
        ODM\EmbeddedDocument::class    => 3,
34
        ODM\QueryResultDocument::class => 4,
35
    ];
36
37
    /**
38
     * {@inheritdoc}
39
     */
40 1365
    public function loadMetadataForClass($className, \Doctrine\Common\Persistence\Mapping\ClassMetadata $class)
41
    {
42
        /** @var ClassMetadata $class */
43 1365
        $reflClass = $class->getReflectionClass();
44
45 1365
        $classAnnotations = $this->reader->getClassAnnotations($reflClass);
46
47 1365
        $documentAnnots = [];
48 1365
        foreach ($classAnnotations as $annot) {
49 1363
            $classAnnotations[get_class($annot)] = $annot;
50
51 1363
            foreach ($this->entityAnnotationClasses as $annotClass => $i) {
52 1363
                if ($annot instanceof $annotClass) {
53 1363
                    $documentAnnots[$i] = $annot;
54 1363
                    continue 2;
55
                }
56
            }
57
58
            // non-document class annotations
59 909
            if ($annot instanceof ODM\AbstractIndex) {
60 6
                $this->addIndex($class, $annot);
61
            }
62 909
            if ($annot instanceof ODM\Indexes) {
63 61
                foreach (is_array($annot->value) ? $annot->value : [$annot->value] as $index) {
64 61
                    $this->addIndex($class, $index);
65
                }
66 894
            } elseif ($annot instanceof ODM\InheritanceType) {
67 833
                $class->setInheritanceType(constant(ClassMetadata::class . '::INHERITANCE_TYPE_' . $annot->value));
68 892
            } elseif ($annot instanceof ODM\DiscriminatorField) {
69 111
                $class->setDiscriminatorField($annot->value);
70 891
            } elseif ($annot instanceof ODM\DiscriminatorMap) {
71 111
                $class->setDiscriminatorMap($annot->value);
72 830
            } elseif ($annot instanceof ODM\DiscriminatorValue) {
73
                $class->setDiscriminatorValue($annot->value);
74 830
            } elseif ($annot instanceof ODM\ChangeTrackingPolicy) {
75 46
                $class->setChangeTrackingPolicy(constant(ClassMetadata::class . '::CHANGETRACKING_' . $annot->value));
76 828
            } elseif ($annot instanceof ODM\DefaultDiscriminatorValue) {
77 48
                $class->setDefaultDiscriminatorValue($annot->value);
78 823
            } elseif ($annot instanceof ODM\ReadPreference) {
79 909
                $class->setReadPreference($annot->value, $annot->tags);
80
            }
81
        }
82
83 1365
        if (! $documentAnnots) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $documentAnnots of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
84 3
            throw MappingException::classIsNotAValidDocument($className);
85
        }
86
87
        // find the winning document annotation
88 1363
        ksort($documentAnnots);
89 1363
        $documentAnnot = reset($documentAnnots);
90
91 1363
        if ($documentAnnot instanceof ODM\MappedSuperclass) {
92 822
            $class->isMappedSuperclass = true;
93 1362
        } elseif ($documentAnnot instanceof ODM\EmbeddedDocument) {
94 234
            $class->isEmbeddedDocument = true;
95 1355
        } elseif ($documentAnnot instanceof ODM\QueryResultDocument) {
96 47
            $class->isQueryResultDocument = true;
97
        }
98 1363
        if (isset($documentAnnot->db)) {
99 1
            $class->setDatabase($documentAnnot->db);
100
        }
101 1363
        if (isset($documentAnnot->collection)) {
102 868
            $class->setCollection($documentAnnot->collection);
103
        }
104 1363
        if (isset($documentAnnot->repositoryClass)) {
105 57
            $class->setCustomRepositoryClass($documentAnnot->repositoryClass);
106
        }
107 1363
        if (isset($documentAnnot->writeConcern)) {
108 10
            $class->setWriteConcern($documentAnnot->writeConcern);
109
        }
110 1363
        if (isset($documentAnnot->indexes)) {
111 1362
            foreach ($documentAnnot->indexes as $index) {
112
                $this->addIndex($class, $index);
113
            }
114
        }
115 1363
        if (! empty($documentAnnot->readOnly)) {
116 5
            $class->markReadOnly();
117
        }
118
119 1363
        foreach ($reflClass->getProperties() as $property) {
120 1362
            if (($class->isMappedSuperclass && ! $property->isPrivate())
121
                ||
122 1362
                ($class->isInheritedField($property->name) && $property->getDeclaringClass()->name !== $class->name)) {
123 864
                continue;
124
            }
125
126 1361
            $indexes = [];
127 1361
            $mapping = ['fieldName' => $property->getName()];
128 1361
            $fieldAnnot = null;
129
130 1361
            foreach ($this->reader->getPropertyAnnotations($property) as $annot) {
131 1361
                if ($annot instanceof ODM\AbstractField) {
132 1361
                    $fieldAnnot = $annot;
133 1361
                    if ($annot->isDeprecated()) {
134
                        @trigger_error($annot->getDeprecationMessage(), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
135
                    }
136
                }
137 1361
                if ($annot instanceof ODM\AbstractIndex) {
138 159
                    $indexes[] = $annot;
139
                }
140 1361
                if ($annot instanceof ODM\Indexes) {
141
                    foreach (is_array($annot->value) ? $annot->value : [$annot->value] as $index) {
142
                        $indexes[] = $index;
143
                    }
144 1361
                } elseif ($annot instanceof ODM\AlsoLoad) {
145 15
                    $mapping['alsoLoadFields'] = (array) $annot->value;
146 1361
                } elseif ($annot instanceof ODM\Version) {
147 67
                    $mapping['version'] = true;
148 1361
                } elseif ($annot instanceof ODM\Lock) {
149 1361
                    $mapping['lock'] = true;
150
                }
151
            }
152
153 1361
            if ($fieldAnnot) {
154 1361
                $mapping = array_replace($mapping, (array) $fieldAnnot);
155 1361
                $class->mapField($mapping);
156
            }
157
158 1361
            if (! $indexes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $indexes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
159 1361
                continue;
160
            }
161
162 159
            foreach ($indexes as $index) {
163 159
                $name = $mapping['name'] ?? $mapping['fieldName'];
164 159
                $keys = [$name => $index->order ?: 'asc'];
165 159
                $this->addIndex($class, $index, $keys);
166
            }
167
        }
168
169
        // Set shard key after all fields to ensure we mapped all its keys
170 1361
        if (isset($classAnnotations['Doctrine\ODM\MongoDB\Mapping\Annotations\ShardKey'])) {
171 59
            $this->setShardKey($class, $classAnnotations['Doctrine\ODM\MongoDB\Mapping\Annotations\ShardKey']);
172
        }
173
174
        /** @var \ReflectionMethod $method */
175 1360
        foreach ($reflClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
176
            /* Filter for the declaring class only. Callbacks from parent
177
             * classes will already be registered.
178
             */
179 1124
            if ($method->getDeclaringClass()->name !== $reflClass->name) {
180 830
                continue;
181
            }
182
183 1124
            foreach ($this->reader->getMethodAnnotations($method) as $annot) {
184 820
                if ($annot instanceof ODM\AlsoLoad) {
185 13
                    $class->registerAlsoLoadMethod($method->getName(), $annot->value);
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
186
                }
187
188 820
                if (! isset($classAnnotations[ODM\HasLifecycleCallbacks::class])) {
189 64
                    continue;
190
                }
191
192 801
                if ($annot instanceof ODM\PrePersist) {
193 786
                    $class->addLifecycleCallback($method->getName(), Events::prePersist);
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
194 71
                } elseif ($annot instanceof ODM\PostPersist) {
195 10
                    $class->addLifecycleCallback($method->getName(), Events::postPersist);
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
196 71
                } elseif ($annot instanceof ODM\PreUpdate) {
197 15
                    $class->addLifecycleCallback($method->getName(), Events::preUpdate);
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
198 66
                } elseif ($annot instanceof ODM\PostUpdate) {
199 55
                    $class->addLifecycleCallback($method->getName(), Events::postUpdate);
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
200 64
                } elseif ($annot instanceof ODM\PreRemove) {
201 62
                    $class->addLifecycleCallback($method->getName(), Events::preRemove);
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
202 64
                } elseif ($annot instanceof ODM\PostRemove) {
203 62
                    $class->addLifecycleCallback($method->getName(), Events::postRemove);
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
204 64
                } elseif ($annot instanceof ODM\PreLoad) {
205 63
                    $class->addLifecycleCallback($method->getName(), Events::preLoad);
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
206 63
                } elseif ($annot instanceof ODM\PostLoad) {
207 62
                    $class->addLifecycleCallback($method->getName(), Events::postLoad);
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
208 11
                } elseif ($annot instanceof ODM\PreFlush) {
209 1124
                    $class->addLifecycleCallback($method->getName(), Events::preFlush);
0 ignored issues
show
Bug introduced by
Consider using $method->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
210
                }
211
            }
212
        }
213 1360
    }
214
215 180
    private function addIndex(ClassMetadata $class, $index, array $keys = [])
216
    {
217 180
        $keys = array_merge($keys, $index->keys);
218 180
        $options = [];
219 180
        $allowed = ['name', 'dropDups', 'background', 'unique', 'sparse', 'expireAfterSeconds'];
220 180
        foreach ($allowed as $name) {
221 180
            if (! isset($index->$name)) {
222 180
                continue;
223
            }
224
225 180
            $options[$name] = $index->$name;
226
        }
227 180
        if (! empty($index->partialFilterExpression)) {
228 2
            $options['partialFilterExpression'] = $index->partialFilterExpression;
229
        }
230 180
        $options = array_merge($options, $index->options);
231 180
        $class->addIndex($keys, $options);
232 180
    }
233
234
    /**
235
     *
236
     * @throws MappingException
237
     */
238 59
    private function setShardKey(ClassMetadata $class, ODM\ShardKey $shardKey)
239
    {
240 59
        $options = [];
241 59
        $allowed = ['unique', 'numInitialChunks'];
242 59
        foreach ($allowed as $name) {
243 59
            if (! isset($shardKey->$name)) {
244 59
                continue;
245
            }
246
247
            $options[$name] = $shardKey->$name;
248
        }
249
250 59
        $class->setShardKey($shardKey->keys, $options);
251 58
    }
252
253
    /**
254
     * Factory method for the Annotation Driver
255
     *
256
     * @param array|string $paths
257
     * @return AnnotationDriver
258
     */
259 1618
    public static function create($paths = [], ?Reader $reader = null)
260
    {
261 1618
        if ($reader === null) {
262 1618
            $reader = new AnnotationReader();
263
        }
264 1618
        return new self($reader, $paths);
265
    }
266
}
267