Completed
Pull Request — master (#1527)
by Andreas
10:44
created

ClassMetadataInfo::setWriteConcern()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
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;
21
22
use Doctrine\ODM\MongoDB\Utility\CollectionHelper;
23
use Doctrine\ODM\MongoDB\LockException;
24
use Doctrine\ODM\MongoDB\Proxy\Proxy;
25
use Doctrine\ODM\MongoDB\Types\Type;
26
use InvalidArgumentException;
27
28
/**
29
 * A <tt>ClassMetadata</tt> instance holds all the object-document mapping metadata
30
 * of a document and it's references.
31
 *
32
 * Once populated, ClassMetadata instances are usually cached in a serialized form.
33
 *
34
 * <b>IMPORTANT NOTE:</b>
35
 *
36
 * The fields of this class are only public for 2 reasons:
37
 * 1) To allow fast READ access.
38
 * 2) To drastically reduce the size of a serialized instance (private/protected members
39
 *    get the whole class name, namespace inclusive, prepended to every property in
40
 *    the serialized representation).
41
 *
42
 * @since       1.0
43
 */
44
class ClassMetadataInfo implements \Doctrine\Common\Persistence\Mapping\ClassMetadata
45
{
46
    /* The Id generator types. */
47
    /**
48
     * AUTO means Doctrine will automatically create a new \MongoId instance for us.
49
     */
50
    const GENERATOR_TYPE_AUTO = 1;
51
52
    /**
53
     * INCREMENT means a separate collection is used for maintaining and incrementing id generation.
54
     * Offers full portability.
55
     */
56
    const GENERATOR_TYPE_INCREMENT = 2;
57
58
    /**
59
     * UUID means Doctrine will generate a uuid for us.
60
     */
61
    const GENERATOR_TYPE_UUID = 3;
62
63
    /**
64
     * ALNUM means Doctrine will generate Alpha-numeric string identifiers, using the INCREMENT
65
     * generator to ensure identifier uniqueness
66
     */
67
    const GENERATOR_TYPE_ALNUM = 4;
68
69
    /**
70
     * CUSTOM means Doctrine expect a class parameter. It will then try to initiate that class
71
     * and pass other options to the generator. It will throw an Exception if the class
72
     * does not exist or if an option was passed for that there is not setter in the new
73
     * generator class.
74
     *
75
     * The class  will have to be a subtype of AbstractIdGenerator.
76
     */
77
    const GENERATOR_TYPE_CUSTOM = 5;
78
79
    /**
80
     * NONE means Doctrine will not generate any id for us and you are responsible for manually
81
     * assigning an id.
82
     */
83
    const GENERATOR_TYPE_NONE = 6;
84
85
    /**
86
     * Default discriminator field name.
87
     *
88
     * This is used for associations value for associations where a that do not define a "targetDocument" or
89
     * "discriminatorField" option in their mapping.
90
     */
91
    const DEFAULT_DISCRIMINATOR_FIELD = '_doctrine_class_name';
92
93
    const REFERENCE_ONE = 1;
94
    const REFERENCE_MANY = 2;
95
    const EMBED_ONE = 3;
96
    const EMBED_MANY = 4;
97
    const MANY = 'many';
98
    const ONE = 'one';
99
100
    /**
101
     * The types of storeAs references
102
     */
103
    const REFERENCE_STORE_AS_ID = 'id';
104
    const REFERENCE_STORE_AS_DB_REF = 'dbRef';
105
    const REFERENCE_STORE_AS_DB_REF_WITH_DB = 'dbRefWithDb';
106
107
    /* The inheritance mapping types */
108
    /**
109
     * NONE means the class does not participate in an inheritance hierarchy
110
     * and therefore does not need an inheritance mapping type.
111
     */
112
    const INHERITANCE_TYPE_NONE = 1;
113
114
    /**
115
     * SINGLE_COLLECTION means the class will be persisted according to the rules of
116
     * <tt>Single Collection Inheritance</tt>.
117
     */
118
    const INHERITANCE_TYPE_SINGLE_COLLECTION = 2;
119
120
    /**
121
     * COLLECTION_PER_CLASS means the class will be persisted according to the rules
122
     * of <tt>Concrete Collection Inheritance</tt>.
123
     */
124
    const INHERITANCE_TYPE_COLLECTION_PER_CLASS = 3;
125
126
    /**
127
     * DEFERRED_IMPLICIT means that changes of entities are calculated at commit-time
128
     * by doing a property-by-property comparison with the original data. This will
129
     * be done for all entities that are in MANAGED state at commit-time.
130
     *
131
     * This is the default change tracking policy.
132
     */
133
    const CHANGETRACKING_DEFERRED_IMPLICIT = 1;
134
135
    /**
136
     * DEFERRED_EXPLICIT means that changes of entities are calculated at commit-time
137
     * by doing a property-by-property comparison with the original data. This will
138
     * be done only for entities that were explicitly saved (through persist() or a cascade).
139
     */
140
    const CHANGETRACKING_DEFERRED_EXPLICIT = 2;
141
142
    /**
143
     * NOTIFY means that Doctrine relies on the entities sending out notifications
144
     * when their properties change. Such entity classes must implement
145
     * the <tt>NotifyPropertyChanged</tt> interface.
146
     */
147
    const CHANGETRACKING_NOTIFY = 3;
148
149
    /**
150
     * SET means that fields will be written to the database using a $set operator
151
     */
152
    const STORAGE_STRATEGY_SET = 'set';
153
154
    /**
155
     * INCREMENT means that fields will be written to the database by calculating
156
     * the difference and using the $inc operator
157
     */
158
    const STORAGE_STRATEGY_INCREMENT = 'increment';
159
160
    const STORAGE_STRATEGY_PUSH_ALL = 'pushAll';
161
    const STORAGE_STRATEGY_ADD_TO_SET = 'addToSet';
162
    const STORAGE_STRATEGY_ATOMIC_SET = 'atomicSet';
163
    const STORAGE_STRATEGY_ATOMIC_SET_ARRAY = 'atomicSetArray';
164
    const STORAGE_STRATEGY_SET_ARRAY = 'setArray';
165
166
    /**
167
     * READ-ONLY: The name of the mongo database the document is mapped to.
168
     */
169
    public $db;
170
171
    /**
172
     * READ-ONLY: The name of the mongo collection the document is mapped to.
173
     */
174
    public $collection;
175
176
    /**
177
     * READ-ONLY: If the collection should be a fixed size.
178
     */
179
    public $collectionCapped;
180
181
    /**
182
     * READ-ONLY: If the collection is fixed size, its size in bytes.
183
     */
184
    public $collectionSize;
185
186
    /**
187
     * READ-ONLY: If the collection is fixed size, the maximum number of elements to store in the collection.
188
     */
189
    public $collectionMax;
190
191
    /**
192
     * READ-ONLY: Describes the level of acknowledgement requested from MongoDB for write operations.
193
     */
194
    public $writeConcern;
195
196
    /**
197
     * READ-ONLY: The field name of the document identifier.
198
     */
199
    public $identifier;
200
201
    /**
202
     * READ-ONLY: The field that stores a file reference and indicates the
203
     * document is a file and should be stored on the MongoGridFS.
204
     */
205
    public $file;
206
207
    /**
208
     * READ-ONLY: The field that stores the calculated distance when performing geo spatial
209
     * queries.
210
     */
211
    public $distance;
212
213
    /**
214
     * READ-ONLY: Whether or not reads for this class are okay to read from a slave.
215
     */
216
    public $slaveOkay;
217
218
    /**
219
     * READ-ONLY: The array of indexes for the document collection.
220
     */
221
    public $indexes = array();
222
223
    /**
224
     * READ-ONLY: Keys and options describing shard key. Only for sharded collections.
225
     */
226
    public $shardKey;
227
228
    /**
229
     * READ-ONLY: Whether or not queries on this document should require indexes.
230
     *
231
     * @deprecated property was deprecated in 1.2 and will be removed in 2.0
232
     */
233
    public $requireIndexes = false;
234
235
    /**
236
     * READ-ONLY: The name of the document class.
237
     */
238
    public $name;
239
240
    /**
241
     * READ-ONLY: The namespace the document class is contained in.
242
     *
243
     * @var string
244
     * @todo Not really needed. Usage could be localized.
245
     */
246
    public $namespace;
247
248
    /**
249
     * READ-ONLY: The name of the document class that is at the root of the mapped document inheritance
250
     * hierarchy. If the document is not part of a mapped inheritance hierarchy this is the same
251
     * as {@link $documentName}.
252
     *
253
     * @var string
254
     */
255
    public $rootDocumentName;
256
257
    /**
258
     * The name of the custom repository class used for the document class.
259
     * (Optional).
260
     *
261
     * @var string
262
     */
263
    public $customRepositoryClassName;
264
265
    /**
266
     * READ-ONLY: The names of the parent classes (ancestors).
267
     *
268
     * @var array
269
     */
270
    public $parentClasses = array();
271
272
    /**
273
     * READ-ONLY: The names of all subclasses (descendants).
274
     *
275
     * @var array
276
     */
277
    public $subClasses = array();
278
279
    /**
280
     * The ReflectionProperty instances of the mapped class.
281
     *
282
     * @var \ReflectionProperty[]
283
     */
284
    public $reflFields = array();
285
286
    /**
287
     * READ-ONLY: The inheritance mapping type used by the class.
288
     *
289
     * @var integer
290
     */
291
    public $inheritanceType = self::INHERITANCE_TYPE_NONE;
292
293
    /**
294
     * READ-ONLY: The Id generator type used by the class.
295
     *
296
     * @var string
297
     */
298
    public $generatorType = self::GENERATOR_TYPE_AUTO;
299
300
    /**
301
     * READ-ONLY: The Id generator options.
302
     *
303
     * @var array
304
     */
305
    public $generatorOptions = array();
306
307
    /**
308
     * READ-ONLY: The ID generator used for generating IDs for this class.
309
     *
310
     * @var \Doctrine\ODM\MongoDB\Id\AbstractIdGenerator
311
     */
312
    public $idGenerator;
313
314
    /**
315
     * READ-ONLY: The field mappings of the class.
316
     * Keys are field names and values are mapping definitions.
317
     *
318
     * The mapping definition array has the following values:
319
     *
320
     * - <b>fieldName</b> (string)
321
     * The name of the field in the Document.
322
     *
323
     * - <b>id</b> (boolean, optional)
324
     * Marks the field as the primary key of the document. Multiple fields of an
325
     * document can have the id attribute, forming a composite key.
326
     *
327
     * @var array
328
     */
329
    public $fieldMappings = array();
330
331
    /**
332
     * READ-ONLY: The association mappings of the class.
333
     * Keys are field names and values are mapping definitions.
334
     *
335
     * @var array
336
     */
337
    public $associationMappings = array();
338
339
    /**
340
     * READ-ONLY: Array of fields to also load with a given method.
341
     *
342
     * @var array
343
     */
344
    public $alsoLoadMethods = array();
345
346
    /**
347
     * READ-ONLY: The registered lifecycle callbacks for documents of this class.
348
     *
349
     * @var array
350
     */
351
    public $lifecycleCallbacks = array();
352
353
    /**
354
     * READ-ONLY: The discriminator value of this class.
355
     *
356
     * <b>This does only apply to the JOINED and SINGLE_COLLECTION inheritance mapping strategies
357
     * where a discriminator field is used.</b>
358
     *
359
     * @var mixed
360
     * @see discriminatorField
361
     */
362
    public $discriminatorValue;
363
364
    /**
365
     * READ-ONLY: The discriminator map of all mapped classes in the hierarchy.
366
     *
367
     * <b>This does only apply to the SINGLE_COLLECTION inheritance mapping strategy
368
     * where a discriminator field is used.</b>
369
     *
370
     * @var mixed
371
     * @see discriminatorField
372
     */
373
    public $discriminatorMap = array();
374
375
    /**
376
     * READ-ONLY: The definition of the discriminator field used in SINGLE_COLLECTION
377
     * inheritance mapping.
378
     *
379
     * @var string
380
     */
381
    public $discriminatorField;
382
383
    /**
384
     * READ-ONLY: The default value for discriminatorField in case it's not set in the document
385
     *
386
     * @var string
387
     * @see discriminatorField
388
     */
389
    public $defaultDiscriminatorValue;
390
391
    /**
392
     * READ-ONLY: Whether this class describes the mapping of a mapped superclass.
393
     *
394
     * @var boolean
395
     */
396
    public $isMappedSuperclass = false;
397
398
    /**
399
     * READ-ONLY: Whether this class describes the mapping of a embedded document.
400
     *
401
     * @var boolean
402
     */
403
    public $isEmbeddedDocument = false;
404
405
    /**
406
     * READ-ONLY: Whether this class describes the mapping of an aggregation result document.
407
     *
408
     * @var boolean
409
     */
410
    public $isQueryResultDocument = false;
411
412
    /**
413
     * READ-ONLY: The policy used for change-tracking on entities of this class.
414
     *
415
     * @var integer
416
     */
417
    public $changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT;
418
419
    /**
420
     * READ-ONLY: A flag for whether or not instances of this class are to be versioned
421
     * with optimistic locking.
422
     *
423
     * @var boolean $isVersioned
424
     */
425
    public $isVersioned;
426
427
    /**
428
     * READ-ONLY: The name of the field which is used for versioning in optimistic locking (if any).
429
     *
430
     * @var mixed $versionField
431
     */
432
    public $versionField;
433
434
    /**
435
     * READ-ONLY: A flag for whether or not instances of this class are to allow pessimistic
436
     * locking.
437
     *
438
     * @var boolean $isLockable
439
     */
440
    public $isLockable;
441
442
    /**
443
     * READ-ONLY: The name of the field which is used for locking a document.
444
     *
445
     * @var mixed $lockField
446
     */
447
    public $lockField;
448
449
    /**
450
     * The ReflectionClass instance of the mapped class.
451
     *
452
     * @var \ReflectionClass
453
     */
454
    public $reflClass;
455
456
    /**
457
     * Initializes a new ClassMetadata instance that will hold the object-document mapping
458
     * metadata of the class with the given name.
459
     *
460
     * @param string $documentName The name of the document class the new instance is used for.
461
     */
462 964
    public function __construct($documentName)
463
    {
464 964
        $this->name = $documentName;
465 964
        $this->rootDocumentName = $documentName;
466 964
    }
467
468
    /**
469
     * {@inheritDoc}
470
     */
471 893
    public function getReflectionClass()
472
    {
473 893
        if ( ! $this->reflClass) {
474 2
            $this->reflClass = new \ReflectionClass($this->name);
475
        }
476
477 893
        return $this->reflClass;
478
    }
479
480
    /**
481
     * {@inheritDoc}
482
     */
483 316
    public function isIdentifier($fieldName)
484
    {
485 316
        return $this->identifier === $fieldName;
486
    }
487
488
    /**
489
     * INTERNAL:
490
     * Sets the mapped identifier field of this class.
491
     *
492
     * @param string $identifier
493
     */
494 353
    public function setIdentifier($identifier)
495
    {
496 353
        $this->identifier = $identifier;
497 353
    }
498
499
    /**
500
     * {@inheritDoc}
501
     *
502
     * Since MongoDB only allows exactly one identifier field
503
     * this will always return an array with only one value
504
     */
505 40
    public function getIdentifier()
506
    {
507 40
        return array($this->identifier);
508
    }
509
510
    /**
511
     * {@inheritDoc}
512
     *
513
     * Since MongoDB only allows exactly one identifier field
514
     * this will always return an array with only one value
515
     */
516 95
    public function getIdentifierFieldNames()
517
    {
518 95
        return array($this->identifier);
519
    }
520
521
    /**
522
     * {@inheritDoc}
523
     */
524 547
    public function hasField($fieldName)
525
    {
526 547
        return isset($this->fieldMappings[$fieldName]);
527
    }
528
529
    /**
530
     * Sets the inheritance type used by the class and it's subclasses.
531
     *
532
     * @param integer $type
533
     */
534 369
    public function setInheritanceType($type)
535
    {
536 369
        $this->inheritanceType = $type;
537 369
    }
538
539
    /**
540
     * Checks whether a mapped field is inherited from an entity superclass.
541
     *
542
     * @param  string $fieldName
543
     *
544
     * @return boolean TRUE if the field is inherited, FALSE otherwise.
545
     */
546 893
    public function isInheritedField($fieldName)
547
    {
548 893
        return isset($this->fieldMappings[$fieldName]['inherited']);
549
    }
550
551
    /**
552
     * Registers a custom repository class for the document class.
553
     *
554
     * @param string $repositoryClassName The class name of the custom repository.
555
     */
556 306
    public function setCustomRepositoryClass($repositoryClassName)
557
    {
558 306
        if ($this->isEmbeddedDocument || $this->isQueryResultDocument) {
559
            return;
560
        }
561
562 306 View Code Duplication
        if ($repositoryClassName && strpos($repositoryClassName, '\\') === false && strlen($this->namespace)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
563 3
            $repositoryClassName = $this->namespace . '\\' . $repositoryClassName;
564
        }
565
566 306
        $this->customRepositoryClassName = $repositoryClassName;
567 306
    }
568
569
    /**
570
     * Dispatches the lifecycle event of the given document by invoking all
571
     * registered callbacks.
572
     *
573
     * @param string $event     Lifecycle event
574
     * @param object $document  Document on which the event occurred
575
     * @param array  $arguments Arguments to pass to all callbacks
576
     * @throws \InvalidArgumentException if document class is not this class or
577
     *                                   a Proxy of this class
578
     */
579 650
    public function invokeLifecycleCallbacks($event, $document, array $arguments = null)
580
    {
581 650
        if ( ! $document instanceof $this->name) {
582 1
            throw new \InvalidArgumentException(sprintf('Expected document class "%s"; found: "%s"', $this->name, get_class($document)));
583
        }
584
585 649
        if (empty($this->lifecycleCallbacks[$event])) {
586 634
            return;
587
        }
588
589 187
        foreach ($this->lifecycleCallbacks[$event] as $callback) {
590 187
            if ($arguments !== null) {
591 186
                call_user_func_array(array($document, $callback), $arguments);
592
            } else {
593 187
                $document->$callback();
594
            }
595
        }
596 187
    }
597
598
    /**
599
     * Checks whether the class has callbacks registered for a lifecycle event.
600
     *
601
     * @param string $event Lifecycle event
602
     *
603
     * @return boolean
604
     */
605
    public function hasLifecycleCallbacks($event)
606
    {
607
        return ! empty($this->lifecycleCallbacks[$event]);
608
    }
609
610
    /**
611
     * Gets the registered lifecycle callbacks for an event.
612
     *
613
     * @param string $event
614
     * @return array
615
     */
616
    public function getLifecycleCallbacks($event)
617
    {
618
        return isset($this->lifecycleCallbacks[$event]) ? $this->lifecycleCallbacks[$event] : array();
619
    }
620
621
    /**
622
     * Adds a lifecycle callback for documents of this class.
623
     *
624
     * If the callback is already registered, this is a NOOP.
625
     *
626
     * @param string $callback
627
     * @param string $event
628
     */
629 286
    public function addLifecycleCallback($callback, $event)
630
    {
631 286
        if (isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event])) {
632 1
            return;
633
        }
634
635 286
        $this->lifecycleCallbacks[$event][] = $callback;
636 286
    }
