Completed
Pull Request — master (#1906)
by Maciej
16:51
created

AnnotationDriver::isTransient()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 11
ccs 6
cts 6
cp 1
rs 9.9
c 0
b 0
f 0
cc 3
nc 3
nop 1
crap 3
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 1439
    public function loadMetadataForClass($className, \Doctrine\Common\Persistence\Mapping\ClassMetadata $class) : void
46
    {
47
        /** @var ClassMetadata $class */
48 1439
        $reflClass = $class->getReflectionClass();
49
50 1439
        $classAnnotations = $this->reader->getClassAnnotations($reflClass);
51
52 1439
        $documentAnnot = null;
53 1439
        foreach ($classAnnotations as $annot) {
54 1437
            $classAnnotations[get_class($annot)] = $annot;
55
56 1437
            if ($annot instanceof ODM\AbstractDocument) {
57 1437
                if ($documentAnnot !== null) {
58 5
                    throw MappingException::classCanOnlyBeMappedByOneAbstractDocument($className, $documentAnnot, $annot);
59
                }
60 1437
                $documentAnnot = $annot;
61
            }
62
63
            // non-document class annotations
64 1437
            if ($annot instanceof ODM\AbstractIndex) {
65 6
                $this->addIndex($class, $annot);
66
            }
67 1437
            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 1437
            } elseif ($annot instanceof ODM\InheritanceType) {
72 859
                $class->setInheritanceType(constant(ClassMetadata::class . '::INHERITANCE_TYPE_' . $annot->value));
73 1437
            } elseif ($annot instanceof ODM\DiscriminatorField) {
74 132
                $class->setDiscriminatorField($annot->value);
75 1437
            } elseif ($annot instanceof ODM\DiscriminatorMap) {
76 131
                $class->setDiscriminatorMap($annot->value);
77 1437
            } elseif ($annot instanceof ODM\DiscriminatorValue) {
78
                $class->setDiscriminatorValue($annot->value);
79 1437
            } elseif ($annot instanceof ODM\ChangeTrackingPolicy) {
80 66
                $class->setChangeTrackingPolicy(constant(ClassMetadata::class . '::CHANGETRACKING_' . $annot->value));
81 1437
            } elseif ($annot instanceof ODM\DefaultDiscriminatorValue) {
82 68
                $class->setDefaultDiscriminatorValue($annot->value);
83 1437
            } elseif ($annot instanceof ODM\ReadPreference) {
84 1437
                $class->setReadPreference($annot->value, $annot->tags);
85
            }
86
        }
87
88 1434
        if ($documentAnnot === null) {
89 3
            throw MappingException::classIsNotAValidDocument($className);
90
        }
91
92 1432
        if ($documentAnnot instanceof ODM\MappedSuperclass) {
93 849
            $class->isMappedSuperclass = true;
94 1431
        } elseif ($documentAnnot instanceof ODM\EmbeddedDocument) {
95 280
            $class->isEmbeddedDocument = true;
96 1424
        } elseif ($documentAnnot instanceof ODM\QueryResultDocument) {
97 67
            $class->isQueryResultDocument = true;
98 1424
        } 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 1432
        if (isset($documentAnnot->db)) {
107 1
            $class->setDatabase($documentAnnot->db);
108
        }
109 1432
        if (isset($documentAnnot->collection)) {
110 904
            $class->setCollection($documentAnnot->collection);
111
        }
112
        // Store bucketName as collection name for GridFS files
113 1432
        if (isset($documentAnnot->bucketName)) {
114 1
            $class->setBucketName($documentAnnot->bucketName);
115
        }
116 1432
        if (isset($documentAnnot->repositoryClass)) {
117 77
            $class->setCustomRepositoryClass($documentAnnot->repositoryClass);
118
        }
119 1432
        if (isset($documentAnnot->writeConcern)) {
120 10
            $class->setWriteConcern($documentAnnot->writeConcern);
121
        }
122 1432
        if (isset($documentAnnot->indexes)) {
123 1431
            foreach ($documentAnnot->indexes as $index) {
124
                $this->addIndex($class, $index);
125
            }
126
        }
127 1432
        if (! empty($documentAnnot->readOnly)) {
128 5
            $class->markReadOnly();
129
        }
130
131 1432
        foreach ($reflClass->getProperties() as $property) {
132 1431
            if (($class->isMappedSuperclass && ! $property->isPrivate())
133
                ||
134 1431
                ($class->isInheritedField($property->name) && $property->getDeclaringClass()->name !== $class->name)) {
135 891
                continue;
136
            }
137
138 1430
            $indexes    = [];
139 1430
            $mapping    = ['fieldName' => $property->getName()];
140 1430
            $fieldAnnot = null;
141
142 1430
            foreach ($this->reader->getPropertyAnnotations($property) as $annot) {
143 1430
                if ($annot instanceof ODM\AbstractField) {
144 1430
                    $fieldAnnot = $annot;
145 1430
                    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 1430
                if ($annot instanceof ODM\AbstractIndex) {
150 182
                    $indexes[] = $annot;
151
                }
152 1430
                if ($annot instanceof ODM\Indexes) {
153
                    foreach (is_array($annot->value) ? $annot->value : [$annot->value] as $index) {
154
                        $indexes[] = $index;
155
                    }
156 1430
                } elseif ($annot instanceof ODM\AlsoLoad) {
157 15
                    $mapping['alsoLoadFields'] = (array) $annot->value;
158 1430
                } elseif ($annot instanceof ODM\Version) {
159 108
                    $mapping['version'] = true;
160 1430
                } elseif ($annot instanceof ODM\Lock) {
161 1430
                    $mapping['lock'] = true;
162
                }
163
            }
164
165 1430
            if ($fieldAnnot) {
166 1430
                $mapping = array_replace($mapping, (array) $fieldAnnot);
167 1430
                $class->mapField($mapping);
168
            }
169
170 1430
            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 1430
                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 1430
        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 1429
        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 1178
            if ($method->getDeclaringClass()->name !== $reflClass->name) {
192 856
                continue;
193
            }
194
195 1178
            foreach ($this->reader->getMethodAnnotations($method) as $annot) {
196 850
                if ($annot instanceof ODM\AlsoLoad) {
197 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...
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);
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 95
                } elseif ($annot instanceof ODM\PostPersist) {
207 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...
208 95
                } elseif ($annot instanceof ODM\PreUpdate) {
209 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...
210 90
                } elseif ($annot instanceof ODM\PostUpdate) {
211 79
                    $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...
212 84
                } elseif ($annot instanceof ODM\PreRemove) {
213 82
                    $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...
214 84
                } elseif ($annot instanceof ODM\PostRemove) {
215 82
                    $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...
216 84
                } elseif ($annot instanceof ODM\PreLoad) {
217 83
                    $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...
218 83
                } elseif ($annot instanceof ODM\PostLoad) {
219 82
                    $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...
220 11
                } elseif ($annot instanceof ODM\PreFlush) {
221 1178
                    $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...
222
                }
223
            }
224
        }
225 1429
    }
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 1701
    public static function create($paths = [], ?Reader $reader = null) : AnnotationDriver
270
    {
271 1701
        if ($reader === null) {
272 1701
            $reader = new AnnotationReader();
273
        }
274 1701
        return new self($reader, $paths);
275
    }
276
}
277