Completed
Pull Request — master (#1458)
by Tony R
10:23
created

ClassMetadataInfo::setParentClasses()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
crap 2
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
    public $requireIndexes = false;
232
233
    /**
234
     * READ-ONLY: The name of the document class.
235
     */
236
    public $name;
237
238
    /**
239
     * READ-ONLY: The namespace the document class is contained in.
240
     *
241
     * @var string
242
     * @todo Not really needed. Usage could be localized.
243
     */
244
    public $namespace;
245
246
    /**
247
     * READ-ONLY: The name of the document class that is at the root of the mapped document inheritance
248
     * hierarchy. If the document is not part of a mapped inheritance hierarchy this is the same
249
     * as {@link $documentName}.
250
     *
251
     * @var string
252
     */
253
    public $rootDocumentName;
254
255
    /**
256
     * The name of the custom repository class used for the document class.
257
     * (Optional).
258
     *
259
     * @var string
260
     */
261
    public $customRepositoryClassName;
262
263
    /**
264
     * READ-ONLY: The names of the parent classes (ancestors).
265
     *
266
     * @var array
267
     */
268
    public $parentClasses = array();
269
270
    /**
271
     * READ-ONLY: The names of all subclasses (descendants).
272
     *
273
     * @var array
274
     */
275
    public $subClasses = array();
276
277
    /**
278
     * The ReflectionProperty instances of the mapped class.
279
     *
280
     * @var \ReflectionProperty[]
281
     */
282
    public $reflFields = array();
283
284
    /**
285
     * READ-ONLY: The inheritance mapping type used by the class.
286
     *
287
     * @var integer
288
     */
289
    public $inheritanceType = self::INHERITANCE_TYPE_NONE;
290
291
    /**
292
     * READ-ONLY: The Id generator type used by the class.
293
     *
294
     * @var string
295
     */
296
    public $generatorType = self::GENERATOR_TYPE_AUTO;
297
298
    /**
299
     * READ-ONLY: The Id generator options.
300
     *
301
     * @var array
302
     */
303
    public $generatorOptions = array();
304
305
    /**
306
     * READ-ONLY: The ID generator used for generating IDs for this class.
307
     *
308
     * @var \Doctrine\ODM\MongoDB\Id\AbstractIdGenerator
309
     */
310
    public $idGenerator;
311
312
    /**
313
     * READ-ONLY: The field mappings of the class.
314
     * Keys are field names and values are mapping definitions.
315
     *
316
     * The mapping definition array has the following values:
317
     *
318
     * - <b>fieldName</b> (string)
319
     * The name of the field in the Document.
320
     *
321
     * - <b>id</b> (boolean, optional)
322
     * Marks the field as the primary key of the document. Multiple fields of an
323
     * document can have the id attribute, forming a composite key.
324
     *
325
     * @var array
326
     */
327
    public $fieldMappings = array();
328
329
    /**
330
     * READ-ONLY: The association mappings of the class.
331
     * Keys are field names and values are mapping definitions.
332
     *
333
     * @var array
334
     */
335
    public $associationMappings = array();
336
337
    /**
338
     * READ-ONLY: Array of fields to also load with a given method.
339
     *
340
     * @var array
341
     */
342
    public $alsoLoadMethods = array();
343
344
    /**
345
     * READ-ONLY: The registered lifecycle callbacks for documents of this class.
346
     *
347
     * @var array
348
     */
349
    public $lifecycleCallbacks = array();
350
351
    /**
352
     * READ-ONLY: The discriminator value of this class.
353
     *
354
     * <b>This does only apply to the JOINED and SINGLE_COLLECTION inheritance mapping strategies
355
     * where a discriminator field is used.</b>
356
     *
357
     * @var mixed
358
     * @see discriminatorField
359
     */
360
    public $discriminatorValue;
361
362
    /**
363
     * READ-ONLY: The discriminator map of all mapped classes in the hierarchy.
364
     *
365
     * <b>This does only apply to the SINGLE_COLLECTION inheritance mapping strategy
366
     * where a discriminator field is used.</b>
367
     *
368
     * @var mixed
369
     * @see discriminatorField
370
     */
371
    public $discriminatorMap = array();
372
373
    /**
374
     * READ-ONLY: The definition of the discriminator field used in SINGLE_COLLECTION
375
     * inheritance mapping.
376
     *
377
     * @var string
378
     */
379
    public $discriminatorField;
380
381
    /**
382
     * READ-ONLY: The default value for discriminatorField in case it's not set in the document
383
     *
384
     * @var string
385
     * @see discriminatorField
386
     */
387
    public $defaultDiscriminatorValue;
388
389
    /**
390
     * READ-ONLY: Whether this class describes the mapping of a mapped superclass.
391
     *
392
     * @var boolean
393
     */
394
    public $isMappedSuperclass = false;
395
396
    /**
397
     * READ-ONLY: Whether this class describes the mapping of a embedded document.
398
     *
399
     * @var boolean
400
     */
401
    public $isEmbeddedDocument = false;
402
403
    /**
404
     * READ-ONLY: The policy used for change-tracking on entities of this class.
405
     *
406
     * @var integer
407
     */
408
    public $changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT;
409
410
    /**
411
     * READ-ONLY: A flag for whether or not instances of this class are to be versioned
412
     * with optimistic locking.
413
     *
414
     * @var boolean $isVersioned
415
     */
416
    public $isVersioned;
417
418
    /**
419
     * READ-ONLY: The name of the field which is used for versioning in optimistic locking (if any).
420
     *
421
     * @var mixed $versionField
422
     */
423
    public $versionField;
424
425
    /**
426
     * READ-ONLY: A flag for whether or not instances of this class are to allow pessimistic
427
     * locking.
428
     *
429
     * @var boolean $isLockable
430
     */
431
    public $isLockable;
432
433
    /**
434
     * READ-ONLY: The name of the field which is used for locking a document.
435
     *
436
     * @var mixed $lockField
437
     */
438
    public $lockField;
439
440
    /**
441
     * The ReflectionClass instance of the mapped class.
442
     *
443
     * @var \ReflectionClass
444
     */
445
    public $reflClass;
446
447
    /**
448
     * Initializes a new ClassMetadata instance that will hold the object-document mapping
449
     * metadata of the class with the given name.
450
     *
451
     * @param string $documentName The name of the document class the new instance is used for.
452
     */
453 945
    public function __construct($documentName)
454
    {
455 945
        $this->name = $documentName;
456 945
        $this->rootDocumentName = $documentName;
457 945
    }
458
459
    /**
460
     * {@inheritDoc}
461
     */
462 875
    public function getReflectionClass()
463
    {
464 875
        if ( ! $this->reflClass) {
465 2
            $this->reflClass = new \ReflectionClass($this->name);
466
        }
467
468 875
        return $this->reflClass;
469
    }
470
471
    /**
472
     * {@inheritDoc}
473
     */
474 308
    public function isIdentifier($fieldName)
475
    {
476 308
        return $this->identifier === $fieldName;
477
    }
478
479
    /**
480
     * INTERNAL:
481
     * Sets the mapped identifier field of this class.
482
     *
483
     * @param string $identifier
484
     */
485 346
    public function setIdentifier($identifier)
486
    {
487 346
        $this->identifier = $identifier;
488 346
    }
489
490
    /**
491
     * {@inheritDoc}
492
     *
493
     * Since MongoDB only allows exactly one identifier field
494
     * this will always return an array with only one value
495
     */
496 40
    public function getIdentifier()
497
    {
498 40
        return array($this->identifier);
499
    }
500
501
    /**
502
     * {@inheritDoc}
503
     *
504
     * Since MongoDB only allows exactly one identifier field
505
     * this will always return an array with only one value
506
     */
507 94
    public function getIdentifierFieldNames()
508
    {
509 94
        return array($this->identifier);
510
    }
511
512
    /**
513
     * {@inheritDoc}
514
     */
515 535
    public function hasField($fieldName)
516
    {
517 535
        return isset($this->fieldMappings[$fieldName]);
518
    }
519
520
    /**
521
     * Sets the inheritance type used by the class and it's subclasses.
522
     *
523
     * @param integer $type
524
     */
525 362
    public function setInheritanceType($type)
526
    {
527 362
        $this->inheritanceType = $type;
528 362
    }
529
530
    /**
531
     * Checks whether a mapped field is inherited from an entity superclass.
532
     *
533
     * @param  string $fieldName
534
     *
535
     * @return boolean TRUE if the field is inherited, FALSE otherwise.
536
     */
537 875
    public function isInheritedField($fieldName)
538
    {
539 875
        return isset($this->fieldMappings[$fieldName]['inherited']);
540
    }
541
542
    /**
543
     * Registers a custom repository class for the document class.
544
     *
545
     * @param string $repositoryClassName The class name of the custom repository.
546
     */
547 302 View Code Duplication
    public function setCustomRepositoryClass($repositoryClassName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
548
    {
549 302
        if ($this->isEmbeddedDocument) {
550
            return;
551
        }
552
553 302
        if ($repositoryClassName && strpos($repositoryClassName, '\\') === false && strlen($this->namespace)) {
554 3
            $repositoryClassName = $this->namespace . '\\' . $repositoryClassName;
555
        }
556
557 302
        $this->customRepositoryClassName = $repositoryClassName;
558 302
    }
559
560
    /**
561
     * Dispatches the lifecycle event of the given document by invoking all
562
     * registered callbacks.
563
     *
564
     * @param string $event     Lifecycle event
565
     * @param object $document  Document on which the event occurred
566
     * @param array  $arguments Arguments to pass to all callbacks
567
     * @throws \InvalidArgumentException if document class is not this class or
568
     *                                   a Proxy of this class
569
     */
570 640
    public function invokeLifecycleCallbacks($event, $document, array $arguments = null)
571
    {
572 640
        if ( ! $document instanceof $this->name) {
573 1
            throw new \InvalidArgumentException(sprintf('Expected document class "%s"; found: "%s"', $this->name, get_class($document)));
574
        }
575
576 639
        if (empty($this->lifecycleCallbacks[$event])) {
577 625
            return;
578
        }
579
580 185
        foreach ($this->lifecycleCallbacks[$event] as $callback) {
581 185
            if ($arguments !== null) {
582 184
                call_user_func_array(array($document, $callback), $arguments);
583
            } else {
584 185
                $document->$callback();
585
            }
586
        }
587 185
    }
588
589
    /**
590
     * Checks whether the class has callbacks registered for a lifecycle event.
591
     *
592
     * @param string $event Lifecycle event
593
     *
594
     * @return boolean
595
     */
596
    public function hasLifecycleCallbacks($event)
597
    {
598
        return ! empty($this->lifecycleCallbacks[$event]);
599
    }
600
601
    /**
602
     * Gets the registered lifecycle callbacks for an event.
603
     *
604
     * @param string $event
605
     * @return array
606
     */
607
    public function getLifecycleCallbacks($event)
608
    {
609
        return isset($this->lifecycleCallbacks[$event]) ? $this->lifecycleCallbacks[$event] : array();
610
    }
611
612
    /**
613
     * Adds a lifecycle callback for documents of this class.
614
     *
615
     * If the callback is already registered, this is a NOOP.
616
     *
617
     * @param string $callback
618
     * @param string $event
619
     */
620 281
    public function addLifecycleCallback($callback, $event)
621
    {
622 281
        if (isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event])) {
623 1
            return;
624
        }
625
626 281
        $this->lifecycleCallbacks[$event][] = $callback;
627 281
    }