637
638
    /**
639
     * Sets the lifecycle callbacks for documents of this class.
640
     *
641
     * Any previously registered callbacks are overwritten.
642
     *
643
     * @param array $callbacks
644
     */
645 352
    public function setLifecycleCallbacks(array $callbacks)
646
    {
647 352
        $this->lifecycleCallbacks = $callbacks;
648 352
    }
649
650
    /**
651
     * Registers a method for loading document data before field hydration.
652
     *
653
     * Note: A method may be registered multiple times for different fields.
654
     * it will be invoked only once for the first field found.
655
     *
656
     * @param string       $method Method name
657
     * @param array|string $fields Database field name(s)
658
     */
659 15
    public function registerAlsoLoadMethod($method, $fields)
660
    {
661 15
        $this->alsoLoadMethods[$method] = is_array($fields) ? $fields : array($fields);
662 15
    }
663
664
    /**
665
     * Sets the AlsoLoad methods for documents of this class.
666
     *
667
     * Any previously registered methods are overwritten.
668
     *
669
     * @param array $methods
670
     */
671 352
    public function setAlsoLoadMethods(array $methods)
672
    {
673 352
        $this->alsoLoadMethods = $methods;
674 352
    }
675
676
    /**
677
     * Sets the discriminator field.
678
     *
679
     * The field name is the the unmapped database field. Discriminator values
680
     * are only used to discern the hydration class and are not mapped to class
681
     * properties.
682
     *
683
     * @param string $discriminatorField
684
     *
685
     * @throws MappingException If the discriminator field conflicts with the
686
     *                          "name" attribute of a mapped field.
687
     */
