Completed
Push — master ( 48b0b5...26ecbc )
by Andreas
16:25 queued 10s
created

ODM/MongoDB/Mapping/Driver/AnnotationDriver.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Annotations\AbstractIndex;
13
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
14
use Doctrine\ODM\MongoDB\Mapping\MappingException;
15
use ReflectionClass;
16
use ReflectionMethod;
17
use const E_USER_DEPRECATED;
18
use function array_merge;
19
use function array_replace;
20
use function constant;
21
use function get_class;
22
use function is_array;
23
use function trigger_error;
24
25
/**
26
 * The AnnotationDriver reads the mapping metadata from docblock annotations.
27
 */
28
class AnnotationDriver extends AbstractAnnotationDriver
29
{
30 918
    public function isTransient($className)
31
    {
32 918
        $classAnnotations = $this->reader->getClassAnnotations(new ReflectionClass($className));
33
34 918
        foreach ($classAnnotations as $annot) {
35 917
            if ($annot instanceof ODM\AbstractDocument) {
36 917
                return false;
37
            }
38
        }
39 69
        return true;
40
    }
41
42
    /**
43
     * {@inheritdoc}
44
     */
45 1448
    public function loadMetadataForClass($className, \Doctrine\Common\Persistence\Mapping\ClassMetadata $class) : void
46
    {
47
        /** @var ClassMetadata $class */
48 1448
        $reflClass = $class->getReflectionClass();
49
50 1448
        $classAnnotations = $this->reader->getClassAnnotations($reflClass);
51
52 1448
        $documentAnnot = null;
53 1448
        foreach ($classAnnotations as $annot) {
54 1446
            $classAnnotations[get_class($annot)] = $annot;
55
56 1446
            if ($annot instanceof ODM\AbstractDocument) {
57 1446
                if ($documentAnnot !== null) {
58 5
                    throw MappingException::classCanOnlyBeMappedByOneAbstractDocument($className, $documentAnnot, $annot);
59
                }
60 1446
                $documentAnnot = $annot;
61
            }
62
63
            // non-document class annotations
64 1446
            if ($annot instanceof ODM\AbstractIndex) {
65 6
                $this->addIndex($class, $annot);
66
            }
67 1446
            if ($annot instanceof ODM\Indexes) {
68 94
                foreach (is_array($annot->value) ? $annot->value : [$annot->value] as $index) {
69 94
                    $this->addIndex($class, $index);
70
                }
71 1446
            } elseif ($annot instanceof ODM\InheritanceType) {
72 859
                $class->setInheritanceType(constant(ClassMetadata::class . '::INHERITANCE_TYPE_' . $annot->value));
73 1446
            } elseif ($annot instanceof ODM\DiscriminatorField) {
74 132
                $class->setDiscriminatorField($annot->value);
75 1446
            } elseif ($annot instanceof ODM\DiscriminatorMap) {
76 131
                $class->setDiscriminatorMap($annot->value);
77 1446
            } elseif ($annot instanceof ODM\DiscriminatorValue) {
78
                $class->setDiscriminatorValue($annot->value);
79 1446
            } elseif ($annot instanceof ODM\ChangeTrackingPolicy) {
80 66
                $class->setChangeTrackingPolicy(constant(ClassMetadata::class . '::CHANGETRACKING_' . $annot->value));
81 1446
            } elseif ($annot instanceof ODM\DefaultDiscriminatorValue) {
82 68
                $class->setDefaultDiscriminatorValue($annot->value);
83 1446
            } elseif ($annot instanceof ODM\ReadPreference) {
84 1446
                $class->setReadPreference($annot->value, $annot->tags);
85
            }
86
        }
87
88 1443
        if ($documentAnnot === null) {
89 3
            throw MappingException::classIsNotAValidDocument($className);
90
        }
91
92 1441
        if ($documentAnnot instanceof ODM\MappedSuperclass) {
93 849
            $class->isMappedSuperclass = true;
94 1440
        } elseif ($documentAnnot instanceof ODM\EmbeddedDocument) {
95 287
            $class->isEmbeddedDocument = true;
96 1433
        } elseif ($documentAnnot instanceof ODM\QueryResultDocument) {
97 67
            $class->isQueryResultDocument = true;
98 1433
        } elseif ($documentAnnot instanceof ODM\File) {
99 79
            $class->isFile = true;
100
101 79
            if ($documentAnnot->chunkSizeBytes !== null) {
102 78
                $class->setChunkSizeBytes($documentAnnot->chunkSizeBytes);
103
            }
104
        }
105
106 1441
        if (isset($documentAnnot->db)) {
107 1
            $class->setDatabase($documentAnnot->db);
108
        }
109 1441
        if (isset($documentAnnot->collection)) {
110 911
            $class->setCollection($documentAnnot->collection);
111
        }
112
        // Store bucketName as collection name for GridFS files
113 1441
        if (isset($documentAnnot->bucketName)) {
114 1
            $class->setBucketName($documentAnnot->bucketName);
115
        }
116 1441
        if (isset($documentAnnot->repositoryClass)) {
117 77
            $class->setCustomRepositoryClass($documentAnnot->repositoryClass);
118
        }
119 1441
        if (isset($documentAnnot->writeConcern)) {
120 10
            $class->setWriteConcern($documentAnnot->writeConcern);
121
        }
122 1441
        if (isset($documentAnnot->indexes)) {
123 1440
            foreach ($documentAnnot->indexes as $index) {
124
                $this->addIndex($class, $index);
125
            }
126
        }
127 1441
        if (! empty($documentAnnot->readOnly)) {
128 5
            $class->markReadOnly();
129
        }
130
131 1441
        foreach ($reflClass->getProperties() as $property) {
132 1440
            if (($class->isMappedSuperclass && ! $property->isPrivate())
133
                ||
134 1440
                ($class->isInheritedField($property->name) && $property->getDeclaringClass()->name !== $class->name)) {
135 891
                continue;
136
            }
137
138 1439
            $indexes    = [];
139 1439
            $mapping    = ['fieldName' => $property->getName()];
140 1439
            $fieldAnnot = null;
141
142 1439
            foreach ($this->reader->getPropertyAnnotations($property) as $annot) {
143 1439
                if ($annot instanceof ODM\AbstractField) {
144 1439
                    $fieldAnnot = $annot;
145 1439
                    if ($annot->isDeprecated()) {
146
                        @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...
147
                    }
148
                }
149 1439
                if ($annot instanceof ODM\AbstractIndex) {
150 182
                    $indexes[] = $annot;
151
                }
152 1439
                if ($annot instanceof ODM\Indexes) {
153
                    foreach (is_array($annot->value) ? $annot->value : [$annot->value] as $index) {
154
                        $indexes[] = $index;
155
                    }
156 1439
                } elseif ($annot instanceof ODM\AlsoLoad) {
157 15
                    $mapping['alsoLoadFields'] = (array) $annot->value;
158 1439
                } elseif ($annot instanceof ODM\Version) {
159 108
                    $mapping['version'] = true;
160 1439
                } elseif ($annot instanceof ODM\Lock) {
161 1439
                    $mapping['lock'] = true;
162
                }
163
            }
164
165 1439
            if ($fieldAnnot) {
166 1439
                $mapping = array_replace($mapping, (array) $fieldAnnot);
167 1439
                $class->mapField($mapping);
168
            }
169
170 1439
            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...
171 1439
                continue;
172
            }
173
174 182
            foreach ($indexes as $index) {
175 182
                $name = $mapping['name'] ?? $mapping['fieldName'];
176 182
                $keys = [$name => $index->order ?: 'asc'];
177 182
                $this->addIndex($class, $index, $keys);
178
            }
179
        }
180
181
        // Set shard key after all fields to ensure we mapped all its keys
182 1438
        if (isset($classAnnotations['Doctrine\ODM\MongoDB\Mapping\Annotations\ShardKey'])) {
183 88
            $this->setShardKey($class, $classAnnotations['Doctrine\ODM\MongoDB\Mapping\Annotations\ShardKey']);
184
        }
185
186
        /** @var ReflectionMethod $method */
187 1437
        foreach ($reflClass->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
188
            /* Filter for the declaring class only. Callbacks from parent
189
             * classes will already be registered.
190
             */
191 1185
            if ($method->getDeclaringClass()->name !== $reflClass->name) {
192 856
                continue;
193
            }
194
195 1185
            foreach ($this->reader->getMethodAnnotations($method) as $annot) {
196 850
                if ($annot instanceof ODM\AlsoLoad) {
197 13
                    $class->registerAlsoLoadMethod($method->getName(), $annot->value);
198
                }
199
200 850
                if (! isset($classAnnotations[ODM\HasLifecycleCallbacks::class])) {
201 84
                    continue;
202
                }
203
204 831
                if ($annot instanceof ODM\PrePersist) {
205 812
                    $class->addLifecycleCallback($method->getName(), Events::prePersist);
206 95
                } elseif ($annot instanceof ODM\PostPersist) {
207 10
                    $class->addLifecycleCallback($method->getName(), Events::postPersist);
208 95
                } elseif ($annot instanceof ODM\PreUpdate) {
209 15
                    $class->addLifecycleCallback($method->getName(), Events::preUpdate);
210 90
                } elseif ($annot instanceof ODM\PostUpdate) {
211 79
                    $class->addLifecycleCallback($method->getName(), Events::postUpdate);
212 84
                } elseif ($annot instanceof ODM\PreRemove) {
213 82
                    $class->addLifecycleCallback($method->getName(), Events::preRemove);
214 84
                } elseif ($annot instanceof ODM\PostRemove) {
215 82
                    $class->addLifecycleCallback($method->getName(), Events::postRemove);
216 84
                } elseif ($annot instanceof ODM\PreLoad) {
217 83
                    $class->addLifecycleCallback($method->getName(), Events::preLoad);
218 83
                } elseif ($annot instanceof ODM\PostLoad) {
219 82
                    $class->addLifecycleCallback($method->getName(), Events::postLoad);
220 11
                } elseif ($annot instanceof ODM\PreFlush) {
221 1185
                    $class->addLifecycleCallback($method->getName(), Events::preFlush);
222
                }
223
            }
224
        }
225 1437
    }