628
629
    /**
630
     * Sets the lifecycle callbacks for documents of this class.
631
     *
632
     * Any previously registered callbacks are overwritten.
633
     *
634
     * @param array $callbacks
635
     */
636 345
    public function setLifecycleCallbacks(array $callbacks)
637
    {
638 345
        $this->lifecycleCallbacks = $callbacks;
639 345
    }
640
641
    /**
642
     * Registers a method for loading document data before field hydration.
643
     *
644
     * Note: A method may be registered multiple times for different fields.
645
     * it will be invoked only once for the first field found.
646
     *
647
     * @param string       $method Method name
648
     * @param array|string $fields Database field name(s)
649
     */
650 15
    public function registerAlsoLoadMethod($method, $fields)
651
    {
652 15
        $this->alsoLoadMethods[$method] = is_array($fields) ? $fields : array($fields);
653 15
    }
654
655
    /**
656
     * Sets the AlsoLoad methods for documents of this class.
657
     *
658
     * Any previously registered methods are overwritten.
659
     *
660
     * @param array $methods
661
     */
662 345
    public function setAlsoLoadMethods(array $methods)
663
    {
664 345
        $this->alsoLoadMethods = $methods;
665 345
    }
666
667
    /**
668
     * Sets the discriminator field.
669
     *
670
     * The field name is the the unmapped database field. Discriminator values
671
     * are only used to discern the hydration class and are not mapped to class
672
     * properties.
673
     *
674
     * @param string $discriminatorField
675
     *
676
     * @throws MappingException If the discriminator field conflicts with the
677
     *                          "name" attribute of a mapped field.
678
     */
679 371
    public function setDiscriminatorField($discriminatorField)
680
    {
681 371
        if ($discriminatorField === null) {
682 311
            $this->discriminatorField = null;
683
684 311
            return;
685
        }
686
687
        // Handle array argument with name/fieldName keys for BC
688 117
        if (is_array($discriminatorField)) {
689
            if (isset($discriminatorField['name'])) {
690
                $discriminatorField = $discriminatorField['name'];
691
            } elseif (isset($discriminatorField['fieldName'])) {
692
                $discriminatorField = $discriminatorField['fieldName'];
693
            }
694
        }
695
696 117
        foreach ($this->fieldMappings as $fieldMapping) {
697 4
            if ($discriminatorField == $fieldMapping['name']) {
698 4
                throw MappingException::discriminatorFieldConflict($this->name, $discriminatorField);
699
            }
700
        }
701
702 116
        $this->discriminatorField = $discriminatorField;
703 116
    }
704
705
    /**
706
     * Sets the discriminator values used by this class.
707
     * Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
708
     *
709
     * @param array $map
710
     *
711
     * @throws MappingException
712
     */
713 367
    public function setDiscriminatorMap(array $map)
714
    {
715 367
        foreach ($map as $value => $className) {
716 115
            if (strpos($className, '\\') === false && strlen($this->namespace)) {
717 83
                $className = $this->namespace . '\\' . $className;
718
            }
719 115
            $this->discriminatorMap[$value] = $className;
720 115
            if ($this->name == $className) {
721 107
                $this->discriminatorValue = $value;
722
            } else {
723 111
                if ( ! class_exists($className)) {
724
                    throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
725
                }
726 111
                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...
727 115
                    $this->subClasses[] = $className;
728
                }
729
            }
730
        }
731 367
    }
732
733
    /**
734
     * Sets the default discriminator value to be used for this class
735
     * Used for JOINED and SINGLE_TABLE inheritance mapping strategies if the document has no discriminator value
736
     *
737
     * @param string $defaultDiscriminatorValue
738
     *
739
     * @throws MappingException
740
     */
741 351
    public function setDefaultDiscriminatorValue($defaultDiscriminatorValue)
742
    {
743 351
        if ($defaultDiscriminatorValue === null) {
744 345
            $this->defaultDiscriminatorValue = null;
745
746 345
            return;
747
        }
748
749 59
        if (!array_key_exists($defaultDiscriminatorValue, $this->discriminatorMap)) {
750
            throw MappingException::invalidDiscriminatorValue($defaultDiscriminatorValue, $this->name);
751
        }
752
753 59
        $this->defaultDiscriminatorValue = $defaultDiscriminatorValue;
754 59
    }
