Completed
Push — master ( 87aba0...0e8729 )
by Andreas
25s queued 16s
created

ODM/MongoDB/Mapping/Driver/AnnotationDriver.php (1 issue)

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
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ODM\MongoDB\Mapping\Driver;
21
22
use Doctrine\Common\Annotations\AnnotationReader;
23
use Doctrine\Common\Annotations\AnnotationRegistry;
24
use Doctrine\Common\Annotations\Reader;
25
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
26
use Doctrine\Common\Persistence\Mapping\Driver\AnnotationDriver as AbstractAnnotationDriver;
27
use Doctrine\ODM\MongoDB\Events;
28
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
29
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata as MappingClassMetadata;
30
use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo;
31
use Doctrine\ODM\MongoDB\Mapping\MappingException;
32
33
/**
34
 * The AnnotationDriver reads the mapping metadata from docblock annotations.
35
 *
36
 * @since       1.0
37
 */
38
class AnnotationDriver extends AbstractAnnotationDriver
39
{
40
    protected $entityAnnotationClasses = array(
41
        ODM\Document::class            => 1,
42
        ODM\MappedSuperclass::class    => 2,
43
        ODM\EmbeddedDocument::class    => 3,
44
        ODM\QueryResultDocument::class => 4,
45
    );
46
47
    /**
48
     * Registers annotation classes to the common registry.
49
     *
50
     * This method should be called when bootstrapping your application.
51
     */
52
    public static function registerAnnotationClasses()
53
    {
54
        AnnotationRegistry::registerFile(__DIR__ . '/../Annotations/DoctrineAnnotations.php');
55
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60 903
    public function loadMetadataForClass($className, ClassMetadata $class)
61
    {
62
        /** @var $class ClassMetadataInfo */
63 903
        $reflClass = $class->getReflectionClass();
64
65 903
        $classAnnotations = $this->reader->getClassAnnotations($reflClass);
66
67 903
        $documentAnnots = array();
68 903
        foreach ($classAnnotations as $annot) {
69 901
            $classAnnotations[get_class($annot)] = $annot;
70
71 901
            foreach ($this->entityAnnotationClasses as $annotClass => $i) {
72 901
                if ($annot instanceof $annotClass) {
73 901
                    $documentAnnots[$i] = $annot;
74 901
                    continue 2;
75
                }
76
            }
77
78
            // non-document class annotations
79 396
            if ($annot instanceof ODM\AbstractIndex) {
80 13
                $this->addIndex($class, $annot);
81
            }
82 396
            if ($annot instanceof ODM\Indexes) {
83 65
                foreach (is_array($annot->value) ? $annot->value : array($annot->value) as $index) {
84 65
                    $this->addIndex($class, $index);
85
                }
86 385
            } elseif ($annot instanceof ODM\InheritanceType) {
87 313
                $class->setInheritanceType(constant(MappingClassMetadata::class . '::INHERITANCE_TYPE_'.$annot->value));
88 383
            } elseif ($annot instanceof ODM\DiscriminatorField) {
89
                // $fieldName property is deprecated, but fall back for BC
90 121
                if (isset($annot->value)) {
91 121
                    $class->setDiscriminatorField($annot->value);
92
                } elseif (isset($annot->name)) {
0 ignored issues
show
Deprecated Code introduced by
The property Doctrine\ODM\MongoDB\Map...scriminatorField::$name has been deprecated with message: property was deprecated in 1.2 and will be removed in 2.0

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
93
                    $class->setDiscriminatorField($annot->name);
94
                } elseif (isset($annot->fieldName)) {
95 121
                    $class->setDiscriminatorField($annot->fieldName);
96
                }
97 382
            } elseif ($annot instanceof ODM\DiscriminatorMap) {
98 121
                $class->setDiscriminatorMap($annot->value);
99 320
            } elseif ($annot instanceof ODM\DiscriminatorValue) {
100
                $class->setDiscriminatorValue($annot->value);
101 320
            } elseif ($annot instanceof ODM\ChangeTrackingPolicy) {
102 57
                $class->setChangeTrackingPolicy(constant(MappingClassMetadata::class . '::CHANGETRACKING_'.$annot->value));
103 317
            } elseif ($annot instanceof ODM\DefaultDiscriminatorValue) {
104 396
                $class->setDefaultDiscriminatorValue($annot->value);
105
            }
106
107
        }
108
109 903
        if ( ! $documentAnnots) {
110 3
            throw MappingException::classIsNotAValidDocument($className);
111
        }
112
113
        // find the winning document annotation
114 901
        ksort($documentAnnots);
115 901
        $documentAnnot = reset($documentAnnots);
116
117 901
        if ($documentAnnot instanceof ODM\MappedSuperclass) {
118 302
            $class->isMappedSuperclass = true;
119 900
        } elseif ($documentAnnot instanceof ODM\EmbeddedDocument) {
120 298
            $class->isEmbeddedDocument = true;
121 893
        } elseif ($documentAnnot instanceof ODM\QueryResultDocument) {
122 52
            $class->isQueryResultDocument = true;
123
        }
124 901
        if (isset($documentAnnot->db)) {
125 1
            $class->setDatabase($documentAnnot->db);
126
        }
127 901
        if (isset($documentAnnot->collection)) {
128 351
            $class->setCollection($documentAnnot->collection);
129
        }
130 901
        if (isset($documentAnnot->repositoryClass)) {
131 69
            $class->setCustomRepositoryClass($documentAnnot->repositoryClass);
132
        }
133 901
        if (isset($documentAnnot->writeConcern)) {
134 11
            $class->setWriteConcern($documentAnnot->writeConcern);
135
        }
136 901
        if (isset($documentAnnot->indexes)) {
137 900
            foreach ($documentAnnot->indexes as $index) {
138
                $this->addIndex($class, $index);
139
            }
140
        }
141 901
        if (isset($documentAnnot->requireIndexes)) {
142 893
            $class->setRequireIndexes($documentAnnot->requireIndexes);
143
        }
144 901
        if (isset($documentAnnot->slaveOkay)) {
145 1
            $class->setSlaveOkay($documentAnnot->slaveOkay);
146
        }
147
148 901
        foreach ($reflClass->getProperties() as $property) {
149 900
            if (($class->isMappedSuperclass && ! $property->isPrivate())
150
                ||
151 900
                ($class->isInheritedField($property->name) && $property->getDeclaringClass()->name !== $class->name)) {
152 347
                continue;
153
            }
154
155 899
            $indexes = array();
156 899
            $mapping = array('fieldName' => $property->getName());
157 899
            $fieldAnnot = null;
158
159 899
            foreach ($this->reader->getPropertyAnnotations($property) as $annot) {
160 899
                if ($annot instanceof ODM\AbstractField) {
161 899
                    $fieldAnnot = $annot;
162
                }
163 899
                if ($annot instanceof ODM\AbstractIndex) {
164 198
                    $indexes[] = $annot;
165
                }
166 899
                if ($annot instanceof ODM\Indexes) {
167
                    foreach (is_array($annot->value) ? $annot->value : array($annot->value) as $index) {
168
                        $indexes[] = $index;
169
                    }
170 899
                } elseif ($annot instanceof ODM\AlsoLoad) {
171 15
                    $mapping['alsoLoadFields'] = (array) $annot->value;
172 899
                } elseif ($annot instanceof ODM\Version) {
173 97
                    $mapping['version'] = true;
174 899
                } elseif ($annot instanceof ODM\Lock) {
175 899
                    $mapping['lock'] = true;
176
                }
177
            }
178
179 899
            if ($fieldAnnot) {
180 899
                $mapping = array_replace($mapping, (array) $fieldAnnot);
181 899
                $class->mapField($mapping);
182
            }
183
184 899
            if ($indexes) {
185 198
                foreach ($indexes as $index) {
186 198
                    $name = isset($mapping['name']) ? $mapping['name'] : $mapping['fieldName'];
187 198
                    $keys = array($name => $index->order ?: 'asc');
188 899
                    $this->addIndex($class, $index, $keys);
189
                }
190
            }
191
        }
192
193
        // Set shard key after all fields to ensure we mapped all its keys
194 899
        if (isset($classAnnotations['Doctrine\ODM\MongoDB\Mapping\Annotations\ShardKey'])) {
195 62
            $this->setShardKey($class, $classAnnotations['Doctrine\ODM\MongoDB\Mapping\Annotations\ShardKey']);
196
        }
197
198
        /** @var $method \ReflectionMethod */
199 898
        foreach ($reflClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
200
            /* Filter for the declaring class only. Callbacks from parent
201
             * classes will already be registered.
202
             */
203 634
            if ($method->getDeclaringClass()->name !== $reflClass->name) {
204 314
                continue;
205
            }
206
207 634
            foreach ($this->reader->getMethodAnnotations($method) as $annot) {
208 307
                if ($annot instanceof ODM\AlsoLoad) {
209 13
                    $class->registerAlsoLoadMethod($method->getName(), $annot->value);
210
                }
211
212 307
                if ( ! isset($classAnnotations[ODM\HasLifecycleCallbacks::class])) {
213 72
                    continue;
214
                }
215
216 288
                if ($annot instanceof ODM\PrePersist) {
217 267
                    $class->addLifecycleCallback($method->getName(), Events::prePersist);
218 86
                } elseif ($annot instanceof ODM\PostPersist) {
219 11
                    $class->addLifecycleCallback($method->getName(), Events::postPersist);
220 85
                } elseif ($annot instanceof ODM\PreUpdate) {
221 15
                    $class->addLifecycleCallback($method->getName(), Events::preUpdate);
222 80
                } elseif ($annot instanceof ODM\PostUpdate) {
223 67
                    $class->addLifecycleCallback($method->getName(), Events::postUpdate);
224 74
                } elseif ($annot instanceof ODM\PreRemove) {
225 72
                    $class->addLifecycleCallback($method->getName(), Events::preRemove);
226 74
                } elseif ($annot instanceof ODM\PostRemove) {
227 70
                    $class->addLifecycleCallback($method->getName(), Events::postRemove);
228 74
                } elseif ($annot instanceof ODM\PreLoad) {
229 71
                    $class->addLifecycleCallback($method->getName(), Events::preLoad);
230 73
                } elseif ($annot instanceof ODM\PostLoad) {
231 72
                    $class->addLifecycleCallback($method->getName(), Events::postLoad);
232 11
                } elseif ($annot instanceof ODM\PreFlush) {
233 634
                    $class->addLifecycleCallback($method->getName(), Events::preFlush);
234
                }
235
            }
236
        }
237 898
    }
238
239 222
    private function addIndex(ClassMetadataInfo $class, $index, array $keys = array())
240
    {
241 222
        $keys = array_merge($keys, $index->keys);
242 222
        $options = array();
243 222
        $allowed = array('name', 'dropDups', 'background', 'safe', 'unique', 'sparse', 'expireAfterSeconds');
244 222
        foreach ($allowed as $name) {
245 222
            if (isset($index->$name)) {
246 222
                $options[$name] = $index->$name;
247
            }
248
        }
249 222
        if (! empty($index->partialFilterExpression)) {
250 3
            $options['partialFilterExpression'] = $index->partialFilterExpression;
251
        }
252 222
        $options = array_merge($options, $index->options);
253 222
        $class->addIndex($keys, $options);
254 222
    }
255
256
    /**
257
     * @param ClassMetadataInfo $class
258
     * @param ODM\ShardKey      $shardKey
259
     *
260
     * @throws MappingException
261
     */
262 62
    private function setShardKey(ClassMetadataInfo $class, ODM\ShardKey $shardKey)
263
    {
264 62
        $options = array();
265 62
        $allowed = array('unique', 'numInitialChunks');
266 62
        foreach ($allowed as $name) {
267 62
            if (isset($shardKey->$name)) {
268 62
                $options[$name] = $shardKey->$name;
269
            }
270
        }
271
272 62
        $class->setShardKey($shardKey->keys, $options);
273 61
    }
274
275
    /**
276
     * Factory method for the Annotation Driver
277
     *
278
     * @param array|string $paths
279
     * @param Reader $reader
280
     * @return AnnotationDriver
281
     */
282 1138
    public static function create($paths = array(), Reader $reader = null)
283
    {
284 1138
        if ($reader === null) {
285 1138
            $reader = new AnnotationReader();
286
        }
287 1138
        return new self($reader, $paths);
288
    }
289
}
290