226
227 214
    private function addIndex(ClassMetadata $class, AbstractIndex $index, array $keys = []) : void
228
    {
229 214
        $keys    = array_merge($keys, $index->keys);
230 214
        $options = [];
231 214
        $allowed = ['name', 'dropDups', 'background', 'unique', 'sparse', 'expireAfterSeconds'];
232 214
        foreach ($allowed as $name) {
233 214
            if (! isset($index->$name)) {
234 214
                continue;
235
            }
236
237 214
            $options[$name] = $index->$name;
238
        }
239 214
        if (! empty($index->partialFilterExpression)) {
240 2
            $options['partialFilterExpression'] = $index->partialFilterExpression;
241
        }
242 214
        $options = array_merge($options, $index->options);
243 214
        $class->addIndex($keys, $options);
244 214
    }
245
246
    /**
247
     * @throws MappingException
248
     */
249 88
    private function setShardKey(ClassMetadata $class, ODM\ShardKey $shardKey) : void
250
    {
251 88
        $options = [];
252 88
        $allowed = ['unique', 'numInitialChunks'];
253 88
        foreach ($allowed as $name) {
254 88
            if (! isset($shardKey->$name)) {
255 88
                continue;
256
            }
257
258
            $options[$name] = $shardKey->$name;
259
        }
260
261 88
        $class->setShardKey($shardKey->keys, $options);
262 87
    }
263
264
    /**
265
     * Factory method for the Annotation Driver
266
     *
267
     * @param array|string $paths
268
     */
269 1711
    public static function create($paths = [], ?Reader $reader = null) : AnnotationDriver
270
    {
271 1711
        if ($reader === null) {
272 1711
            $reader = new AnnotationReader();
273
        }
274 1711
        return new self($reader, $paths);
275
    }
276
}
277