755
756
    /**
757
     * Sets the discriminator value for this class.
758
     * Used for JOINED/SINGLE_TABLE inheritance and multiple document types in a single
759
     * collection.
760
     *
761
     * @param string $value
762
     */
763
    public function setDiscriminatorValue($value)
764
    {
765
        $this->discriminatorMap[$value] = $this->name;
766
        $this->discriminatorValue = $value;
767
    }
768
769
    /**
770
     * Sets the slaveOkay option applied to collections for this class.
771
     *
772
     * @param boolean|null $slaveOkay
773
     */
774 3
    public function setSlaveOkay($slaveOkay)
775
    {
776 3
        $this->slaveOkay = $slaveOkay === null ? null : (boolean) $slaveOkay;
777 3
    }
778
779
    /**
780
     * Add a index for this Document.
781
     *
782
     * @param array $keys Array of keys for the index.
783
     * @param array $options Array of options for the index.
784
     */
785 217
    public function addIndex($keys, array $options = array())
786
    {
787 217
        $this->indexes[] = array(
788 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...
789 217
                if ($value == 1 || $value == -1) {
790 60
                    return (int) $value;
791
                }
792 210
                if (is_string($value)) {
793 210
                    $lower = strtolower($value);
794 210
                    if ($lower === 'asc') {
795 203
                        return 1;
796 10
                    } elseif ($lower === 'desc') {
797 3
                        return -1;
798
                    }
799
                }
800 7
                return $value;
801 217
            }, $keys),
802 217
            'options' => $options
803
        );
804 217
    }
805
806
    /**
807
     * Set whether or not queries on this document should require indexes.
808
     *
809
     * @param bool $requireIndexes
810
     */
811 866
    public function setRequireIndexes($requireIndexes)
812
    {
813 866
        $this->requireIndexes = $requireIndexes;
814 866
    }
815
816
    /**
817
     * Returns the array of indexes for this Document.
818
     *
819
     * @return array $indexes The array of indexes.
820
     */
821 53
    public function getIndexes()
822
    {
823 53
        return $this->indexes;
824
    }
825
826
    /**
827
     * Checks whether this document has indexes or not.
828
     *
829
     * @return boolean
830
     */
831
    public function hasIndexes()
832
    {
833
        return $this->indexes ? true : false;
834
    }
835
836
    /**
837
     * Set shard key for this Document.
838
     *
839
     * @param array $keys Array of document keys.
840
     * @param array $options Array of sharding options.
841
     *
842
     * @throws MappingException
843
     */
844 85
    public function setShardKey(array $keys, array $options = array())
845
    {
846 85
        if ($this->inheritanceType === self::INHERITANCE_TYPE_SINGLE_COLLECTION && !is_null($this->shardKey)) {
847 2
            throw MappingException::shardKeyInSingleCollInheritanceSubclass($this->getName());
848
        }
849
850 85
        if ($this->isEmbeddedDocument) {
851 2
            throw MappingException::embeddedDocumentCantHaveShardKey($this->getName());
852
        }
853
854 83
        foreach (array_keys($keys) as $field) {
855 83
            if (! isset($this->fieldMappings[$field])) {
856 76
                continue;
857
            }
858
859 7
            if (in_array($this->fieldMappings[$field]['type'], ['many', 'collection'])) {
860 3
                throw MappingException::noMultiKeyShardKeys($this->getName(), $field);
861
            }
862
863 4
            if ($this->fieldMappings[$field]['strategy'] !== static::STORAGE_STRATEGY_SET) {
864 4
                throw MappingException::onlySetStrategyAllowedInShardKey($this->getName(), $field);
865
            }
866
        }
867
868 79
        $this->shardKey = array(
869 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...
870 79
                if ($value == 1 || $value == -1) {
871 6
                    return (int) $value;
872
                }
873 78
                if (is_string($value)) {
874 78
                    $lower = strtolower($value);
875 78
                    if ($lower === 'asc') {
876 78
                        return 1;
877 52
                    } elseif ($lower === 'desc') {
878
                        return -1;
879
                    }
880
                }
881 52
                return $value;
882 79
            }, $keys),
883 79
            'options' => $options
884
        );
885 79
    }
886
887
    /**
888
     * @return array
889
     */
890 28
    public function getShardKey()
891
    {
892 28
        return $this->shardKey;
893
    }
894
895
    /**
896
     * Checks whether this document has shard key or not.
897
     *
898
     * @return bool
899
     */
900 578
    public function isSharded()
901
    {
902 578
        return $this->shardKey ? true : false;
903
    }
904
905
    /**
906
     * Sets the write concern used by this class.
907
     *
908
     * @param string $writeConcern
909
     */
910 358
    public function setWriteConcern($writeConcern)
911
    {
912 358
        $this->writeConcern = $writeConcern;
913 358
    }
914
915
    /**
916
     * @return string
917
     */
918 12
    public function getWriteConcern()
919
    {
920 12
        return $this->writeConcern;
921
    }
922
923
    /**
924
     * Whether there is a write concern configured for this class.
925
     *
926
     * @return bool
927
     */
928 591
    public function hasWriteConcern()
929
    {
930 591
        return $this->writeConcern !== null;
931
    }
932
933
    /**
934
     * Sets the change tracking policy used by this class.
935
     *
936
     * @param integer $policy
937
     */
938 350
    public function setChangeTrackingPolicy($policy)
939
    {
940 350
        $this->changeTrackingPolicy = $policy;
941 350
    }
942
943
    /**
944
     * Whether the change tracking policy of this class is "deferred explicit".
945
     *
946
     * @return boolean
947
     */
948 66
    public function isChangeTrackingDeferredExplicit()
949
    {
950 66
        return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_EXPLICIT;
951
    }
952
953
    /**
954
     * Whether the change tracking policy of this class is "deferred implicit".
955
     *
956
     * @return boolean
957
     */
958 611
    public function isChangeTrackingDeferredImplicit()
959
    {
960 611
        return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_IMPLICIT;
961
    }
962
963
    /**
964
     * Whether the change tracking policy of this class is "notify".
965
     *
966
     * @return boolean
967
     */
968 346
    public function isChangeTrackingNotify()
969
    {
970 346
        return $this->changeTrackingPolicy == self::CHANGETRACKING_NOTIFY;
971
    }
972
973
    /**
974
     * Gets the ReflectionProperties of the mapped class.
975
     *
976
     * @return array An array of ReflectionProperty instances.
977
     */
978 94
    public function getReflectionProperties()
979
    {
980 94
        return $this->reflFields;
981
    }
982
983
    /**
984
     * Gets a ReflectionProperty for a specific field of the mapped class.
985
     *
986
     * @param string $name
987
     *
988
     * @return \ReflectionProperty
989
     */
990
    public function getReflectionProperty($name)
991
    {
992
        return $this->reflFields[$name];
993
    }
994
995
    /**
996
     * {@inheritDoc}
997
     */
998 881
    public function getName()
999
    {
1000 881
        return $this->name;
1001
    }
1002
1003
    /**
1004
     * The namespace this Document class belongs to.
1005
     *
1006
     * @return string $namespace The namespace name.
1007
     */
1008
    public function getNamespace()
1009
    {
1010
        return $this->namespace;
1011
    }
1012
1013
    /**
1014
     * Returns the database this Document is mapped to.
1015
     *
1016
     * @return string $db The database name.
1017
     */
1018 804
    public function getDatabase()
1019
    {
1020 804
        return $this->db;
1021
    }
1022
1023
    /**
1024
     * Set the database this Document is mapped to.
1025
     *
1026
     * @param string $db The database name
1027
     */
1028 94
    public function setDatabase($db)
1029
    {
1030 94
        $this->db = $db;
1031 94
    }