688 379
    public function setDiscriminatorField($discriminatorField)
689
    {
690 379
        if ($discriminatorField === null) {
691 315
            $this->discriminatorField = null;
692
693 315
            return;
694
        }
695
696
        // Handle array argument with name/fieldName keys for BC
697 121
        if (is_array($discriminatorField)) {
698
            if (isset($discriminatorField['name'])) {
699
                $discriminatorField = $discriminatorField['name'];
700
            } elseif (isset($discriminatorField['fieldName'])) {
701
                $discriminatorField = $discriminatorField['fieldName'];
702
            }
703
        }
704
705 121
        foreach ($this->fieldMappings as $fieldMapping) {
706 4
            if ($discriminatorField == $fieldMapping['name']) {
707 4
                throw MappingException::discriminatorFieldConflict($this->name, $discriminatorField);
708
            }
709
        }
710
711 120
        $this->discriminatorField = $discriminatorField;
712 120
    }
713
714
    /**
715
     * Sets the discriminator values used by this class.
716
     * Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
717
     *
718
     * @param array $map
719
     *
720
     * @throws MappingException
721
     */
722 375
    public function setDiscriminatorMap(array $map)
723
    {
724 375
        foreach ($map as $value => $className) {
725 119
            if (strpos($className, '\\') === false && strlen($this->namespace)) {
726 85
                $className = $this->namespace . '\\' . $className;
727
            }
728 119
            $this->discriminatorMap[$value] = $className;
729 119
            if ($this->name == $className) {
730 111
                $this->discriminatorValue = $value;
731
            } else {
732 114
                if ( ! class_exists($className)) {
733
                    throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
734
                }
735 114
                if (is_subclass_of($className, $this->name)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if $this->name can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
736 119
                    $this->subClasses[] = $className;
737
                }
738
            }
739
        }
740 375
    }
741
742
    /**
743
     * Sets the default discriminator value to be used for this class
744
     * Used for JOINED and SINGLE_TABLE inheritance mapping strategies if the document has no discriminator value
745
     *
746
     * @param string $defaultDiscriminatorValue
747
     *
748
     * @throws MappingException
749
     */
750 359
    public function setDefaultDiscriminatorValue($defaultDiscriminatorValue)
751
    {
752 359
        if ($defaultDiscriminatorValue === null) {
753 352
            $this->defaultDiscriminatorValue = null;
754
755 352
            return;
756
        }
757
758 60
        if (!array_key_exists($defaultDiscriminatorValue, $this->discriminatorMap)) {
759
            throw MappingException::invalidDiscriminatorValue($defaultDiscriminatorValue, $this->name);
760
        }
761
762 60
        $this->defaultDiscriminatorValue = $defaultDiscriminatorValue;
763 60
    }
764
765
    /**
766
     * Sets the discriminator value for this class.
767
     * Used for JOINED/SINGLE_TABLE inheritance and multiple document types in a single
768
     * collection.
769
     *
770
     * @param string $value
771
     */
772
    public function setDiscriminatorValue($value)
773
    {
774
        $this->discriminatorMap[$value] = $this->name;
775
        $this->discriminatorValue = $value;
776
    }
777
778
    /**
779
     * Sets the slaveOkay option applied to collections for this class.
780
     *
781
     * @param boolean|null $slaveOkay
782
     */
783 3
    public function setSlaveOkay($slaveOkay)
784
    {
785 3
        $this->slaveOkay = $slaveOkay === null ? null : (boolean) $slaveOkay;
786 3
    }
787
788
    /**
789
     * Add a index for this Document.
790
     *
791
     * @param array $keys Array of keys for the index.
792
     * @param array $options Array of options for the index.
793
     */
794 221
    public function addIndex($keys, array $options = array())
795
    {
796 221
        $this->indexes[] = array(
797 View Code Duplication
            'keys' => array_map(function($value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
798 221
                if ($value == 1 || $value == -1) {
799 60
                    return (int) $value;
800
                }
801 214
                if (is_string($value)) {
802 214
                    $lower = strtolower($value);
803 214
                    if ($lower === 'asc') {
804 207
                        return 1;
805 11
                    } elseif ($lower === 'desc') {
806 4
                        return -1;
807
                    }
808
                }
809 7
                return $value;
810 221
            }, $keys),
811 221
            'options' => $options
812
        );
813 221
    }
814
815
    /**
816
     * Set whether or not queries on this document should require indexes.
817
     *
818
     * @param bool $requireIndexes
819
     *
820
     * @deprecated method was deprecated in 1.2 and will be removed in 2.0
821
     */
822 884
    public function setRequireIndexes($requireIndexes)
823
    {
824 884
        $this->requireIndexes = $requireIndexes;
0 ignored issues
show
Deprecated Code introduced by
The property Doctrine\ODM\MongoDB\Map...taInfo::$requireIndexes 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...
825 884
    }
826
827
    /**
828
     * Returns the array of indexes for this Document.
829
     *
830
     * @return array $indexes The array of indexes.
831
     */
832 53
    public function getIndexes()
833
    {
834 53
        return $this->indexes;
835
    }
836
837
    /**
838
     * Checks whether this document has indexes or not.
839
     *
840
     * @return boolean
841
     */
842
    public function hasIndexes()
843
    {
844
        return $this->indexes ? true : false;
845
    }
846
847
    /**
848
     * Set shard key for this Document.
849
     *
850
     * @param array $keys Array of document keys.
851
     * @param array $options Array of sharding options.
852
     *
853
     * @throws MappingException
854
     */
855 87
    public function setShardKey(array $keys, array $options = array())
