66
77use Doctrine \Common \Annotations \AnnotationReader ;
88use Doctrine \Common \Annotations \Reader ;
9- use Doctrine \ODM \MongoDB \Events ;
10- use Doctrine \ODM \MongoDB \Mapping \Annotations as ODM ;
11- use Doctrine \ODM \MongoDB \Mapping \Annotations \AbstractIndex ;
12- use Doctrine \ODM \MongoDB \Mapping \Annotations \ShardKey ;
13- use Doctrine \ODM \MongoDB \Mapping \ClassMetadata ;
14- use Doctrine \ODM \MongoDB \Mapping \MappingException ;
15- use Doctrine \Persistence \Mapping \Driver \ColocatedMappingDriver ;
16- use Doctrine \Persistence \Mapping \Driver \MappingDriver ;
17- use MongoDB \Driver \Exception \UnexpectedValueException ;
18- use ReflectionClass ;
19- use ReflectionMethod ;
20-
21- use function array_merge ;
22- use function array_replace ;
23- use function assert ;
24- use function class_exists ;
25- use function constant ;
26- use function count ;
27- use function interface_exists ;
28- use function is_array ;
29- use function MongoDB \BSON \fromJSON ;
30- use function MongoDB \BSON \toPHP ;
31- use function trigger_deprecation ;
329
3310/**
3411 * The AnnotationDriver reads the mapping metadata from docblock annotations.
3512 */
36- class AnnotationDriver implements MappingDriver
13+ class AnnotationDriver extends AttributeDriver
3714{
38- use ColocatedMappingDriver;
39-
4015 /**
4116 * The annotation reader.
4217 *
@@ -60,323 +35,6 @@ public function __construct($reader, $paths = null)
6035 $ this ->addPaths ((array ) $ paths );
6136 }
6237
63- public function isTransient ($ className )
64- {
65- $ classAnnotations = $ this ->reader ->getClassAnnotations (new ReflectionClass ($ className ));
66-
67- foreach ($ classAnnotations as $ annot ) {
68- if ($ annot instanceof ODM \AbstractDocument) {
69- return false ;
70- }
71- }
72-
73- return true ;
74- }
75-
76- public function loadMetadataForClass ($ className , \Doctrine \Persistence \Mapping \ClassMetadata $ metadata ): void
77- {
78- assert ($ metadata instanceof ClassMetadata);
79- $ reflClass = $ metadata ->getReflectionClass ();
80-
81- $ classAnnotations = $ this ->reader ->getClassAnnotations ($ reflClass );
82-
83- $ documentAnnot = null ;
84- foreach ($ classAnnotations as $ annot ) {
85- $ classAnnotations [$ annot ::class] = $ annot ;
86-
87- if ($ annot instanceof ODM \AbstractDocument) {
88- if ($ documentAnnot !== null ) {
89- throw MappingException::classCanOnlyBeMappedByOneAbstractDocument ($ className , $ documentAnnot , $ annot );
90- }
91-
92- $ documentAnnot = $ annot ;
93- }
94-
95- // non-document class annotations
96- if ($ annot instanceof ODM \AbstractIndex) {
97- $ this ->addIndex ($ metadata , $ annot );
98- }
99-
100- if ($ annot instanceof ODM \Indexes) {
101- trigger_deprecation (
102- 'doctrine/mongodb-odm ' ,
103- '2.2 ' ,
104- 'The "@Indexes" annotation used in class "%s" is deprecated. Specify all "@Index" and "@UniqueIndex" annotations on the class. ' ,
105- $ className ,
106- );
107- $ value = $ annot ->value ;
108- foreach (is_array ($ value ) ? $ value : [$ value ] as $ index ) {
109- $ this ->addIndex ($ metadata , $ index );
110- }
111- } elseif ($ annot instanceof ODM \InheritanceType) {
112- $ metadata ->setInheritanceType (constant (ClassMetadata::class . '::INHERITANCE_TYPE_ ' . $ annot ->value ));
113- } elseif ($ annot instanceof ODM \DiscriminatorField) {
114- $ metadata ->setDiscriminatorField ($ annot ->value );
115- } elseif ($ annot instanceof ODM \DiscriminatorMap) {
116- $ value = $ annot ->value ;
117- assert (is_array ($ value ));
118- $ metadata ->setDiscriminatorMap ($ value );
119- } elseif ($ annot instanceof ODM \DiscriminatorValue) {
120- $ metadata ->setDiscriminatorValue ($ annot ->value );
121- } elseif ($ annot instanceof ODM \ChangeTrackingPolicy) {
122- $ metadata ->setChangeTrackingPolicy (constant (ClassMetadata::class . '::CHANGETRACKING_ ' . $ annot ->value ));
123- } elseif ($ annot instanceof ODM \DefaultDiscriminatorValue) {
124- $ metadata ->setDefaultDiscriminatorValue ($ annot ->value );
125- } elseif ($ annot instanceof ODM \ReadPreference) {
126- $ metadata ->setReadPreference ($ annot ->value , $ annot ->tags ?? []);
127- } elseif ($ annot instanceof ODM \Validation) {
128- if (isset ($ annot ->validator )) {
129- try {
130- $ validatorBson = fromJSON ($ annot ->validator );
131- } catch (UnexpectedValueException $ e ) {
132- throw MappingException::schemaValidationError ($ e ->getCode (), $ e ->getMessage (), $ className , 'validator ' );
133- }
134-
135- $ validator = toPHP ($ validatorBson , []);
136- $ metadata ->setValidator ($ validator );
137- }
138-
139- if (isset ($ annot ->action )) {
140- $ metadata ->setValidationAction ($ annot ->action );
141- }
142-
143- if (isset ($ annot ->level )) {
144- $ metadata ->setValidationLevel ($ annot ->level );
145- }
146- }
147- }
148-
149- if ($ documentAnnot === null ) {
150- throw MappingException::classIsNotAValidDocument ($ className );
151- }
152-
153- if ($ documentAnnot instanceof ODM \MappedSuperclass) {
154- $ metadata ->isMappedSuperclass = true ;
155- } elseif ($ documentAnnot instanceof ODM \EmbeddedDocument) {
156- $ metadata ->isEmbeddedDocument = true ;
157- } elseif ($ documentAnnot instanceof ODM \QueryResultDocument) {
158- $ metadata ->isQueryResultDocument = true ;
159- } elseif ($ documentAnnot instanceof ODM \View) {
160- if (! $ documentAnnot ->rootClass ) {
161- throw MappingException::viewWithoutRootClass ($ className );
162- }
163-
164- if (! class_exists ($ documentAnnot ->rootClass )) {
165- throw MappingException::viewRootClassNotFound ($ className , $ documentAnnot ->rootClass );
166- }
167-
168- $ metadata ->markViewOf ($ documentAnnot ->rootClass );
169- } elseif ($ documentAnnot instanceof ODM \File) {
170- $ metadata ->isFile = true ;
171-
172- if ($ documentAnnot ->chunkSizeBytes !== null ) {
173- $ metadata ->setChunkSizeBytes ($ documentAnnot ->chunkSizeBytes );
174- }
175- }
176-
177- if (isset ($ documentAnnot ->db )) {
178- $ metadata ->setDatabase ($ documentAnnot ->db );
179- }
180-
181- if (isset ($ documentAnnot ->collection )) {
182- $ metadata ->setCollection ($ documentAnnot ->collection );
183- }
184-
185- if (isset ($ documentAnnot ->view )) {
186- $ metadata ->setCollection ($ documentAnnot ->view );
187- }
188-
189- // Store bucketName as collection name for GridFS files
190- if (isset ($ documentAnnot ->bucketName )) {
191- $ metadata ->setBucketName ($ documentAnnot ->bucketName );
192- }
193-
194- if (isset ($ documentAnnot ->repositoryClass )) {
195- $ metadata ->setCustomRepositoryClass ($ documentAnnot ->repositoryClass );
196- }
197-
198- if (isset ($ documentAnnot ->writeConcern )) {
199- $ metadata ->setWriteConcern ($ documentAnnot ->writeConcern );
200- }
201-
202- if (isset ($ documentAnnot ->indexes ) && count ($ documentAnnot ->indexes )) {
203- trigger_deprecation (
204- 'doctrine/mongodb-odm ' ,
205- '2.2 ' ,
206- 'The "indexes" parameter in the "%s" annotation for class "%s" is deprecated. Specify all "@Index" and "@UniqueIndex" annotations on the class. ' ,
207- $ className ,
208- $ documentAnnot ::class,
209- );
210-
211- foreach ($ documentAnnot ->indexes as $ index ) {
212- $ this ->addIndex ($ metadata , $ index );
213- }
214- }
215-
216- if (! empty ($ documentAnnot ->readOnly )) {
217- $ metadata ->markReadOnly ();
218- }
219-
220- foreach ($ reflClass ->getProperties () as $ property ) {
221- if (
222- ($ metadata ->isMappedSuperclass && ! $ property ->isPrivate ())
223- ||
224- ($ metadata ->isInheritedField ($ property ->name ) && $ property ->getDeclaringClass ()->name !== $ metadata ->name )
225- ) {
226- continue ;
227- }
228-
229- $ indexes = [];
230- $ mapping = ['fieldName ' => $ property ->getName ()];
231- $ fieldAnnot = null ;
232-
233- foreach ($ this ->reader ->getPropertyAnnotations ($ property ) as $ annot ) {
234- if ($ annot instanceof ODM \AbstractField) {
235- $ fieldAnnot = $ annot ;
236- }
237-
238- if ($ annot instanceof ODM \AbstractIndex) {
239- $ indexes [] = $ annot ;
240- }
241-
242- if ($ annot instanceof ODM \Indexes) {
243- $ value = $ annot ->value ;
244- foreach (is_array ($ value ) ? $ value : [$ value ] as $ index ) {
245- $ indexes [] = $ index ;
246- }
247- } elseif ($ annot instanceof ODM \AlsoLoad) {
248- $ mapping ['alsoLoadFields ' ] = (array ) $ annot ->value ;
249- } elseif ($ annot instanceof ODM \Version) {
250- $ mapping ['version ' ] = true ;
251- } elseif ($ annot instanceof ODM \Lock) {
252- $ mapping ['lock ' ] = true ;
253- }
254- }
255-
256- if ($ fieldAnnot ) {
257- $ mapping = array_replace ($ mapping , (array ) $ fieldAnnot );
258- $ metadata ->mapField ($ mapping );
259- }
260-
261- if (! $ indexes ) {
262- continue ;
263- }
264-
265- foreach ($ indexes as $ index ) {
266- $ name = $ mapping ['name ' ] ?? $ mapping ['fieldName ' ];
267- $ keys = [$ name => $ index ->order ?: 'asc ' ];
268- $ this ->addIndex ($ metadata , $ index , $ keys );
269- }
270- }
271-
272- // Set shard key after all fields to ensure we mapped all its keys
273- if (isset ($ classAnnotations [ShardKey::class])) {
274- assert ($ classAnnotations [ShardKey::class] instanceof ShardKey);
275- $ this ->setShardKey ($ metadata , $ classAnnotations [ShardKey::class]);
276- }
277-
278- foreach ($ reflClass ->getMethods (ReflectionMethod::IS_PUBLIC ) as $ method ) {
279- /* Filter for the declaring class only. Callbacks from parent
280- * classes will already be registered.
281- */
282- if ($ method ->getDeclaringClass ()->name !== $ reflClass ->name ) {
283- continue ;
284- }
285-
286- foreach ($ this ->reader ->getMethodAnnotations ($ method ) as $ annot ) {
287- if ($ annot instanceof ODM \AlsoLoad) {
288- $ metadata ->registerAlsoLoadMethod ($ method ->getName (), $ annot ->value );
289- }
290-
291- if (! isset ($ classAnnotations [ODM \HasLifecycleCallbacks::class])) {
292- continue ;
293- }
294-
295- if ($ annot instanceof ODM \PrePersist) {
296- $ metadata ->addLifecycleCallback ($ method ->getName (), Events::prePersist);
297- } elseif ($ annot instanceof ODM \PostPersist) {
298- $ metadata ->addLifecycleCallback ($ method ->getName (), Events::postPersist);
299- } elseif ($ annot instanceof ODM \PreUpdate) {
300- $ metadata ->addLifecycleCallback ($ method ->getName (), Events::preUpdate);
301- } elseif ($ annot instanceof ODM \PostUpdate) {
302- $ metadata ->addLifecycleCallback ($ method ->getName (), Events::postUpdate);
303- } elseif ($ annot instanceof ODM \PreRemove) {
304- $ metadata ->addLifecycleCallback ($ method ->getName (), Events::preRemove);
305- } elseif ($ annot instanceof ODM \PostRemove) {
306- $ metadata ->addLifecycleCallback ($ method ->getName (), Events::postRemove);
307- } elseif ($ annot instanceof ODM \PreLoad) {
308- $ metadata ->addLifecycleCallback ($ method ->getName (), Events::preLoad);
309- } elseif ($ annot instanceof ODM \PostLoad) {
310- $ metadata ->addLifecycleCallback ($ method ->getName (), Events::postLoad);
311- } elseif ($ annot instanceof ODM \PreFlush) {
312- $ metadata ->addLifecycleCallback ($ method ->getName (), Events::preFlush);
313- }
314- }
315- }
316- }
317-
318- /**
319- * @param ClassMetadata<object> $class
320- * @param array<string, int|string> $keys
321- */
322- private function addIndex (ClassMetadata $ class , AbstractIndex $ index , array $ keys = []): void
323- {
324- $ keys = array_merge ($ keys , $ index ->keys );
325- $ options = [];
326- $ allowed = ['name ' , 'background ' , 'unique ' , 'sparse ' , 'expireAfterSeconds ' ];
327- foreach ($ allowed as $ name ) {
328- if (! isset ($ index ->$ name )) {
329- continue ;
330- }
331-
332- $ options [$ name ] = $ index ->$ name ;
333- }
334-
335- if (! empty ($ index ->partialFilterExpression )) {
336- $ options ['partialFilterExpression ' ] = $ index ->partialFilterExpression ;
337- }
338-
339- $ options = array_merge ($ options , $ index ->options );
340- $ class ->addIndex ($ keys , $ options );
341- }
342-
343- /**
344- * @param ClassMetadata<object> $class
345- *
346- * @throws MappingException
347- */
348- private function setShardKey (ClassMetadata $ class , ODM \ShardKey $ shardKey ): void
349- {
350- $ options = [];
351- $ allowed = ['unique ' , 'numInitialChunks ' ];
352- foreach ($ allowed as $ name ) {
353- if (! isset ($ shardKey ->$ name )) {
354- continue ;
355- }
356-
357- $ options [$ name ] = $ shardKey ->$ name ;
358- }
359-
360- $ class ->setShardKey ($ shardKey ->keys , $ options );
361- }
362-
363- /**
364- * Retrieve the current annotation reader
365- *
366- * @return Reader
367- */
368- public function getReader ()
369- {
370- trigger_deprecation (
371- 'doctrine/mongodb-odm ' ,
372- '2.4 ' ,
373- '%s is deprecated with no replacement ' ,
374- __METHOD__ ,
375- );
376-
377- return $ this ->reader ;
378- }
379-
38038 /**
38139 * Factory method for the Annotation Driver
38240 *
@@ -387,5 +45,3 @@ public static function create($paths = [], ?Reader $reader = null): AnnotationDr
38745 return new self ($ reader ?? new AnnotationReader (), $ paths );
38846 }
38947}
390-
391- interface_exists (\Doctrine \Persistence \Mapping \ClassMetadata::class);
0 commit comments