1032
1033
    /**
1034
     * Get the collection this Document is mapped to.
1035
     *
1036
     * @return string $collection The collection name.
1037
     */
1038 808
    public function getCollection()
1039
    {
1040 808
        return $this->collection;
1041
    }
1042
1043
    /**
1044
     * Sets the collection this Document is mapped to.
1045
     *
1046
     * @param array|string $name
1047
     *
1048
     * @throws \InvalidArgumentException
1049
     */
1050 909
    public function setCollection($name)
1051
    {
1052 909
        if (is_array($name)) {
1053
            if ( ! isset($name['name'])) {
1054
                throw new \InvalidArgumentException('A name key is required when passing an array to setCollection()');
1055
            }
1056
            $this->collectionCapped = isset($name['capped']) ? $name['capped'] : false;
1057
            $this->collectionSize = isset($name['size']) ? $name['size'] : 0;
1058
            $this->collectionMax = isset($name['max']) ? $name['max'] : 0;
1059
            $this->collection = $name['name'];
1060
        } else {
1061 909
            $this->collection = $name;
1062
        }
1063 909
    }
1064
1065
    /**
1066
     * Get whether or not the documents collection is capped.
1067
     *
1068
     * @return boolean
1069
     */
1070 4
    public function getCollectionCapped()
1071
    {
1072 4
        return $this->collectionCapped;
1073
    }
1074
1075
    /**
1076
     * Set whether or not the documents collection is capped.
1077
     *
1078
     * @param boolean $bool
1079
     */
1080 1
    public function setCollectionCapped($bool)
1081
    {
1082 1
        $this->collectionCapped = $bool;
1083 1
    }
1084
1085
    /**
1086
     * Get the collection size
1087
     *
1088
     * @return integer
1089
     */
1090 4
    public function getCollectionSize()
1091
    {
1092 4
        return $this->collectionSize;
1093
    }
1094
1095
    /**
1096
     * Set the collection size.
1097
     *
1098
     * @param integer $size
1099
     */
1100 1
    public function setCollectionSize($size)
1101
    {
1102 1
        $this->collectionSize = $size;
1103 1
    }
1104
1105
    /**
1106
     * Get the collection max.
1107
     *
1108
     * @return integer
1109
     */
1110 4
    public function getCollectionMax()
1111
    {
1112 4
        return $this->collectionMax;
1113
    }
1114
1115
    /**
1116
     * Set the collection max.
1117
     *
1118
     * @param integer $max
1119
     */
1120 1
    public function setCollectionMax($max)
1121
    {
1122 1
        $this->collectionMax = $max;
1123 1
    }
1124
1125
    /**
1126
     * Returns TRUE if this Document is mapped to a collection FALSE otherwise.
1127
     *
1128
     * @return boolean
1129
     */
1130
    public function isMappedToCollection()
1131
    {
1132
        return $this->collection ? true : false;
1133
    }
1134
1135
    /**
1136
     * Returns TRUE if this Document is a file to be stored on the MongoGridFS FALSE otherwise.
1137
     *
1138
     * @return boolean
1139
     */
1140 749
    public function isFile()
1141
    {
1142 749
        return $this->file ? true : false;
1143
    }
1144
1145
    /**
1146
     * Returns the file field name.
1147
     *
1148
     * @return string $file The file field name.
1149
     */
1150 345
    public function getFile()
1151
    {
1152 345
        return $this->file;
1153
    }
1154
1155
    /**
1156
     * Set the field name that stores the grid file.
1157
     *
1158
     * @param string $file
1159
     */
1160 346
    public function setFile($file)
1161
    {
1162 346
        $this->file = $file;
1163 346
    }
1164
1165
    /**
1166
     * Returns the distance field name.
1167
     *
1168
     * @return string $distance The distance field name.
1169
     */
1170
    public function getDistance()
1171
    {
1172
        return $this->distance;
1173
    }
1174
1175
    /**
1176
     * Set the field name that stores the distance.
1177
     *
1178
     * @param string $distance
1179
     */
1180 1
    public function setDistance($distance)
1181
    {
1182 1
        $this->distance = $distance;
1183 1
    }
1184
1185
    /**
1186
     * Map a field.
1187
     *
1188
     * @param array $mapping The mapping information.
1189
     *
1190
     * @return array
1191
     *
1192
     * @throws MappingException
1193
     */
1194 923
    public function mapField(array $mapping)
1195
    {
1196 923
        if ( ! isset($mapping['fieldName']) && isset($mapping['name'])) {
1197 9
            $mapping['fieldName'] = $mapping['name'];
1198
        }
1199 923
        if ( ! isset($mapping['fieldName'])) {
1200
            throw MappingException::missingFieldName($this->name);
1201
        }
1202 923
        if ( ! isset($mapping['name'])) {
1203 914
            $mapping['name'] = $mapping['fieldName'];
1204
        }
1205 923
        if ($this->identifier === $mapping['name'] && empty($mapping['id'])) {
1206 1
            throw MappingException::mustNotChangeIdentifierFieldsType($this->name, $mapping['name']);
1207
        }
1208 922
        if (isset($this->fieldMappings[$mapping['fieldName']])) {
1209
            //throw MappingException::duplicateFieldMapping($this->name, $mapping['fieldName']);
1210
        }
1211 922
        if ($this->discriminatorField !== null && $this->discriminatorField == $mapping['name']) {
1212 1
            throw MappingException::discriminatorFieldConflict($this->name, $this->discriminatorField);
1213
        }
1214 921 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...
1215 583
            $mapping['targetDocument'] = $this->namespace . '\\' . $mapping['targetDocument'];
1216
        }
1217 921
        if (isset($mapping['collectionClass'])) {
1218 64 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...
1219 62
                $mapping['collectionClass'] = $this->namespace . '\\' . $mapping['collectionClass'];
1220
            }
1221 64
            $mapping['collectionClass'] = ltrim($mapping['collectionClass'], '\\');
1222
        }
1223 921
        if ( ! empty($mapping['collectionClass'])) {
1224 64
            $rColl = new \ReflectionClass($mapping['collectionClass']);
1225 64
            if ( ! $rColl->implementsInterface('Doctrine\\Common\\Collections\\Collection')) {
1226 1
                throw MappingException::collectionClassDoesNotImplementCommonInterface($this->name, $mapping['fieldName'], $mapping['collectionClass']);
1227
            }
1228
        }
1229
1230 920
        if (isset($mapping['discriminatorMap'])) {
1231 122
            foreach ($mapping['discriminatorMap'] as $key => $class) {
1232 122 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...
1233 122
                    $mapping['discriminatorMap'][$key] = $this->namespace . '\\' . $class;
1234
                }
1235
            }
1236
        }
1237
1238 920
        if (isset($mapping['cascade']) && isset($mapping['embedded'])) {
1239 1
            throw MappingException::cascadeOnEmbeddedNotAllowed($this->name, $mapping['fieldName']);
1240
        }
1241
1242 919
        $cascades = isset($mapping['cascade']) ? array_map('strtolower', (array) $mapping['cascade']) : array();
1243
1244 919
        if (in_array('all', $cascades) || isset($mapping['embedded'])) {
1245 616
            $cascades = array('remove', 'persist', 'refresh', 'merge', 'detach');
1246
        }
1247
1248 919
        if (isset($mapping['embedded'])) {
1249 582
            unset($mapping['cascade']);
1250 914
        } elseif (isset($mapping['cascade'])) {
1251 377
            $mapping['cascade'] = $cascades;
1252
        }
1253
1254 919
        $mapping['isCascadeRemove'] = in_array('remove', $cascades);
1255 919
        $mapping['isCascadePersist'] = in_array('persist', $cascades);
1256 919
        $mapping['isCascadeRefresh'] = in_array('refresh', $cascades);
1257 919
        $mapping['isCascadeMerge'] = in_array('merge', $cascades);