856
    {
857 87
        if ($this->inheritanceType === self::INHERITANCE_TYPE_SINGLE_COLLECTION && !is_null($this->shardKey)) {
858 2
            throw MappingException::shardKeyInSingleCollInheritanceSubclass($this->getName());
859
        }
860
861 87
        if ($this->isEmbeddedDocument) {
862 2
            throw MappingException::embeddedDocumentCantHaveShardKey($this->getName());
863
        }
864
865 85
        foreach (array_keys($keys) as $field) {
866 85
            if (! isset($this->fieldMappings[$field])) {
867 78
                continue;
868
            }
869
870 7
            if (in_array($this->fieldMappings[$field]['type'], ['many', 'collection'])) {
871 3
                throw MappingException::noMultiKeyShardKeys($this->getName(), $field);
872
            }
873
874 4
            if ($this->fieldMappings[$field]['strategy'] !== static::STORAGE_STRATEGY_SET) {
875 4
                throw MappingException::onlySetStrategyAllowedInShardKey($this->getName(), $field);
876
            }
877
        }
878
879 81
        $this->shardKey = array(
880 View Code Duplication
            'keys' => array_map(function($value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
881 81
                if ($value == 1 || $value == -1) {
882 6
                    return (int) $value;
883
                }
884 80
                if (is_string($value)) {
885 80
                    $lower = strtolower($value);
886 80
                    if ($lower === 'asc') {
887 79
                        return 1;
888 53
                    } elseif ($lower === 'desc') {
889
                        return -1;
890
                    }
891
                }
892 53
                return $value;
893 81
            }, $keys),
894 81
            'options' => $options
895
        );
896 81
    }
897
898
    /**
899
     * @return array
900
     */
901 28
    public function getShardKey()
902
    {
903 28
        return $this->shardKey;
904
    }
905
906
    /**
907
     * Checks whether this document has shard key or not.
908
     *
909
     * @return bool
910
     */
911 587
    public function isSharded()
912
    {
913 587
        return $this->shardKey ? true : false;
914
    }
915
916
    /**
917
     * Sets the write concern used by this class.
918
     *
919
     * @param string $writeConcern
920
     */
921 366
    public function setWriteConcern($writeConcern)
922
    {
923 366
        $this->writeConcern = $writeConcern;
924 366
    }
925
926
    /**
927
     * @return string
928
     */
929 12
    public function getWriteConcern()
930
    {
931 12
        return $this->writeConcern;
932
    }
933
934
    /**
935
     * Whether there is a write concern configured for this class.
936
     *
937
     * @return bool
938
     */
939 599
    public function hasWriteConcern()
940
    {
941 599
        return $this->writeConcern !== null;
942
    }
943
944
    /**
945
     * Sets the change tracking policy used by this class.
946
     *
947
     * @param integer $policy
948
     */
949 357
    public function setChangeTrackingPolicy($policy)
950
    {
951 357
        $this->changeTrackingPolicy = $policy;
952 357
    }
953
954
    /**
955
     * Whether the change tracking policy of this class is "deferred explicit".
956
     *
957
     * @return boolean
958
     */
959 70
    public function isChangeTrackingDeferredExplicit()
960
    {
961 70
        return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_EXPLICIT;
962
    }
963
964
    /**
965
     * Whether the change tracking policy of this class is "deferred implicit".
966
     *
967
     * @return boolean
968
     */
969 619
    public function isChangeTrackingDeferredImplicit()
970
    {
971 619
        return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_IMPLICIT;
972
    }
973
974
    /**
975
     * Whether the change tracking policy of this class is "notify".
976
     *
977
     * @return boolean
978
     */
979 347
    public function isChangeTrackingNotify()
980
    {
981 347
        return $this->changeTrackingPolicy == self::CHANGETRACKING_NOTIFY;
982
    }
983
984
    /**
985
     * Gets the ReflectionProperties of the mapped class.
986
     *
987
     * @return array An array of ReflectionProperty instances.
988
     */
989 95
    public function getReflectionProperties()
990
    {
991 95
        return $this->reflFields;
992
    }
993
994
    /**
995
     * Gets a ReflectionProperty for a specific field of the mapped class.
996
     *
997
     * @param string $name
998
     *
999
     * @return \ReflectionProperty
1000
     */
1001
    public function getReflectionProperty($name)
1002
    {
1003
        return $this->reflFields[$name];
1004
    }
1005
1006
    /**
1007
     * {@inheritDoc}
1008
     */
1009 899
    public function getName()
1010
    {
1011 899
        return $this->name;
1012
    }
1013
1014
    /**
1015
     * The namespace this Document class belongs to.
1016
     *
1017
     * @return string $namespace The namespace name.
1018
     */
1019
    public function getNamespace()
1020
    {
1021
        return $this->namespace;
1022
    }
1023
1024
    /**
1025
     * Returns the database this Document is mapped to.
1026
     *
1027
     * @return string $db The database name.
1028
     */
1029 820
    public function getDatabase()
1030
    {
1031 820
        return $this->db;
1032
    }
1033
1034
    /**
1035
     * Set the database this Document is mapped to.
1036
     *
1037
     * @param string $db The database name
1038
     */
1039 97
    public function setDatabase($db)
1040
    {
1041 97
        $this->db = $db;
1042 97
    }
1043
1044
    /**
1045
     * Get the collection this Document is mapped to.
1046
     *
1047
     * @return string $collection The collection name.
1048
     */
1049 826
    public function getCollection()
1050
    {
1051 826
        return $this->collection;
1052
    }
1053
1054
    /**
1055
     * Sets the collection this Document is mapped to.
1056
     *
1057
     * @param array|string $name
1058
     *
1059
     * @throws \InvalidArgumentException
1060
     */
1061 927
    public function setCollection($name)
1062
    {
1063 927
        if (is_array($name)) {
1064
            if ( ! isset($name['name'])) {
1065
                throw new \InvalidArgumentException('A name key is required when passing an array to setCollection()');
1066
            }
1067
            $this->collectionCapped = isset($name['capped']) ? $name['capped'] : false;
1068
            $this->collectionSize = isset($name['size']) ? $name['size'] : 0;
1069
            $this->collectionMax = isset($name['max']) ? $name['max'] : 0;
1070
            $this->collection = $name['name'];
1071
        } else {
1072 927
            $this->collection = $name;
1073
        }
1074 927
    }
1075
1076
    /**
1077
     * Get whether or not the documents collection is capped.
1078
     *
1079
     * @return boolean
1080
     */
1081 4
    public function getCollectionCapped()
1082
    {
1083 4
        return $this->collectionCapped;
1084
    }
1085
1086
    /**
1087
     * Set whether or not the documents collection is capped.
1088
     *
1089
     * @param boolean $bool
1090
     */
1091 1
    public function setCollectionCapped($bool)
1092
    {
1093 1
        $this->collectionCapped = $bool;
1094 1
    }
1095
1096
    /**
1097
     * Get the collection size
1098
     *
1099
     * @return integer
1100
     */
1101 4
    public function getCollectionSize()
1102
    {
1103 4
        return $this->collectionSize;
1104
    }
1105
1106
    /**
1107
     * Set the collection size.
1108
     *
1109
     * @param integer $size
1110
     */
1111 1
    public function setCollectionSize($size)
1112
    {
1113 1
        $this->collectionSize = $size;
1114 1
    }
1115
1116
    /**
1117
     * Get the collection max.
1118
     *
1119
     * @return integer
1120
     */
1121 4
    public function getCollectionMax()
1122
    {
1123 4
        return $this->collectionMax;
1124
    }
1125
1126
    /**
1127
     * Set the collection max.
1128
     *
1129
     * @param integer $max
1130
     */
1131 1
    public function setCollectionMax($max)
1132
    {
1133 1
        $this->collectionMax = $max;
1134 1
    }
1135
1136
    /**
1137
     * Returns TRUE if this Document is mapped to a collection FALSE otherwise.
1138
     *
1139
     * @return boolean
1140
     */
1141
    public function isMappedToCollection()
1142
    {
1143
        return $this->collection ? true : false;
1144
    }
1145
1146
    /**
1147
     * Returns TRUE if this Document is a file to be stored on the MongoGridFS FALSE otherwise.
1148
     *
1149
     * @return boolean
1150
     */
1151 766
    public function isFile()
1152
    {
1153 766
        return $this->file ? true : false;
1154
    }
1155
1156
    /**
1157
     * Returns the file field name.
1158
     *
1159
     * @return string $file The file field name.
1160
     */
1161 352
    public function getFile()
1162
    {
1163 352
        return $this->file;
1164
    }
1165
1166
    /**
1167
     * Set the field name that stores the grid file.
1168
     *
1169
     * @param string $file
1170
     */
1171 353
    public function setFile($file)
1172
    {
1173 353
        $this->file = $file;
1174 353
    }
1175
1176
    /**
1177
     * Returns the distance field name.
1178
     *
1179
     * @return string $distance The distance field name.
1180
     */
1181
    public function getDistance()
1182
    {
1183
        return $this->distance;
1184
    }
1185
1186
    /**
1187
     * Set the field name that stores the distance.
1188
     *
1189
     * @param string $distance
1190
     */
1191 1
    public function setDistance($distance)
1192
    {
1193 1
        $this->distance = $distance;
1194 1
    }
1195
1196
    /**
1197
     * Map a field.
1198
     *
1199
     * @param array $mapping The mapping information.
1200
     *
1201
     * @return array
1202
     *
1203
     * @throws MappingException
1204
     */
1205 942
    public function mapField(array $mapping)