1258 919
        $mapping['isCascadeDetach'] = in_array('detach', $cascades);
1259
1260 919
        if (isset($mapping['type']) && $mapping['type'] === 'file') {
1261 63
            $mapping['file'] = true;
1262
        }
1263 919
        if (isset($mapping['type']) && $mapping['type'] === 'increment') {
1264 1
            $mapping['strategy'] = self::STORAGE_STRATEGY_INCREMENT;
1265
        }
1266 919 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...
1267 63
            $this->file = $mapping['fieldName'];
1268 63
            $mapping['name'] = 'file';
1269
        }
1270 919 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...
1271 7
            $this->distance = $mapping['fieldName'];
1272
        }
1273 919
        if (isset($mapping['id']) && $mapping['id'] === true) {
1274 891
            $mapping['name'] = '_id';
1275 891
            $this->identifier = $mapping['fieldName'];
1276 891 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...
1277 874
                $this->generatorType = constant(ClassMetadata::class . '::GENERATOR_TYPE_' . strtoupper($mapping['strategy']));
1278
            }
1279 891
            $this->generatorOptions = isset($mapping['options']) ? $mapping['options'] : array();
1280 891
            switch ($this->generatorType) {
1281 891
                case self::GENERATOR_TYPE_AUTO:
1282 820
                    $mapping['type'] = 'id';
1283 820
                    break;
1284
                default:
1285 150
                    if ( ! empty($this->generatorOptions['type'])) {
1286 52
                        $mapping['type'] = $this->generatorOptions['type'];
1287 98
                    } elseif (empty($mapping['type'])) {
1288 84
                        $mapping['type'] = $this->generatorType === self::GENERATOR_TYPE_INCREMENT ? 'int_id' : 'custom_id';
1289
                    }
1290
            }
1291 891
            unset($this->generatorOptions['type']);
1292
        }
1293
1294 919
        if ( ! isset($mapping['nullable'])) {
1295 51
            $mapping['nullable'] = false;
1296
        }
1297
1298
        // Synchronize the "simple" and "storeAs" mapping information for backwards compatibility
1299 919
        if (isset($mapping['simple']) && ($mapping['simple'] === true || $mapping['simple'] === 'true')) {
1300 274
            $mapping['storeAs'] = ClassMetadataInfo::REFERENCE_STORE_AS_ID;
1301
        }
1302
        // Provide the correct value for the "simple" field for backwards compatibility
1303 919
        if (isset($mapping['storeAs'])) {
1304 550
            $mapping['simple'] = $mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID;
1305
        }
1306
1307 919
        if (isset($mapping['reference'])
1308 919
            && isset($mapping['storeAs'])
1309 919
            && $mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID
1310 919
            && ! isset($mapping['targetDocument'])
1311
        ) {
1312 3
            throw MappingException::simpleReferenceRequiresTargetDocument($this->name, $mapping['fieldName']);
1313
        }
1314
1315 916
        if (isset($mapping['reference']) && empty($mapping['targetDocument']) && empty($mapping['discriminatorMap']) &&
1316 916
                (isset($mapping['mappedBy']) || isset($mapping['inversedBy']))) {
1317 4
            throw MappingException::owningAndInverseReferencesRequireTargetDocument($this->name, $mapping['fieldName']);
1318
        }
1319
1320 912
        if ($this->isEmbeddedDocument && $mapping['type'] === 'many' && CollectionHelper::isAtomic($mapping['strategy'])) {
1321 1
            throw MappingException::atomicCollectionStrategyNotAllowed($mapping['strategy'], $this->name, $mapping['fieldName']);
1322
        }
1323
1324 911 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...
1325 486
            $mapping['association'] = self::REFERENCE_ONE;
1326
        }
1327 911 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...
1328 429
            $mapping['association'] = self::REFERENCE_MANY;
1329
        }
1330 911 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...
1331 443
            $mapping['association'] = self::EMBED_ONE;
1332
        }
1333 911 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...
1334 488
            $mapping['association'] = self::EMBED_MANY;
1335
        }
1336
1337 911
        if (isset($mapping['association']) && ! isset($mapping['targetDocument']) && ! isset($mapping['discriminatorField'])) {
1338 131
            $mapping['discriminatorField'] = self::DEFAULT_DISCRIMINATOR_FIELD;
1339
        }
1340
1341
        /*
1342
        if (isset($mapping['type']) && ($mapping['type'] === 'one' || $mapping['type'] === 'many')) {
1343
            $mapping['type'] = $mapping['type'] === 'one' ? self::ONE : self::MANY;
1344
        }
1345
        */
1346 911
        if (isset($mapping['version'])) {
1347 99
            $mapping['notSaved'] = true;
1348 99
            $this->setVersionMapping($mapping);
1349
        }
1350 911
        if (isset($mapping['lock'])) {
1351 26
            $mapping['notSaved'] = true;
1352 26
            $this->setLockMapping($mapping);
1353
        }
1354 911
        $mapping['isOwningSide'] = true;
1355 911
        $mapping['isInverseSide'] = false;
1356 911
        if (isset($mapping['reference'])) {
1357 555 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...
1358 80
                $mapping['isOwningSide'] = true;
1359 80
                $mapping['isInverseSide'] = false;
1360
            }
1361 555 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...
1362 274
                $mapping['isInverseSide'] = true;
1363 274
                $mapping['isOwningSide'] = false;
1364
            }
1365 555 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...
1366 60
                $mapping['isInverseSide'] = true;
1367 60
                $mapping['isOwningSide'] = false;
1368
            }
1369 555
            if (!isset($mapping['orphanRemoval'])) {
1370 533
                $mapping['orphanRemoval'] = false;
1371
            }
1372
        }
1373
1374 911
        $this->applyStorageStrategy($mapping);
1375
1376 910
        $this->fieldMappings[$mapping['fieldName']] = $mapping;
1377 910
        if (isset($mapping['association'])) {
1378 705
            $this->associationMappings[$mapping['fieldName']] = $mapping;
1379
        }
1380
1381 910
        return $mapping;
1382
    }
1383
1384
    /**
1385
     * Validates the storage strategy of a mapping for consistency
1386
     * @param array $mapping
1387
     * @throws \Doctrine\ODM\MongoDB\Mapping\MappingException
1388
     */
1389 911
    private function applyStorageStrategy(array &$mapping)
1390
    {
1391 911
        if (! isset($mapping['type']) || isset($mapping['id'])) {
1392 893
            return;
1393
        }
1394
1395
        switch (true) {
1396 873
            case $mapping['type'] == 'int':
1397 872
            case $mapping['type'] == 'float':
1398 872
            case $mapping['type'] == 'increment':
1399 317
                $defaultStrategy = self::STORAGE_STRATEGY_SET;
1400 317
                $allowedStrategies = [self::STORAGE_STRATEGY_SET, self::STORAGE_STRATEGY_INCREMENT];
1401 317
                break;
1402
1403 871
            case $mapping['type'] == 'many':
1404 586
                $defaultStrategy = CollectionHelper::DEFAULT_STRATEGY;
1405
                $allowedStrategies = [
1406 586
                    self::STORAGE_STRATEGY_PUSH_ALL,
1407 586
                    self::STORAGE_STRATEGY_ADD_TO_SET,
1408 586
                    self::STORAGE_STRATEGY_SET,
1409 586
                    self::STORAGE_STRATEGY_SET_ARRAY,
1410 586
                    self::STORAGE_STRATEGY_ATOMIC_SET,
1411 586
                    self::STORAGE_STRATEGY_ATOMIC_SET_ARRAY,
1412
                ];
1413 586
                break;
1414
1415
            default:
1416 861
                $defaultStrategy = self::STORAGE_STRATEGY_SET;
1417 861
                $allowedStrategies = [self::STORAGE_STRATEGY_SET];
1418
        }
1419
1420 873
        if (! isset($mapping['strategy'])) {
1421 864
            $mapping['strategy'] = $defaultStrategy;
1422
        }
1423
1424 873
        if (! in_array($mapping['strategy'], $allowedStrategies)) {
1425
            throw MappingException::invalidStorageStrategy($this->name, $mapping['fieldName'], $mapping['type'], $mapping['strategy']);
1426
        }
1427
1428 873
        if (isset($mapping['reference']) && $mapping['type'] === 'many' && $mapping['isOwningSide']
1429 873
            && ! empty($mapping['sort']) && ! CollectionHelper::usesSet($mapping['strategy'])) {
1430 1
            throw MappingException::referenceManySortMustNotBeUsedWithNonSetCollectionStrategy($this->name, $mapping['fieldName'], $mapping['strategy']);
1431
        }
1432 872
    }
1433
1434
    /**
1435
     * Map a MongoGridFSFile.
1436
     *
1437
     * @param array $mapping The mapping information.
1438
     */
1439
    public function mapFile(array $mapping)
1440
    {
1441
        $mapping['file'] = true;
1442
        $mapping['type'] = 'file';
1443
        $this->mapField($mapping);
1444
    }
1445
1446
    /**
1447
     * Map a single embedded document.
1448
     *
1449
     * @param array $mapping The mapping information.
1450
     */
1451 6
    public function mapOneEmbedded(array $mapping)
1452
    {
1453 6
        $mapping['embedded'] = true;
1454 6
        $mapping['type'] = 'one';
1455 6
        $this->mapField($mapping);
1456 5
    }
1457
1458
    /**
1459
     * Map a collection of embedded documents.
1460
     *
1461
     * @param array $mapping The mapping information.
1462
     */
1463 5
    public function mapManyEmbedded(array $mapping)
1464
    {
1465 5
        $mapping['embedded'] = true;
1466 5
        $mapping['type'] = 'many';
1467 5
        $this->mapField($mapping);
1468 5
    }
1469
1470
    /**
1471
     * Map a single document reference.
1472
     *
1473
     * @param array $mapping The mapping information.
1474
     */
1475 8
    public function mapOneReference(array $mapping)
1476
    {
1477 8
        $mapping['reference'] = true;
1478 8
        $mapping['type'] = 'one';
1479 8
        $this->mapField($mapping);
1480 8
    }
1481
1482
    /**
1483
     * Map a collection of document references.
1484
     *
1485
     * @param array $mapping The mapping information.
1486
     */
1487 8
    public function mapManyReference(array $mapping)
1488
    {
1489 8
        $mapping['reference'] = true;
1490 8
        $mapping['type'] = 'many';
1491 8
        $this->mapField($mapping);
1492 8
    }
1493
1494
    /**
1495
     * INTERNAL:
1496
     * Adds a field mapping without completing/validating it.
1497
     * This is mainly used to add inherited field mappings to derived classes.
1498
     *
1499
     * @param array $fieldMapping
1500
     */
1501 120
    public function addInheritedFieldMapping(array $fieldMapping)
1502
    {
1503 120
        $this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping;
1504
1505 120
        if (isset($fieldMapping['association'])) {
1506 76
            $this->associationMappings[$fieldMapping['fieldName']] = $fieldMapping;
1507
        }
1508 120
    }
1509
1510
    /**
1511
     * INTERNAL:
1512
     * Adds an association mapping without completing/validating it.
1513
     * This is mainly used to add inherited association mappings to derived classes.
1514
     *
1515
     * @param array $mapping
1516
     *
1517
     * @return void
1518
     *
1519
     * @throws MappingException
1520
     */
1521 77
    public function addInheritedAssociationMapping(array $mapping/*, $owningClassName = null*/)
1522
    {
1523 77
        $this->associationMappings[$mapping['fieldName']] = $mapping;
1524 77
    }
1525
1526
    /**
1527
     * Checks whether the class has a mapped association with the given field name.
1528
     *
1529
     * @param string $fieldName
1530
     * @return boolean
1531
     */
1532 7
    public function hasReference($fieldName)
1533
    {
1534 7
        return isset($this->fieldMappings[$fieldName]['reference']);
1535
    }
1536
1537
    /**
1538
     * Checks whether the class has a mapped embed with the given field name.
1539
     *
1540
     * @param string $fieldName
1541
     * @return boolean
1542
     */
1543 5
    public function hasEmbed($fieldName)
1544
    {
1545 5
        return isset($this->fieldMappings[$fieldName]['embedded']);
1546
    }
1547
1548
    /**
1549
     * {@inheritDoc}
1550
     *
1551
     * Checks whether the class has a mapped association (embed or reference) with the given field name.
1552
     */
1553 7
    public function hasAssociation($fieldName)
1554
    {
1555 7
        return $this->hasReference($fieldName) || $this->hasEmbed($fieldName);
1556
    }
1557
1558
    /**
1559
     * {@inheritDoc}
1560
     *
1561
     * Checks whether the class has a mapped reference or embed for the specified field and
1562
     * is a single valued association.
1563
     */
1564
    public function isSingleValuedAssociation($fieldName)
1565
    {
1566
        return $this->isSingleValuedReference($fieldName) || $this->isSingleValuedEmbed($fieldName);
1567
    }
1568
1569
    /**
1570
     * {@inheritDoc}
1571
     *
1572
     * Checks whether the class has a mapped reference or embed for the specified field and
1573
     * is a collection valued association.
1574
     */
1575
    public function isCollectionValuedAssociation($fieldName)
1576
    {
1577
        return $this->isCollectionValuedReference($fieldName) || $this->isCollectionValuedEmbed($fieldName);
1578
    }
1579
1580
    /**
1581
     * Checks whether the class has a mapped association for the specified field
1582
     * and if yes, checks whether it is a single-valued association (to-one).
1583
     *
1584
     * @param string $fieldName
1585
     * @return boolean TRUE if the association exists and is single-valued, FALSE otherwise.
1586
     */
1587
    public function isSingleValuedReference($fieldName)
1588
    {
1589
        return isset($this->fieldMappings[$fieldName]['association']) &&
1590
            $this->fieldMappings[$fieldName]['association'] === self::REFERENCE_ONE;
1591
    }
1592
1593
    /**
1594
     * Checks whether the class has a mapped association for the specified field
1595
     * and if yes, checks whether it is a collection-valued association (to-many).
1596
     *
1597
     * @param string $fieldName
1598
     * @return boolean TRUE if the association exists and is collection-valued, FALSE otherwise.
1599
     */
1600
    public function isCollectionValuedReference($fieldName)
1601
    {
1602
        return isset($this->fieldMappings[$fieldName]['association']) &&
1603
            $this->fieldMappings[$fieldName]['association'] === self::REFERENCE_MANY;
1604
    }
1605
1606
    /**
1607
     * Checks whether the class has a mapped embedded document for the specified field
1608
     * and if yes, checks whether it is a single-valued association (to-one).
1609
     *
1610
     * @param string $fieldName
1611
     * @return boolean TRUE if the association exists and is single-valued, FALSE otherwise.
1612
     */
1613
    public function isSingleValuedEmbed($fieldName)
1614
    {
1615
        return isset($this->fieldMappings[$fieldName]['association']) &&
1616
            $this->fieldMappings[$fieldName]['association'] === self::EMBED_ONE;
1617
    }
1618
1619
    /**
1620
     * Checks whether the class has a mapped embedded document for the specified field
1621
     * and if yes, checks whether it is a collection-valued association (to-many).
1622
     *
1623
     * @param string $fieldName
1624
     * @return boolean TRUE if the association exists and is collection-valued, FALSE otherwise.
1625
     */
1626
    public function isCollectionValuedEmbed($fieldName)
1627
    {
1628
        return isset($this->fieldMappings[$fieldName]['association']) &&
1629
            $this->fieldMappings[$fieldName]['association'] === self::EMBED_MANY;
1630
    }