1206
    {
1207 942
        if ( ! isset($mapping['fieldName']) && isset($mapping['name'])) {
1208 9
            $mapping['fieldName'] = $mapping['name'];
1209
        }
1210 942
        if ( ! isset($mapping['fieldName'])) {
1211
            throw MappingException::missingFieldName($this->name);
1212
        }
1213 942
        if ( ! isset($mapping['name'])) {
1214 933
            $mapping['name'] = $mapping['fieldName'];
1215
        }
1216 942
        if ($this->identifier === $mapping['name'] && empty($mapping['id'])) {
1217 1
            throw MappingException::mustNotChangeIdentifierFieldsType($this->name, $mapping['name']);
1218
        }
1219 941
        if (isset($this->fieldMappings[$mapping['fieldName']])) {
1220
            //throw MappingException::duplicateFieldMapping($this->name, $mapping['fieldName']);
1221
        }
1222 941
        if ($this->discriminatorField !== null && $this->discriminatorField == $mapping['name']) {
1223 1
            throw MappingException::discriminatorFieldConflict($this->name, $this->discriminatorField);
1224
        }
1225 940 View Code Duplication
        if (isset($mapping['targetDocument']) && strpos($mapping['targetDocument'], '\\') === false && strlen($this->namespace)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1226 597
            $mapping['targetDocument'] = $this->namespace . '\\' . $mapping['targetDocument'];
1227
        }
1228 940
        if (isset($mapping['collectionClass'])) {
1229 65 View Code Duplication
            if (strpos($mapping['collectionClass'], '\\') === false && strlen($this->namespace)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1230 63
                $mapping['collectionClass'] = $this->namespace . '\\' . $mapping['collectionClass'];
1231
            }
1232 65
            $mapping['collectionClass'] = ltrim($mapping['collectionClass'], '\\');
1233
        }
1234 940
        if ( ! empty($mapping['collectionClass'])) {
1235 65
            $rColl = new \ReflectionClass($mapping['collectionClass']);
1236 65
            if ( ! $rColl->implementsInterface('Doctrine\\Common\\Collections\\Collection')) {
1237 1
                throw MappingException::collectionClassDoesNotImplementCommonInterface($this->name, $mapping['fieldName'], $mapping['collectionClass']);
1238
            }
1239
        }
1240
1241 939
        if (isset($mapping['discriminatorMap'])) {
1242 123
            foreach ($mapping['discriminatorMap'] as $key => $class) {
1243 123 View Code Duplication
                if (strpos($class, '\\') === false && strlen($this->namespace)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1244 123
                    $mapping['discriminatorMap'][$key] = $this->namespace . '\\' . $class;
1245
                }
1246
            }
1247
        }
1248
1249 939
        if (isset($mapping['cascade']) && isset($mapping['embedded'])) {
1250 1
            throw MappingException::cascadeOnEmbeddedNotAllowed($this->name, $mapping['fieldName']);
1251
        }
1252
1253 938
        $cascades = isset($mapping['cascade']) ? array_map('strtolower', (array) $mapping['cascade']) : array();
1254
1255 938
        if (in_array('all', $cascades) || isset($mapping['embedded'])) {
1256 624
            $cascades = array('remove', 'persist', 'refresh', 'merge', 'detach');
1257
        }
1258
1259 938
        if (isset($mapping['embedded'])) {
1260 587
            unset($mapping['cascade']);
1261 933
        } elseif (isset($mapping['cascade'])) {
1262 387
            $mapping['cascade'] = $cascades;
1263
        }
1264
1265 938
        $mapping['isCascadeRemove'] = in_array('remove', $cascades);
1266 938
        $mapping['isCascadePersist'] = in_array('persist', $cascades);
1267 938
        $mapping['isCascadeRefresh'] = in_array('refresh', $cascades);
1268 938
        $mapping['isCascadeMerge'] = in_array('merge', $cascades);
1269 938
        $mapping['isCascadeDetach'] = in_array('detach', $cascades);
1270
1271 938
        if (isset($mapping['type']) && $mapping['type'] === 'file') {
1272 63
            $mapping['file'] = true;
1273
        }
1274 938
        if (isset($mapping['type']) && $mapping['type'] === 'increment') {
1275 1
            $mapping['strategy'] = self::STORAGE_STRATEGY_INCREMENT;
1276
        }
1277 938 View Code Duplication
        if (isset($mapping['file']) && $mapping['file'] === true) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1278 63
            $this->file = $mapping['fieldName'];
1279 63
            $mapping['name'] = 'file';
1280
        }
1281 938 View Code Duplication
        if (isset($mapping['distance']) && $mapping['distance'] === true) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1282 7
            $this->distance = $mapping['fieldName'];
1283
        }
1284 938
        if (isset($mapping['id']) && $mapping['id'] === true) {
1285 909
            $mapping['name'] = '_id';
1286 909
            $this->identifier = $mapping['fieldName'];
1287 909 View Code Duplication
            if (isset($mapping['strategy'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1288 892
                $this->generatorType = constant(ClassMetadata::class . '::GENERATOR_TYPE_' . strtoupper($mapping['strategy']));
1289
            }
1290 909
            $this->generatorOptions = isset($mapping['options']) ? $mapping['options'] : array();
1291 909
            switch ($this->generatorType) {
1292 909
                case self::GENERATOR_TYPE_AUTO:
1293 837
                    $mapping['type'] = 'id';
1294 837
                    break;
1295
                default:
1296 151
                    if ( ! empty($this->generatorOptions['type'])) {
1297 52
                        $mapping['type'] = $this->generatorOptions['type'];
1298 99
                    } elseif (empty($mapping['type'])) {
1299 84
                        $mapping['type'] = $this->generatorType === self::GENERATOR_TYPE_INCREMENT ? 'int_id' : 'custom_id';
1300
                    }
1301
            }
1302 909
            unset($this->generatorOptions['type']);
1303
        }
1304
1305 938
        if ( ! isset($mapping['nullable'])) {
1306 52
            $mapping['nullable'] = false;
1307
        }
1308
1309
        // Synchronize the "simple" and "storeAs" mapping information for backwards compatibility
1310 938
        if (isset($mapping['simple']) && ($mapping['simple'] === true || $mapping['simple'] === 'true')) {
1311 280
            $mapping['storeAs'] = ClassMetadataInfo::REFERENCE_STORE_AS_ID;
1312
        }
1313
        // Provide the correct value for the "simple" field for backwards compatibility
1314 938
        if (isset($mapping['storeAs'])) {
1315 566
            $mapping['simple'] = $mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID;
1316
        }
1317
1318 938 View Code Duplication
        if (isset($mapping['reference'])
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1319 938
            && isset($mapping['storeAs'])
1320 938
            && $mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID
1321 938
            && ! isset($mapping['targetDocument'])
1322
        ) {
1323 3
            throw MappingException::simpleReferenceRequiresTargetDocument($this->name, $mapping['fieldName']);
1324
        }
1325
1326 935 View Code Duplication
        if (isset($mapping['reference'])
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1327 935
            && isset($mapping['storeAs'])
1328 935
            && $mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID
1329 935
            && isset($mapping['redundantFields'])
1330 935
            && $mapping['redundantFields'] !== []
1331
        ) {
1332 1
            throw MappingException::simpleReferenceCannotHaveRedundantFields($this->name, $mapping['fieldName']);
1333
        }
1334
1335 934
        if (isset($mapping['reference']) && empty($mapping['targetDocument']) && empty($mapping['discriminatorMap']) &&
1336 934
                (isset($mapping['mappedBy']) || isset($mapping['inversedBy']))) {
1337 4
            throw MappingException::owningAndInverseReferencesRequireTargetDocument($this->name, $mapping['fieldName']);
1338
        }
1339
1340 930
        if ($this->isEmbeddedDocument && $mapping['type'] === 'many' && CollectionHelper::isAtomic($mapping['strategy'])) {
1341 1
            throw MappingException::atomicCollectionStrategyNotAllowed($mapping['strategy'], $this->name, $mapping['fieldName']);
1342
        }
1343
1344 929 View Code Duplication
        if (isset($mapping['reference']) && $mapping['type'] === 'one') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1345 500
            $mapping['association'] = self::REFERENCE_ONE;
1346
        }
1347 929 View Code Duplication
        if (isset($mapping['reference']) && $mapping['type'] === 'many') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1348 440
            $mapping['association'] = self::REFERENCE_MANY;
1349
        }
1350 929 View Code Duplication
        if (isset($mapping['embedded']) && $mapping['type'] === 'one') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1351 448
            $mapping['association'] = self::EMBED_ONE;
1352
        }
1353 929 View Code Duplication
        if (isset($mapping['embedded']) && $mapping['type'] === 'many') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1354 493
            $mapping['association'] = self::EMBED_MANY;
1355
        }
1356
1357 929
        if (isset($mapping['association']) && ! isset($mapping['targetDocument']) && ! isset($mapping['discriminatorField'])) {
1358 131
            $mapping['discriminatorField'] = self::DEFAULT_DISCRIMINATOR_FIELD;
1359
        }