1631
1632
    /**
1633
     * Sets the ID generator used to generate IDs for instances of this class.
1634
     *
1635
     * @param \Doctrine\ODM\MongoDB\Id\AbstractIdGenerator $generator
1636
     */
1637 815
    public function setIdGenerator($generator)
1638
    {
1639 815
        $this->idGenerator = $generator;
1640 815
    }
1641
1642
    /**
1643
     * Casts the identifier to its portable PHP type.
1644
     *
1645
     * @param mixed $id
1646
     * @return mixed $id
1647
     */
1648 627
    public function getPHPIdentifierValue($id)
1649
    {
1650 627
        $idType = $this->fieldMappings[$this->identifier]['type'];
1651 627
        return Type::getType($idType)->convertToPHPValue($id);
1652
    }
1653
1654
    /**
1655
     * Casts the identifier to its database type.
1656
     *
1657
     * @param mixed $id
1658
     * @return mixed $id
1659
     */
1660 694
    public function getDatabaseIdentifierValue($id)
1661
    {
1662 694
        $idType = $this->fieldMappings[$this->identifier]['type'];
1663 694
        return Type::getType($idType)->convertToDatabaseValue($id);
1664
    }
1665
1666
    /**
1667
     * Sets the document identifier of a document.
1668
     *
1669
     * The value will be converted to a PHP type before being set.
1670
     *
1671
     * @param object $document
1672
     * @param mixed $id
1673
     */
1674 558
    public function setIdentifierValue($document, $id)
1675
    {
1676 558
        $id = $this->getPHPIdentifierValue($id);
1677 558
        $this->reflFields[$this->identifier]->setValue($document, $id);
1678 558
    }
1679
1680
    /**
1681
     * Gets the document identifier as a PHP type.
1682
     *
1683
     * @param object $document
1684
     * @return mixed $id
1685
     */
1686 645
    public function getIdentifierValue($document)
1687
    {
1688 645
        return $this->reflFields[$this->identifier]->getValue($document);
1689
    }
1690
1691
    /**
1692
     * {@inheritDoc}
1693
     *
1694
     * Since MongoDB only allows exactly one identifier field this is a proxy
1695
     * to {@see getIdentifierValue()} and returns an array with the identifier
1696
     * field as a key.
1697
     */
1698
    public function getIdentifierValues($object)
1699
    {
1700
        return array($this->identifier => $this->getIdentifierValue($object));
1701
    }
1702
1703
    /**
1704
     * Get the document identifier object as a database type.
1705
     *
1706
     * @param object $document
1707
     *
1708
     * @return \MongoId $id The MongoID object.
1709
     */
1710 34
    public function getIdentifierObject($document)
1711
    {
1712 34
        return $this->getDatabaseIdentifierValue($this->getIdentifierValue($document));
1713
    }
1714
1715
    /**
1716
     * Sets the specified field to the specified value on the given document.
1717
     *
1718
     * @param object $document
1719
     * @param string $field
1720
     * @param mixed $value
1721
     */
1722 8
    public function setFieldValue($document, $field, $value)
1723
    {
1724 8
        if ($document instanceof Proxy && ! $document->__isInitialized()) {
1725
            //property changes to an uninitialized proxy will not be tracked or persisted,
1726
            //so the proxy needs to be loaded first.
1727 1
            $document->__load();
1728
        }
1729
1730 8
        $this->reflFields[$field]->setValue($document, $value);
1731 8
    }
1732
1733
    /**
1734
     * Gets the specified field's value off the given document.
1735
     *
1736
     * @param object $document
1737
     * @param string $field
1738
     *
1739
     * @return mixed
1740
     */
1741 27
    public function getFieldValue($document, $field)
1742
    {
1743 27
        if ($document instanceof Proxy && $field !== $this->identifier && ! $document->__isInitialized()) {
1744 1
            $document->__load();
1745
        }
1746
1747 27
        return $this->reflFields[$field]->getValue($document);
1748
    }
1749
1750
    /**
1751
     * Gets the mapping of a field.
1752
     *
1753
     * @param string $fieldName  The field name.
1754
     *
1755
     * @return array  The field mapping.
1756
     *
1757
     * @throws MappingException if the $fieldName is not found in the fieldMappings array
1758
     */
1759 95
    public function getFieldMapping($fieldName)
1760
    {
1761 95
        if ( ! isset($this->fieldMappings[$fieldName])) {
1762 6
            throw MappingException::mappingNotFound($this->name, $fieldName);
1763
        }
1764 93
        return $this->fieldMappings[$fieldName];
1765
    }
1766
1767
    /**
1768
     * Gets mappings of fields holding embedded document(s).
1769
     *
1770
     * @return array of field mappings
1771
     */
1772 603
    public function getEmbeddedFieldsMappings()
1773
    {
1774 603
        return array_filter(
1775 603
            $this->associationMappings,
1776
            function($assoc) { return ! empty($assoc['embedded']); }
1777
        );
1778
    }
1779
1780
    /**
1781
     * Gets the field mapping by its DB name.
1782
     * E.g. it returns identifier's mapping when called with _id.
1783
     *
1784
     * @param string $dbFieldName
1785
     *
1786
     * @return array
1787
     * @throws MappingException
1788
     */
1789 9
    public function getFieldMappingByDbFieldName($dbFieldName)
1790
    {
1791 9
        foreach ($this->fieldMappings as $mapping) {
1792 9
            if ($mapping['name'] == $dbFieldName) {
1793 9
                return $mapping;
1794
            }
1795
        }
1796
1797
        throw MappingException::mappingNotFoundByDbName($this->name, $dbFieldName);
1798
    }
1799
1800
    /**
1801
     * Check if the field is not null.
1802
     *
1803
     * @param string $fieldName  The field name
1804
     *
1805
     * @return boolean  TRUE if the field is not null, FALSE otherwise.
1806
     */
1807 1
    public function isNullable($fieldName)
1808
    {
1809 1
        $mapping = $this->getFieldMapping($fieldName);
1810 1
        if ($mapping !== false) {
1811 1
            return isset($mapping['nullable']) && $mapping['nullable'] == true;
1812
        }
1813
        return false;
1814
    }
1815
1816
    /**
1817
     * Checks whether the document has a discriminator field and value configured.
1818
     *
1819
     * @return boolean
1820
     */
1821 499
    public function hasDiscriminator()
1822
    {
1823 499
        return isset($this->discriminatorField, $this->discriminatorValue);
1824
    }
1825
1826
    /**
1827
     * Sets the type of Id generator to use for the mapped class.
1828
     *
1829
     * @param string $generatorType Generator type.
1830
     */
1831 351
    public function setIdGeneratorType($generatorType)
1832
    {
1833 351
        $this->generatorType = $generatorType;
1834 351
    }
1835
1836
    /**
1837
     * Sets the Id generator options.
1838
     *
1839
     * @param array $generatorOptions Generator options.
1840
     */
1841
    public function setIdGeneratorOptions($generatorOptions)
1842
    {
1843
        $this->generatorOptions = $generatorOptions;
1844
    }
1845
1846
    /**
1847
     * @return boolean
1848
     */
1849 609
    public function isInheritanceTypeNone()
1850
    {
1851 609
        return $this->inheritanceType == self::INHERITANCE_TYPE_NONE;
1852
    }
1853
1854
    /**
1855
     * Checks whether the mapped class uses the SINGLE_COLLECTION inheritance mapping strategy.
1856
     *
1857
     * @return boolean
1858
     */
1859 344
    public function isInheritanceTypeSingleCollection()
1860
    {
1861 344
        return $this->inheritanceType == self::INHERITANCE_TYPE_SINGLE_COLLECTION;
1862
    }
1863
1864
    /**
1865
     * Checks whether the mapped class uses the COLLECTION_PER_CLASS inheritance mapping strategy.
1866
     *
1867
     * @return boolean
1868
     */
1869
    public function isInheritanceTypeCollectionPerClass()
1870
    {
1871
        return $this->inheritanceType == self::INHERITANCE_TYPE_COLLECTION_PER_CLASS;
1872
    }
1873
1874
    /**
1875
     * Sets the mapped subclasses of this class.
1876
     *
1877
     * @param string[] $subclasses The names of all mapped subclasses.
1878
     */
1879 2 View Code Duplication
    public function setSubclasses(array $subclasses)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
1880
    {
1881 2
        foreach ($subclasses as $subclass) {
1882 2
            if (strpos($subclass, '\\') === false && strlen($this->namespace)) {
1883 1
                $this->subClasses[] = $this->namespace . '\\' . $subclass;
1884
            } else {
1885 2
                $this->subClasses[] = $subclass;
1886
            }
1887
        }
1888 2
    }
1889
1890
    /**
1891
     * Sets the parent class names.
1892
     * Assumes that the class names in the passed array are in the order:
1893
     * directParent -> directParentParent -> directParentParentParent ... -> root.
1894
     *
1895
     * @param string[] $classNames
1896
     */
1897 872
    public function setParentClasses(array $classNames)
1898
    {
1899 872
        $this->parentClasses = $classNames;
1900
1901 872
        if (count($classNames) > 0) {
1902 104
            $this->rootDocumentName = array_pop($classNames);
1903
        }
1904 872
    }
1905
1906
    /**
1907
     * Checks whether the class will generate a new \MongoId instance for us.
1908
     *
1909
     * @return boolean TRUE if the class uses the AUTO generator, FALSE otherwise.
1910
     */
1911
    public function isIdGeneratorAuto()
1912
    {
1913
        return $this->generatorType == self::GENERATOR_TYPE_AUTO;
1914
    }
1915
1916
    /**
1917
     * Checks whether the class will use a collection to generate incremented identifiers.
1918
     *
1919
     * @return boolean TRUE if the class uses the INCREMENT generator, FALSE otherwise.
1920
     */
1921
    public function isIdGeneratorIncrement()
1922
    {
1923
        return $this->generatorType == self::GENERATOR_TYPE_INCREMENT;
1924
    }
1925
1926
    /**
1927
     * Checks whether the class will generate a uuid id.
1928
     *
1929
     * @return boolean TRUE if the class uses the UUID generator, FALSE otherwise.
1930
     */
1931
    public function isIdGeneratorUuid()
1932
    {
1933
        return $this->generatorType == self::GENERATOR_TYPE_UUID;
1934
    }
1935
1936
    /**
1937
     * Checks whether the class uses no id generator.
1938
     *
1939
     * @return boolean TRUE if the class does not use any id generator, FALSE otherwise.
1940
     */
1941
    public function isIdGeneratorNone()
1942
    {
1943
        return $this->generatorType == self::GENERATOR_TYPE_NONE;
1944
    }
1945
1946
    /**
1947
     * Sets the version field mapping used for versioning. Sets the default
1948
     * value to use depending on the column type.
1949
     *
1950
     * @param array $mapping   The version field mapping array
1951
     *
1952
     * @throws LockException
1953
     */
1954 99
    public function setVersionMapping(array &$mapping)
1955
    {
1956 99
        if ($mapping['type'] !== 'int' && $mapping['type'] !== 'date') {
1957 1
            throw LockException::invalidVersionFieldType($mapping['type']);
1958
        }
1959
1960 98
        $this->isVersioned  = true;
1961 98
        $this->versionField = $mapping['fieldName'];
1962 98
    }
1963
1964
    /**
1965
     * Sets whether this class is to be versioned for optimistic locking.
1966
     *
1967
     * @param boolean $bool
1968
     */
1969 345
    public function setVersioned($bool)
1970
    {
1971 345
        $this->isVersioned = $bool;
1972 345
    }
1973
1974
    /**
1975
     * Sets the name of the field that is to be used for versioning if this class is
1976
     * versioned for optimistic locking.
1977
     *
1978
     * @param string $versionField
1979
     */
1980 345
    public function setVersionField($versionField)
1981
    {
1982 345
        $this->versionField = $versionField;
1983 345
    }
1984
1985
    /**
1986
     * Sets the version field mapping used for versioning. Sets the default
1987
     * value to use depending on the column type.
1988
     *
1989
     * @param array $mapping   The version field mapping array
1990
     *
1991
     * @throws \Doctrine\ODM\MongoDB\LockException
1992
     */
1993 26
    public function setLockMapping(array &$mapping)
1994
    {
1995 26
        if ($mapping['type'] !== 'int') {
1996 1
            throw LockException::invalidLockFieldType($mapping['type']);
1997
        }
1998
1999 25
        $this->isLockable = true;
2000 25
        $this->lockField = $mapping['fieldName'];
2001 25
    }
2002
2003
    /**
2004
     * Sets whether this class is to allow pessimistic locking.
2005
     *
2006
     * @param boolean $bool
2007
     */
2008
    public function setLockable($bool)
2009
    {
2010
        $this->isLockable = $bool;
2011
    }
2012
2013
    /**
2014
     * Sets the name of the field that is to be used for storing whether a document
2015
     * is currently locked or not.
2016
     *
2017
     * @param string $lockField
2018
     */
2019
    public function setLockField($lockField)
2020
    {
2021
        $this->lockField = $lockField;
2022
    }
2023
2024
    /**
2025
     * {@inheritDoc}
2026
     */
2027
    public function getFieldNames()
2028
    {
2029
        return array_keys($this->fieldMappings);
2030
    }
2031
2032
    /**
2033
     * {@inheritDoc}
2034
     */
2035
    public function getAssociationNames()
2036
    {
2037
        return array_keys($this->associationMappings);
2038
    }
2039
2040
    /**
2041
     * {@inheritDoc}
2042
     */
2043 22
    public function getTypeOfField($fieldName)
2044
    {
2045 22
        return isset($this->fieldMappings[$fieldName]) ?
2046 22
            $this->fieldMappings[$fieldName]['type'] : null;
2047
    }
2048
2049
    /**
2050
     * {@inheritDoc}
2051
     */
2052 6
    public function getAssociationTargetClass($assocName)
2053
    {
2054 6
        if ( ! isset($this->associationMappings[$assocName])) {
2055 3
            throw new InvalidArgumentException("Association name expected, '" . $assocName . "' is not an association.");
2056
        }
2057
2058 3
        return $this->associationMappings[$assocName]['targetDocument'];
2059
    }
2060
2061
    /**
2062
     * Retrieve the collectionClass associated with an association
2063
     *
2064
     * @param string $assocName
2065
     */
2066 2
    public function getAssociationCollectionClass($assocName)
2067
    {
2068 2
        if ( ! isset($this->associationMappings[$assocName])) {
2069
            throw new InvalidArgumentException("Association name expected, '" . $assocName . "' is not an association.");
2070
        }
2071
2072 2
        if ( ! array_key_exists('collectionClass', $this->associationMappings[$assocName])) {
2073
            throw new InvalidArgumentException("collectionClass can only be applied to 'embedMany' and 'referenceMany' associations.");
2074
        }
2075
2076 2
        return $this->associationMappings[$assocName]['collectionClass'];
2077
    }
2078
2079
    /**
2080
     * {@inheritDoc}
2081
     */
2082
    public function isAssociationInverseSide($fieldName)
2083
    {
2084
        throw new \BadMethodCallException(__METHOD__ . '() is not implemented yet.');
2085
    }
2086
2087
    /**
2088
     * {@inheritDoc}
2089
     */
2090
    public function getAssociationMappedByTargetField($fieldName)
2091
    {
2092
        throw new \BadMethodCallException(__METHOD__ . '() is not implemented yet.');
2093
    }
2094
}
2095