1360
1361
        /*
1362
        if (isset($mapping['type']) && ($mapping['type'] === 'one' || $mapping['type'] === 'many')) {
1363
            $mapping['type'] = $mapping['type'] === 'one' ? self::ONE : self::MANY;
1364
        }
1365
        */
1366 929
        if (isset($mapping['version'])) {
1367 100
            $mapping['notSaved'] = true;
1368 100
            $this->setVersionMapping($mapping);
1369
        }
1370 929
        if (isset($mapping['lock'])) {
1371 27
            $mapping['notSaved'] = true;
1372 27
            $this->setLockMapping($mapping);
1373
        }
1374 929
        $mapping['isOwningSide'] = true;
1375 929
        $mapping['isInverseSide'] = false;
1376 929
        if (isset($mapping['reference'])) {
1377 570 View Code Duplication
            if (isset($mapping['inversedBy']) && $mapping['inversedBy']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1378 83
                $mapping['isOwningSide'] = true;
1379 83
                $mapping['isInverseSide'] = false;
1380
            }
1381 570 View Code Duplication
            if (isset($mapping['mappedBy']) && $mapping['mappedBy']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1382 281
                $mapping['isInverseSide'] = true;
1383 281
                $mapping['isOwningSide'] = false;
1384
            }
1385 570 View Code Duplication
            if (isset($mapping['repositoryMethod'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1386 63
                $mapping['isInverseSide'] = true;
1387 63
                $mapping['isOwningSide'] = false;
1388
            }
1389 570
            if (!isset($mapping['orphanRemoval'])) {
1390 547
                $mapping['orphanRemoval'] = false;
1391
            }
1392
        }
1393
1394 929
        $this->applyStorageStrategy($mapping);
1395
1396 928
        $this->fieldMappings[$mapping['fieldName']] = $mapping;
1397 928
        if (isset($mapping['association'])) {
1398 720
            $this->associationMappings[$mapping['fieldName']] = $mapping;
1399
        }
1400
1401 928
        return $mapping;
1402
    }
1403
1404
    /**
1405
     * Validates the storage strategy of a mapping for consistency
1406
     * @param array $mapping
1407
     * @throws \Doctrine\ODM\MongoDB\Mapping\MappingException
1408
     */
1409 929
    private function applyStorageStrategy(array &$mapping)
1410
    {
1411 929
        if (! isset($mapping['type']) || isset($mapping['id'])) {
1412 911
            return;
1413
        }
1414
1415
        switch (true) {
1416 891
            case $mapping['type'] == 'int':
1417 890
            case $mapping['type'] == 'float':
1418 890
            case $mapping['type'] == 'increment':
1419 323
                $defaultStrategy = self::STORAGE_STRATEGY_SET;
1420 323
                $allowedStrategies = [self::STORAGE_STRATEGY_SET, self::STORAGE_STRATEGY_INCREMENT];
1421 323
                break;
1422
1423 889
            case $mapping['type'] == 'many':
1424 597
                $defaultStrategy = CollectionHelper::DEFAULT_STRATEGY;
1425
                $allowedStrategies = [
1426 597
                    self::STORAGE_STRATEGY_PUSH_ALL,
1427 597
                    self::STORAGE_STRATEGY_ADD_TO_SET,
1428 597
                    self::STORAGE_STRATEGY_SET,
1429 597
                    self::STORAGE_STRATEGY_SET_ARRAY,
1430 597
                    self::STORAGE_STRATEGY_ATOMIC_SET,
1431 597
                    self::STORAGE_STRATEGY_ATOMIC_SET_ARRAY,
1432
                ];
1433 597
                break;
1434
1435
            default:
1436 879
                $defaultStrategy = self::STORAGE_STRATEGY_SET;
1437 879
                $allowedStrategies = [self::STORAGE_STRATEGY_SET];
1438
        }
1439
1440 891
        if (! isset($mapping['strategy'])) {
1441 882
            $mapping['strategy'] = $defaultStrategy;
1442
        }
1443
1444 891
        if (! in_array($mapping['strategy'], $allowedStrategies)) {
1445
            throw MappingException::invalidStorageStrategy($this->name, $mapping['fieldName'], $mapping['type'], $mapping['strategy']);
1446
        }
1447
1448 891
        if (isset($mapping['reference']) && $mapping['type'] === 'many' && $mapping['isOwningSide']
1449 891
            && ! empty($mapping['sort']) && ! CollectionHelper::usesSet($mapping['strategy'])) {
1450 1
            throw MappingException::referenceManySortMustNotBeUsedWithNonSetCollectionStrategy($this->name, $mapping['fieldName'], $mapping['strategy']);
1451
        }
1452 890
    }
1453
1454
    /**
1455
     * Map a MongoGridFSFile.
1456
     *
1457
     * @param array $mapping The mapping information.
1458
     */
1459
    public function mapFile(array $mapping)
1460
    {
1461
        $mapping['file'] = true;
1462
        $mapping['type'] = 'file';
1463
        $this->mapField($mapping);
1464
    }
1465
1466
    /**
1467
     * Map a single embedded document.
1468
     *
1469
     * @param array $mapping The mapping information.
1470
     */
1471 6
    public function mapOneEmbedded(array $mapping)
1472
    {
1473 6
        $mapping['embedded'] = true;
1474 6
        $mapping['type'] = 'one';
1475 6
        $this->mapField($mapping);
1476 5
    }
1477
1478
    /**
1479
     * Map a collection of embedded documents.
1480
     *
1481
     * @param array $mapping The mapping information.
1482
     */
1483 5
    public function mapManyEmbedded(array $mapping)
1484
    {
1485 5
        $mapping['embedded'] = true;
1486 5
        $mapping['type'] = 'many';
1487 5
        $this->mapField($mapping);
1488 5
    }
1489
1490
    /**
1491
     * Map a single document reference.
1492
     *
1493
     * @param array $mapping The mapping information.
1494
     */
1495 9
    public function mapOneReference(array $mapping)
1496
    {
1497 9
        $mapping['reference'] = true;
1498 9
        $mapping['type'] = 'one';
1499 9
        $this->mapField($mapping);
1500 8
    }
1501
1502
    /**
1503
     * Map a collection of document references.
1504
     *
1505
     * @param array $mapping The mapping information.
1506
     */
1507 8
    public function mapManyReference(array $mapping)
1508
    {
1509 8
        $mapping['reference'] = true;
1510 8
        $mapping['type'] = 'many';
1511 8
        $this->mapField($mapping);
1512 8
    }
1513
1514
    /**
1515
     * INTERNAL:
1516
     * Adds a field mapping without completing/validating it.
1517
     * This is mainly used to add inherited field mappings to derived classes.
1518
     *
1519
     * @param array $fieldMapping
1520
     */
1521 123
    public function addInheritedFieldMapping(array $fieldMapping)
1522
    {
1523 123
        $this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping;
1524
1525 123
        if (isset($fieldMapping['association'])) {
1526 77
            $this->associationMappings[$fieldMapping['fieldName']] = $fieldMapping;
1527
        }
1528 123
    }
1529
1530
    /**
1531
     * INTERNAL:
1532
     * Adds an association mapping without completing/validating it.
1533
     * This is mainly used to add inherited association mappings to derived classes.
1534
     *
1535
     * @param array $mapping
1536
     *
1537
     * @return void
1538
     *
1539
     * @throws MappingException
1540
     */
1541 78
    public function addInheritedAssociationMapping(array $mapping/*, $owningClassName = null*/)
1542
    {
1543 78
        $this->associationMappings[$mapping['fieldName']] = $mapping;
1544 78
    }
1545
1546
    /**
1547
     * Checks whether the class has a mapped association with the given field name.
1548
     *
1549
     * @param string $fieldName
1550
     * @return boolean
1551
     */
1552 10
    public function hasReference($fieldName)
1553
    {
1554 10
        return isset($this->fieldMappings[$fieldName]['reference']);
1555
    }
1556
1557
    /**
1558
     * Checks whether the class has a mapped embed with the given field name.
1559
     *
1560
     * @param string $fieldName
1561
     * @return boolean
1562
     */
1563 8
    public function hasEmbed($fieldName)
1564
    {
1565 8
        return isset($this->fieldMappings[$fieldName]['embedded']);
1566
    }
1567
1568
    /**
1569
     * {@inheritDoc}
1570
     *
1571
     * Checks whether the class has a mapped association (embed or reference) with the given field name.
1572
     */
1573 10
    public function hasAssociation($fieldName)
1574
    {
1575 10
        return $this->hasReference($fieldName) || $this->hasEmbed($fieldName);
1576
    }
1577
1578
    /**
1579
     * {@inheritDoc}
1580
     *
1581
     * Checks whether the class has a mapped reference or embed for the specified field and
1582
     * is a single valued association.
1583
     */
1584
    public function isSingleValuedAssociation($fieldName)
1585
    {
1586
        return $this->isSingleValuedReference($fieldName) || $this->isSingleValuedEmbed($fieldName);
1587
    }
1588
1589
    /**
1590
     * {@inheritDoc}
1591
     *
1592
     * Checks whether the class has a mapped reference or embed for the specified field and
1593
     * is a collection valued association.
1594
     */
1595
    public function isCollectionValuedAssociation($fieldName)
1596
    {
1597
        return $this->isCollectionValuedReference($fieldName) || $this->isCollectionValuedEmbed($fieldName);
1598
    }
1599
1600
    /**
1601
     * Checks whether the class has a mapped association for the specified field
1602
     * and if yes, checks whether it is a single-valued association (to-one).
1603
     *
1604
     * @param string $fieldName
1605
     * @return boolean TRUE if the association exists and is single-valued, FALSE otherwise.
1606
     */
1607
    public function isSingleValuedReference($fieldName)
1608
    {
1609
        return isset($this->fieldMappings[$fieldName]['association']) &&
1610
            $this->fieldMappings[$fieldName]['association'] === self::REFERENCE_ONE;
1611
    }
1612
1613
    /**
1614
     * Checks whether the class has a mapped association for the specified field
1615
     * and if yes, checks whether it is a collection-valued association (to-many).
1616
     *
1617
     * @param string $fieldName
1618
     * @return boolean TRUE if the association exists and is collection-valued, FALSE otherwise.
1619
     */
1620
    public function isCollectionValuedReference($fieldName)
1621
    {
1622
        return isset($this->fieldMappings[$fieldName]['association']) &&
1623
            $this->fieldMappings[$fieldName]['association'] === self::REFERENCE_MANY;
1624
    }
1625
1626
    /**
1627
     * Checks whether the class has a mapped embedded document for the specified field
1628
     * and if yes, checks whether it is a single-valued association (to-one).
1629
     *
1630
     * @param string $fieldName
1631
     * @return boolean TRUE if the association exists and is single-valued, FALSE otherwise.
1632
     */
1633
    public function isSingleValuedEmbed($fieldName)
1634
    {
1635
        return isset($this->fieldMappings[$fieldName]['association']) &&
1636
            $this->fieldMappings[$fieldName]['association'] === self::EMBED_ONE;
1637
    }
1638
1639
    /**
1640
     * Checks whether the class has a mapped embedded document for the specified field
1641
     * and if yes, checks whether it is a collection-valued association (to-many).
1642
     *
1643
     * @param string $fieldName
1644
     * @return boolean TRUE if the association exists and is collection-valued, FALSE otherwise.
1645
     */
1646
    public function isCollectionValuedEmbed($fieldName)
1647
    {
1648
        return isset($this->fieldMappings[$fieldName]['association']) &&
1649
            $this->fieldMappings[$fieldName]['association'] === self::EMBED_MANY;
1650
    }
1651
1652
    /**
1653
     * Sets the ID generator used to generate IDs for instances of this class.
1654
     *
1655
     * @param \Doctrine\ODM\MongoDB\Id\AbstractIdGenerator $generator
1656
     */
1657 832
    public function setIdGenerator($generator)
1658
    {
1659 832
        $this->idGenerator = $generator;
1660 832
    }
1661
1662
    /**
1663
     * Casts the identifier to its portable PHP type.
1664
     *
1665
     * @param mixed $id
1666
     * @return mixed $id
1667
     */
1668 636
    public function getPHPIdentifierValue($id)
1669
    {
1670 636
        $idType = $this->fieldMappings[$this->identifier]['type'];
1671 636
        return Type::getType($idType)->convertToPHPValue($id);
1672
    }
1673
1674
    /**
1675
     * Casts the identifier to its database type.
1676
     *
1677
     * @param mixed $id
1678
     * @return mixed $id
1679
     */
1680 704
    public function getDatabaseIdentifierValue($id)
1681
    {
1682 704
        $idType = $this->fieldMappings[$this->identifier]['type'];
1683 704
        return Type::getType($idType)->convertToDatabaseValue($id);
1684
    }
1685
1686
    /**
1687
     * Sets the document identifier of a document.
1688
     *
1689
     * The value will be converted to a PHP type before being set.
1690
     *
1691
     * @param object $document
1692
     * @param mixed $id
1693
     */
1694 567
    public function setIdentifierValue($document, $id)
1695
    {
1696 567
        $id = $this->getPHPIdentifierValue($id);
1697 567
        $this->reflFields[$this->identifier]->setValue($document, $id);
1698 567
    }
1699
1700
    /**
1701
     * Gets the document identifier as a PHP type.
1702
     *
1703
     * @param object $document
1704
     * @return mixed $id
1705
     */
1706 655
    public function getIdentifierValue($document)
1707
    {
1708 655
        return $this->reflFields[$this->identifier]->getValue($document);
1709
    }
1710
1711
    /**
1712
     * {@inheritDoc}
1713
     *
1714
     * Since MongoDB only allows exactly one identifier field this is a proxy
1715
     * to {@see getIdentifierValue()} and returns an array with the identifier
1716
     * field as a key.
1717
     */
1718
    public function getIdentifierValues($object)
1719
    {
1720
        return array($this->identifier => $this->getIdentifierValue($object));
1721
    }
1722
1723
    /**
1724
     * Get the document identifier object as a database type.
1725
     *
1726
     * @param object $document
1727
     *
1728
     * @return \MongoId $id The MongoID object.
1729
     */
1730 34
    public function getIdentifierObject($document)
1731
    {
1732 34
        return $this->getDatabaseIdentifierValue($this->getIdentifierValue($document));
1733
    }
1734
1735
    /**
1736
     * Sets the specified field to the specified value on the given document.
1737
     *
1738
     * @param object $document
1739
     * @param string $field
1740
     * @param mixed $value
1741
     */
1742 8
    public function setFieldValue($document, $field, $value)
1743
    {
1744 8
        if ($document instanceof Proxy && ! $document->__isInitialized()) {
1745
            //property changes to an uninitialized proxy will not be tracked or persisted,
1746
            //so the proxy needs to be loaded first.
1747 1
            $document->__load();
1748
        }
1749
1750 8
        $this->reflFields[$field]->setValue($document, $value);
1751 8
    }
1752
1753
    /**
1754
     * Gets the specified field's value off the given document.
1755
     *
1756
     * @param object $document
1757
     * @param string $field
1758
     *
1759
     * @return mixed
1760
     */
1761 30
    public function getFieldValue($document, $field)
1762
    {
1763 30
        if ($document instanceof Proxy && $field !== $this->identifier && ! $document->__isInitialized()) {
1764 1
            $document->__load();
1765
        }
1766
1767 30
        return $this->reflFields[$field]->getValue($document);
1768
    }
1769
1770
    /**
1771
     * Gets the mapping of a field.
1772
     *
1773
     * @param string $fieldName  The field name.
1774
     *
1775
     * @return array  The field mapping.
1776
     *
1777
     * @throws MappingException if the $fieldName is not found in the fieldMappings array
1778
     */
1779 98
    public function getFieldMapping($fieldName)
1780
    {
1781 98
        if ( ! isset($this->fieldMappings[$fieldName])) {
1782 6
            throw MappingException::mappingNotFound($this->name, $fieldName);
1783
        }
1784 96
        return $this->fieldMappings[$fieldName];
1785
    }
1786
1787
    /**
1788
     * Gets mappings of fields holding embedded document(s).
1789
     *
1790
     * @return array of field mappings
1791
     */
1792 611
    public function getEmbeddedFieldsMappings()
1793
    {
1794 611
        return array_filter(
1795 611
            $this->associationMappings,
1796
            function($assoc) { return ! empty($assoc['embedded']); }
1797
        );
1798
    }
1799
1800
    /**
1801
     * Gets the field mapping by its DB name.
1802
     * E.g. it returns identifier's mapping when called with _id.
1803
     *
1804
     * @param string $dbFieldName
1805
     *
1806
     * @return array
1807
     * @throws MappingException
1808
     */
1809 9
    public function getFieldMappingByDbFieldName($dbFieldName)
1810
    {
1811 9
        foreach ($this->fieldMappings as $mapping) {
1812 9
            if ($mapping['name'] == $dbFieldName) {
1813 9
                return $mapping;
1814
            }
1815
        }
1816
1817
        throw MappingException::mappingNotFoundByDbName($this->name, $dbFieldName);
1818
    }
1819
1820
    /**
1821
     * Check if the field is not null.
1822
     *
1823
     * @param string $fieldName  The field name
1824
     *
1825
     * @return boolean  TRUE if the field is not null, FALSE otherwise.
1826
     */
1827 1
    public function isNullable($fieldName)
1828
    {
1829 1
        $mapping = $this->getFieldMapping($fieldName);
1830 1
        if ($mapping !== false) {
1831 1
            return isset($mapping['nullable']) && $mapping['nullable'] == true;
1832
        }
1833
        return false;
1834
    }
1835
1836
    /**
1837
     * Checks whether the document has a discriminator field and value configured.
1838
     *
1839
     * @return boolean
1840
     */
1841 513
    public function hasDiscriminator()
1842
    {
1843 513
        return isset($this->discriminatorField, $this->discriminatorValue);
1844
    }
1845
1846
    /**
1847
     * Sets the type of Id generator to use for the mapped class.
1848
     *
1849
     * @param string $generatorType Generator type.
1850
     */
1851 358
    public function setIdGeneratorType($generatorType)
1852
    {
1853 358
        $this->generatorType = $generatorType;
1854 358
    }
1855
1856
    /**
1857
     * Sets the Id generator options.
1858
     *
1859
     * @param array $generatorOptions Generator options.
1860
     */
1861
    public function setIdGeneratorOptions($generatorOptions)
1862
    {
1863
        $this->generatorOptions = $generatorOptions;
1864
    }
1865
1866
    /**
1867
     * @return boolean
1868
     */
1869 617
    public function isInheritanceTypeNone()
1870
    {
1871 617
        return $this->inheritanceType == self::INHERITANCE_TYPE_NONE;
1872
    }
1873
1874
    /**
1875
     * Checks whether the mapped class uses the SINGLE_COLLECTION inheritance mapping strategy.
1876
     *
1877
     * @return boolean
1878
     */
1879 351
    public function isInheritanceTypeSingleCollection()
1880
    {
1881 351
        return $this->inheritanceType == self::INHERITANCE_TYPE_SINGLE_COLLECTION;
1882
    }
1883
1884
    /**
1885
     * Checks whether the mapped class uses the COLLECTION_PER_CLASS inheritance mapping strategy.
1886
     *
1887
     * @return boolean
1888
     */
1889
    public function isInheritanceTypeCollectionPerClass()
1890
    {
1891
        return $this->inheritanceType == self::INHERITANCE_TYPE_COLLECTION_PER_CLASS;
1892
    }
1893
1894
    /**
1895
     * Sets the mapped subclasses of this class.
1896
     *
1897
     * @param string[] $subclasses The names of all mapped subclasses.
1898
     */
1899 2
    public function setSubclasses(array $subclasses)
1900
    {
1901 2
        foreach ($subclasses as $subclass) {
1902 2
            if (strpos($subclass, '\\') === false && strlen($this->namespace)) {
1903 1
                $this->subClasses[] = $this->namespace . '\\' . $subclass;
1904
            } else {
1905 2
                $this->subClasses[] = $subclass;
1906
            }
1907
        }
1908 2
    }
1909
1910
    /**
1911
     * Sets the parent class names.
1912
     * Assumes that the class names in the passed array are in the order:
1913
     * directParent -> directParentParent -> directParentParentParent ... -> root.
1914
     *
1915
     * @param string[] $classNames
1916
     */
1917 890
    public function setParentClasses(array $classNames)
1918
    {
1919 890
        $this->parentClasses = $classNames;
1920
1921 890
        if (count($classNames) > 0) {
1922 107
            $this->rootDocumentName = array_pop($classNames);
1923
        }
1924 890
    }
1925
1926
    /**
1927
     * Checks whether the class will generate a new \MongoId instance for us.
1928
     *
1929
     * @return boolean TRUE if the class uses the AUTO generator, FALSE otherwise.
1930
     */
1931
    public function isIdGeneratorAuto()
1932
    {
1933
        return $this->generatorType == self::GENERATOR_TYPE_AUTO;
1934
    }
1935
1936
    /**
1937
     * Checks whether the class will use a collection to generate incremented identifiers.
1938
     *
1939
     * @return boolean TRUE if the class uses the INCREMENT generator, FALSE otherwise.
1940
     */
1941
    public function isIdGeneratorIncrement()
1942
    {
1943
        return $this->generatorType == self::GENERATOR_TYPE_INCREMENT;
1944
    }
1945
1946
    /**
1947
     * Checks whether the class will generate a uuid id.
1948
     *
1949
     * @return boolean TRUE if the class uses the UUID generator, FALSE otherwise.
1950
     */
1951
    public function isIdGeneratorUuid()
1952
    {
1953
        return $this->generatorType == self::GENERATOR_TYPE_UUID;
1954
    }
1955
1956
    /**
1957
     * Checks whether the class uses no id generator.
1958
     *
1959
     * @return boolean TRUE if the class does not use any id generator, FALSE otherwise.
1960
     */
1961
    public function isIdGeneratorNone()
1962
    {
1963
        return $this->generatorType == self::GENERATOR_TYPE_NONE;
1964
    }
1965
1966
    /**
1967
     * Sets the version field mapping used for versioning. Sets the default
1968
     * value to use depending on the column type.
1969
     *
1970
     * @param array $mapping   The version field mapping array
1971
     *
1972
     * @throws LockException
1973
     */
1974 100
    public function setVersionMapping(array &$mapping)
1975
    {
1976 100
        if ($mapping['type'] !== 'int' && $mapping['type'] !== 'date') {
1977 1
            throw LockException::invalidVersionFieldType($mapping['type']);
1978
        }
1979
1980 99
        $this->isVersioned  = true;
1981 99
        $this->versionField = $mapping['fieldName'];
1982 99
    }
1983
1984
    /**
1985
     * Sets whether this class is to be versioned for optimistic locking.
1986
     *
1987
     * @param boolean $bool
1988
     */
1989 352
    public function setVersioned($bool)
1990
    {
1991 352
        $this->isVersioned = $bool;
1992 352
    }
1993
1994
    /**
1995
     * Sets the name of the field that is to be used for versioning if this class is
1996
     * versioned for optimistic locking.
1997
     *
1998
     * @param string $versionField
1999
     */
2000 352
    public function setVersionField($versionField)
2001
    {
2002 352
        $this->versionField = $versionField;
2003 352
    }
2004
2005
    /**
2006
     * Sets the version field mapping used for versioning. Sets the default
2007
     * value to use depending on the column type.
2008
     *
2009
     * @param array $mapping   The version field mapping array
2010
     *
2011
     * @throws \Doctrine\ODM\MongoDB\LockException
2012
     */
2013 27
    public function setLockMapping(array &$mapping)
2014
    {
2015 27
        if ($mapping['type'] !== 'int') {
2016 1
            throw LockException::invalidLockFieldType($mapping['type']);
2017
        }
2018
2019 26
        $this->isLockable = true;
2020 26
        $this->lockField = $mapping['fieldName'];
2021 26
    }
2022
2023
    /**
2024
     * Sets whether this class is to allow pessimistic locking.
2025
     *
2026
     * @param boolean $bool
2027
     */
2028
    public function setLockable($bool)
2029
    {
2030
        $this->isLockable = $bool;
2031
    }
2032
2033
    /**
2034
     * Sets the name of the field that is to be used for storing whether a document
2035
     * is currently locked or not.
2036
     *
2037
     * @param string $lockField
2038
     */
2039
    public function setLockField($lockField)
2040
    {
2041
        $this->lockField = $lockField;
2042
    }
2043
2044
    /**
2045
     * {@inheritDoc}
2046
     */
2047
    public function getFieldNames()
2048
    {
2049
        return array_keys($this->fieldMappings);
2050
    }
2051
2052
    /**
2053
     * {@inheritDoc}
2054
     */
2055
    public function getAssociationNames()
2056
    {
2057
        return array_keys($this->associationMappings);
2058
    }
2059
2060
    /**
2061
     * {@inheritDoc}
2062
     */
2063 22
    public function getTypeOfField($fieldName)
2064
    {
2065 22
        return isset($this->fieldMappings[$fieldName]) ?
2066 22
            $this->fieldMappings[$fieldName]['type'] : null;
2067
    }
2068
2069
    /**
2070
     * {@inheritDoc}
2071
     */
2072 6
    public function getAssociationTargetClass($assocName)
2073
    {
2074 6
        if ( ! isset($this->associationMappings[$assocName])) {
2075 3
            throw new InvalidArgumentException("Association name expected, '" . $assocName . "' is not an association.");
2076
        }
2077
2078 3
        return $this->associationMappings[$assocName]['targetDocument'];
2079
    }
2080
2081
    /**
2082
     * Retrieve the collectionClass associated with an association
2083
     *
2084
     * @param string $assocName
2085
     */
2086 2
    public function getAssociationCollectionClass($assocName)
2087
    {
2088 2
        if ( ! isset($this->associationMappings[$assocName])) {
2089
            throw new InvalidArgumentException("Association name expected, '" . $assocName . "' is not an association.");
2090
        }
2091
2092 2
        if ( ! array_key_exists('collectionClass', $this->associationMappings[$assocName])) {
2093
            throw new InvalidArgumentException("collectionClass can only be applied to 'embedMany' and 'referenceMany' associations.");
2094
        }
2095
2096 2
        return $this->associationMappings[$assocName]['collectionClass'];
2097
    }
2098
2099
    /**
2100
     * {@inheritDoc}
2101
     */
2102
    public function isAssociationInverseSide($fieldName)
2103
    {
2104
        throw new \BadMethodCallException(__METHOD__ . '() is not implemented yet.');
2105
    }
2106
2107
    /**
2108
     * {@inheritDoc}
2109
     */
2110
    public function getAssociationMappedByTargetField($fieldName)
2111
    {
2112
        throw new \BadMethodCallException(__METHOD__ . '() is not implemented yet.');
2113
    }
2114
}
2115