Completed
Pull Request — master (#1566)
by Andreas
08:59
created

ClassMetadataInfo::setShardKey()   C

Complexity

Conditions 13
Paths 7

Size

Total Lines 42
Code Lines 25

Duplication

Lines 14
Ratio 33.33 %

Code Coverage

Tests 24
CRAP Score 13.0108

Importance

Changes 0
Metric Value
dl 14
loc 42
ccs 24
cts 25
cp 0.96
rs 5.1234
c 0
b 0
f 0
cc 13
eloc 25
nc 7
nop 2
crap 13.0108

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
    const REFERENCE_STORE_AS_REF = 'ref';
107
    const REFERENCE_STORE_AS_REF_WITH_DB = 'refWithDb';
108
109
    /* The inheritance mapping types */
110
    /**
111
     * NONE means the class does not participate in an inheritance hierarchy
112
     * and therefore does not need an inheritance mapping type.
113
     */
114
    const INHERITANCE_TYPE_NONE = 1;
115
116
    /**
117
     * SINGLE_COLLECTION means the class will be persisted according to the rules of
118
     * <tt>Single Collection Inheritance</tt>.
119
     */
120
    const INHERITANCE_TYPE_SINGLE_COLLECTION = 2;
121
122
    /**
123
     * COLLECTION_PER_CLASS means the class will be persisted according to the rules
124
     * of <tt>Concrete Collection Inheritance</tt>.
125
     */
126
    const INHERITANCE_TYPE_COLLECTION_PER_CLASS = 3;
127
128
    /**
129
     * DEFERRED_IMPLICIT means that changes of entities are calculated at commit-time
130
     * by doing a property-by-property comparison with the original data. This will
131
     * be done for all entities that are in MANAGED state at commit-time.
132
     *
133
     * This is the default change tracking policy.
134
     */
135
    const CHANGETRACKING_DEFERRED_IMPLICIT = 1;
136
137
    /**
138
     * DEFERRED_EXPLICIT means that changes of entities are calculated at commit-time
139
     * by doing a property-by-property comparison with the original data. This will
140
     * be done only for entities that were explicitly saved (through persist() or a cascade).
141
     */
142
    const CHANGETRACKING_DEFERRED_EXPLICIT = 2;
143
144
    /**
145
     * NOTIFY means that Doctrine relies on the entities sending out notifications
146
     * when their properties change. Such entity classes must implement
147
     * the <tt>NotifyPropertyChanged</tt> interface.
148
     */
149
    const CHANGETRACKING_NOTIFY = 3;
150
151
    /**
152
     * SET means that fields will be written to the database using a $set operator
153
     */
154
    const STORAGE_STRATEGY_SET = 'set';
155
156
    /**
157
     * INCREMENT means that fields will be written to the database by calculating
158
     * the difference and using the $inc operator
159
     */
160
    const STORAGE_STRATEGY_INCREMENT = 'increment';
161
162
    const STORAGE_STRATEGY_PUSH_ALL = 'pushAll';
163
    const STORAGE_STRATEGY_ADD_TO_SET = 'addToSet';
164
    const STORAGE_STRATEGY_ATOMIC_SET = 'atomicSet';
165
    const STORAGE_STRATEGY_ATOMIC_SET_ARRAY = 'atomicSetArray';
166
    const STORAGE_STRATEGY_SET_ARRAY = 'setArray';
167
168
    /**
169
     * READ-ONLY: The name of the mongo database the document is mapped to.
170
     */
171
    public $db;
172
173
    /**
174
     * READ-ONLY: The name of the mongo collection the document is mapped to.
175
     */
176
    public $collection;
177
178
    /**
179
     * READ-ONLY: If the collection should be a fixed size.
180
     */
181
    public $collectionCapped;
182
183
    /**
184
     * READ-ONLY: If the collection is fixed size, its size in bytes.
185
     */
186
    public $collectionSize;
187
188
    /**
189
     * READ-ONLY: If the collection is fixed size, the maximum number of elements to store in the collection.
190
     */
191
    public $collectionMax;
192
193
    /**
194
     * READ-ONLY: Describes the level of acknowledgement requested from MongoDB for write operations.
195
     */
196
    public $writeConcern;
197
198
    /**
199
     * READ-ONLY: The field name of the document identifier.
200
     */
201
    public $identifier;
202
203
    /**
204
     * READ-ONLY: The field that stores a file reference and indicates the
205
     * document is a file and should be stored on the MongoGridFS.
206
     */
207
    public $file;
208
209
    /**
210
     * READ-ONLY: The field that stores the calculated distance when performing geo spatial
211
     * queries.
212
     */
213
    public $distance;
214
215
    /**
216
     * READ-ONLY: Whether or not reads for this class are okay to read from a slave.
217
     *
218
     * @deprecated in version 1.2 and will be removed in 2.0.
219
     */
220
    public $slaveOkay;
221
222
    /**
223
     * READ-ONLY: The array of indexes for the document collection.
224
     */
225
    public $indexes = array();
226
227
    /**
228
     * READ-ONLY: Keys and options describing shard key. Only for sharded collections.
229
     */
230
    public $shardKey;
231
232
    /**
233
     * READ-ONLY: Whether or not queries on this document should require indexes.
234
     *
235
     * @deprecated property was deprecated in 1.2 and will be removed in 2.0
236
     */
237
    public $requireIndexes = false;
238
239
    /**
240
     * READ-ONLY: The name of the document class.
241
     */
242
    public $name;
243
244
    /**
245
     * READ-ONLY: The namespace the document class is contained in.
246
     *
247
     * @var string
248
     * @todo Not really needed. Usage could be localized.
249
     */
250
    public $namespace;
251
252
    /**
253
     * READ-ONLY: The name of the document class that is at the root of the mapped document inheritance
254
     * hierarchy. If the document is not part of a mapped inheritance hierarchy this is the same
255
     * as {@link $documentName}.
256
     *
257
     * @var string
258
     */
259
    public $rootDocumentName;
260
261
    /**
262
     * The name of the custom repository class used for the document class.
263
     * (Optional).
264
     *
265
     * @var string
266
     */
267
    public $customRepositoryClassName;
268
269
    /**
270
     * READ-ONLY: The names of the parent classes (ancestors).
271
     *
272
     * @var array
273
     */
274
    public $parentClasses = array();
275
276
    /**
277
     * READ-ONLY: The names of all subclasses (descendants).
278
     *
279
     * @var array
280
     */
281
    public $subClasses = array();
282
283
    /**
284
     * The ReflectionProperty instances of the mapped class.
285
     *
286
     * @var \ReflectionProperty[]
287
     */
288
    public $reflFields = array();
289
290
    /**
291
     * READ-ONLY: The inheritance mapping type used by the class.
292
     *
293
     * @var integer
294
     */
295
    public $inheritanceType = self::INHERITANCE_TYPE_NONE;
296
297
    /**
298
     * READ-ONLY: The Id generator type used by the class.
299
     *
300
     * @var string
301
     */
302
    public $generatorType = self::GENERATOR_TYPE_AUTO;
303
304
    /**
305
     * READ-ONLY: The Id generator options.
306
     *
307
     * @var array
308
     */
309
    public $generatorOptions = array();
310
311
    /**
312
     * READ-ONLY: The ID generator used for generating IDs for this class.
313
     *
314
     * @var \Doctrine\ODM\MongoDB\Id\AbstractIdGenerator
315
     */
316
    public $idGenerator;
317
318
    /**
319
     * READ-ONLY: The field mappings of the class.
320
     * Keys are field names and values are mapping definitions.
321
     *
322
     * The mapping definition array has the following values:
323
     *
324
     * - <b>fieldName</b> (string)
325
     * The name of the field in the Document.
326
     *
327
     * - <b>id</b> (boolean, optional)
328
     * Marks the field as the primary key of the document. Multiple fields of an
329
     * document can have the id attribute, forming a composite key.
330
     *
331
     * @var array
332
     */
333
    public $fieldMappings = array();
334
335
    /**
336
     * READ-ONLY: The association mappings of the class.
337
     * Keys are field names and values are mapping definitions.
338
     *
339
     * @var array
340
     */
341
    public $associationMappings = array();
342
343
    /**
344
     * READ-ONLY: Array of fields to also load with a given method.
345
     *
346
     * @var array
347
     */
348
    public $alsoLoadMethods = array();
349
350
    /**
351
     * READ-ONLY: The registered lifecycle callbacks for documents of this class.
352
     *
353
     * @var array
354
     */
355
    public $lifecycleCallbacks = array();
356
357
    /**
358
     * READ-ONLY: The discriminator value of this class.
359
     *
360
     * <b>This does only apply to the JOINED and SINGLE_COLLECTION inheritance mapping strategies
361
     * where a discriminator field is used.</b>
362
     *
363
     * @var mixed
364
     * @see discriminatorField
365
     */
366
    public $discriminatorValue;
367
368
    /**
369
     * READ-ONLY: The discriminator map of all mapped classes in the hierarchy.
370
     *
371
     * <b>This does only apply to the SINGLE_COLLECTION inheritance mapping strategy
372
     * where a discriminator field is used.</b>
373
     *
374
     * @var mixed
375
     * @see discriminatorField
376
     */
377
    public $discriminatorMap = array();
378
379
    /**
380
     * READ-ONLY: The definition of the discriminator field used in SINGLE_COLLECTION
381
     * inheritance mapping.
382
     *
383
     * @var string
384
     */
385
    public $discriminatorField;
386
387
    /**
388
     * READ-ONLY: The default value for discriminatorField in case it's not set in the document
389
     *
390
     * @var string
391
     * @see discriminatorField
392
     */
393
    public $defaultDiscriminatorValue;
394
395
    /**
396
     * READ-ONLY: Whether this class describes the mapping of a mapped superclass.
397
     *
398
     * @var boolean
399
     */
400
    public $isMappedSuperclass = false;
401
402
    /**
403
     * READ-ONLY: Whether this class describes the mapping of a embedded document.
404
     *
405
     * @var boolean
406
     */
407
    public $isEmbeddedDocument = false;
408
409
    /**
410
     * READ-ONLY: Whether this class describes the mapping of an aggregation result document.
411
     *
412
     * @var boolean
413
     */
414
    public $isQueryResultDocument = false;
415
416
    /**
417
     * READ-ONLY: The policy used for change-tracking on entities of this class.
418
     *
419
     * @var integer
420
     */
421
    public $changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT;
422
423
    /**
424
     * READ-ONLY: A flag for whether or not instances of this class are to be versioned
425
     * with optimistic locking.
426
     *
427
     * @var boolean $isVersioned
428
     */
429
    public $isVersioned;
430
431
    /**
432
     * READ-ONLY: The name of the field which is used for versioning in optimistic locking (if any).
433
     *
434
     * @var mixed $versionField
435
     */
436
    public $versionField;
437
438
    /**
439
     * READ-ONLY: A flag for whether or not instances of this class are to allow pessimistic
440
     * locking.
441
     *
442
     * @var boolean $isLockable
443
     */
444
    public $isLockable;
445
446
    /**
447
     * READ-ONLY: The name of the field which is used for locking a document.
448
     *
449
     * @var mixed $lockField
450
     */
451
    public $lockField;
452
453
    /**
454
     * The ReflectionClass instance of the mapped class.
455
     *
456
     * @var \ReflectionClass
457
     */
458
    public $reflClass;
459
460
    /**
461
     * Initializes a new ClassMetadata instance that will hold the object-document mapping
462
     * metadata of the class with the given name.
463
     *
464
     * @param string $documentName The name of the document class the new instance is used for.
465
     */
466 975
    public function __construct($documentName)
467
    {
468 975
        $this->name = $documentName;
469 975
        $this->rootDocumentName = $documentName;
470 975
    }
471
472
    /**
473
     * Helper method to get reference id of ref* type references
474
     * @param array  $reference
475
     * @param string $storeAs
476
     * @return \MongoId
477
     */
478 46
    public static function getReferenceId($reference, $storeAs)
479
    {
480 46
        if ($storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_REF_WITH_DB || $storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_REF) {
481
            return $reference['id'];
482
        } else {
483 46
            return $reference['$id'];
484
        }
485
    }
486
487 220
    public static function getReferencePrefix($storeAs)
488
    {
489 220
        if ($storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_REF_WITH_DB || $storeAs === ClassMetadataInfo::REFERENCE_STORE_AS_REF) {
490
            return '';
491
        } else {
492 220
            return '$';
493
        }
494
    }
495
496
    /**
497
     * {@inheritDoc}
498
     */
499 903
    public function getReflectionClass()
500
    {
501 903
        if ( ! $this->reflClass) {
502 2
            $this->reflClass = new \ReflectionClass($this->name);
503
        }
504
505 903
        return $this->reflClass;
506
    }
507
508
    /**
509
     * {@inheritDoc}
510
     */
511 330
    public function isIdentifier($fieldName)
512
    {
513 330
        return $this->identifier === $fieldName;
514
    }
515
516
    /**
517
     * INTERNAL:
518
     * Sets the mapped identifier field of this class.
519
     *
520
     * @param string $identifier
521
     */
522 370
    public function setIdentifier($identifier)
523
    {
524 370
        $this->identifier = $identifier;
525 370
    }
526
527
    /**
528
     * {@inheritDoc}
529
     *
530
     * Since MongoDB only allows exactly one identifier field
531
     * this will always return an array with only one value
532
     */
533 40
    public function getIdentifier()
534
    {
535 40
        return array($this->identifier);
536
    }
537
538
    /**
539
     * {@inheritDoc}
540
     *
541
     * Since MongoDB only allows exactly one identifier field
542
     * this will always return an array with only one value
543
     */
544 98
    public function getIdentifierFieldNames()
545
    {
546 98
        return array($this->identifier);
547
    }
548
549
    /**
550
     * {@inheritDoc}
551
     */
552 561
    public function hasField($fieldName)
553
    {
554 561
        return isset($this->fieldMappings[$fieldName]);
555
    }
556
557
    /**
558
     * Sets the inheritance type used by the class and it's subclasses.
559
     *
560
     * @param integer $type
561
     */
562 386
    public function setInheritanceType($type)
563
    {
564 386
        $this->inheritanceType = $type;
565 386
    }
566
567
    /**
568
     * Checks whether a mapped field is inherited from an entity superclass.
569
     *
570
     * @param  string $fieldName
571
     *
572
     * @return boolean TRUE if the field is inherited, FALSE otherwise.
573
     */
574 903
    public function isInheritedField($fieldName)
575
    {
576 903
        return isset($this->fieldMappings[$fieldName]['inherited']);
577
    }
578
579
    /**
580
     * Registers a custom repository class for the document class.
581
     *
582
     * @param string $repositoryClassName The class name of the custom repository.
583
     */
584 318
    public function setCustomRepositoryClass($repositoryClassName)
585
    {
586 318
        if ($this->isEmbeddedDocument || $this->isQueryResultDocument) {
587
            return;
588
        }
589
590 318 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...
591 4
            $repositoryClassName = $this->namespace . '\\' . $repositoryClassName;
592
        }
593
594 318
        $this->customRepositoryClassName = $repositoryClassName;
595 318
    }
596
597
    /**
598
     * Dispatches the lifecycle event of the given document by invoking all
599
     * registered callbacks.
600
     *
601
     * @param string $event     Lifecycle event
602
     * @param object $document  Document on which the event occurred
603
     * @param array  $arguments Arguments to pass to all callbacks
604
     * @throws \InvalidArgumentException if document class is not this class or
605
     *                                   a Proxy of this class
606
     */
607 660
    public function invokeLifecycleCallbacks($event, $document, array $arguments = null)
608
    {
609 660
        if ( ! $document instanceof $this->name) {
610 1
            throw new \InvalidArgumentException(sprintf('Expected document class "%s"; found: "%s"', $this->name, get_class($document)));
611
        }
612
613 659
        if (empty($this->lifecycleCallbacks[$event])) {
614 645
            return;
615
        }
616
617 196
        foreach ($this->lifecycleCallbacks[$event] as $callback) {
618 196
            if ($arguments !== null) {
619 195
                call_user_func_array(array($document, $callback), $arguments);
620
            } else {
621 196
                $document->$callback();
622
            }
623
        }
624 196
    }
625
626
    /**
627
     * Checks whether the class has callbacks registered for a lifecycle event.
628
     *
629
     * @param string $event Lifecycle event
630
     *
631
     * @return boolean
632
     */
633
    public function hasLifecycleCallbacks($event)
634
    {
635
        return ! empty($this->lifecycleCallbacks[$event]);
636
    }
637
638
    /**
639
     * Gets the registered lifecycle callbacks for an event.
640
     *
641
     * @param string $event
642
     * @return array
643
     */
644
    public function getLifecycleCallbacks($event)
645
    {
646
        return isset($this->lifecycleCallbacks[$event]) ? $this->lifecycleCallbacks[$event] : array();
647
    }
648
649
    /**
650
     * Adds a lifecycle callback for documents of this class.
651
     *
652
     * If the callback is already registered, this is a NOOP.
653
     *
654
     * @param string $callback
655
     * @param string $event
656
     */
657 297
    public function addLifecycleCallback($callback, $event)
658
    {
659 297
        if (isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event])) {
660 1
            return;
661
        }
662
663 297
        $this->lifecycleCallbacks[$event][] = $callback;
664 297
    }
665
666
    /**
667
     * Sets the lifecycle callbacks for documents of this class.
668
     *
669
     * Any previously registered callbacks are overwritten.
670
     *
671
     * @param array $callbacks
672
     */
673 369
    public function setLifecycleCallbacks(array $callbacks)
674
    {
675 369
        $this->lifecycleCallbacks = $callbacks;
676 369
    }
677
678
    /**
679
     * Registers a method for loading document data before field hydration.
680
     *
681
     * Note: A method may be registered multiple times for different fields.
682
     * it will be invoked only once for the first field found.
683
     *
684
     * @param string       $method Method name
685
     * @param array|string $fields Database field name(s)
686
     */
687 15
    public function registerAlsoLoadMethod($method, $fields)
688
    {
689 15
        $this->alsoLoadMethods[$method] = is_array($fields) ? $fields : array($fields);
690 15
    }
691
692
    /**
693
     * Sets the AlsoLoad methods for documents of this class.
694
     *
695
     * Any previously registered methods are overwritten.
696
     *
697
     * @param array $methods
698
     */
699 369
    public function setAlsoLoadMethods(array $methods)
700
    {
701 369
        $this->alsoLoadMethods = $methods;
702 369
    }
703
704
    /**
705
     * Sets the discriminator field.
706
     *
707
     * The field name is the the unmapped database field. Discriminator values
708
     * are only used to discern the hydration class and are not mapped to class
709
     * properties.
710
     *
711
     * @param string $discriminatorField
712
     *
713
     * @throws MappingException If the discriminator field conflicts with the
714
     *                          "name" attribute of a mapped field.
715
     */
716 399
    public function setDiscriminatorField($discriminatorField)
717
    {
718 399
        if ($discriminatorField === null) {
719 326
            $this->discriminatorField = null;
720
721 326
            return;
722
        }
723
724
        // Handle array argument with name/fieldName keys for BC
725 130
        if (is_array($discriminatorField)) {
726
            if (isset($discriminatorField['name'])) {
727
                $discriminatorField = $discriminatorField['name'];
728
            } elseif (isset($discriminatorField['fieldName'])) {
729
                $discriminatorField = $discriminatorField['fieldName'];
730
            }
731
        }
732
733 130
        foreach ($this->fieldMappings as $fieldMapping) {
734 4
            if ($discriminatorField == $fieldMapping['name']) {
735 4
                throw MappingException::discriminatorFieldConflict($this->name, $discriminatorField);
736
            }
737
        }
738
739 129
        $this->discriminatorField = $discriminatorField;
740 129
    }
741
742
    /**
743
     * Sets the discriminator values used by this class.
744
     * Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
745
     *
746
     * @param array $map
747
     *
748
     * @throws MappingException
749
     */
750 392
    public function setDiscriminatorMap(array $map)
751
    {
752 392
        foreach ($map as $value => $className) {
753 125
            if (strpos($className, '\\') === false && strlen($this->namespace)) {
754 91
                $className = $this->namespace . '\\' . $className;
755
            }
756 125
            $this->discriminatorMap[$value] = $className;
757 125
            if ($this->name == $className) {
758 117
                $this->discriminatorValue = $value;
759
            } else {
760 120
                if ( ! class_exists($className)) {
761
                    throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
762
                }
763 120
                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...
764 125
                    $this->subClasses[] = $className;
765
                }
766
            }
767
        }
768 392
    }
769
770
    /**
771
     * Sets the default discriminator value to be used for this class
772
     * Used for JOINED and SINGLE_TABLE inheritance mapping strategies if the document has no discriminator value
773
     *
774
     * @param string $defaultDiscriminatorValue
775
     *
776
     * @throws MappingException
777
     */
778 376
    public function setDefaultDiscriminatorValue($defaultDiscriminatorValue)
779
    {
780 376
        if ($defaultDiscriminatorValue === null) {
781 369
            $this->defaultDiscriminatorValue = null;
782
783 369
            return;
784
        }
785
786 60
        if (!array_key_exists($defaultDiscriminatorValue, $this->discriminatorMap)) {
787
            throw MappingException::invalidDiscriminatorValue($defaultDiscriminatorValue, $this->name);
788
        }
789
790 60
        $this->defaultDiscriminatorValue = $defaultDiscriminatorValue;
791 60
    }
792
793
    /**
794
     * Sets the discriminator value for this class.
795
     * Used for JOINED/SINGLE_TABLE inheritance and multiple document types in a single
796
     * collection.
797
     *
798
     * @param string $value
799
     */
800 3
    public function setDiscriminatorValue($value)
801
    {
802 3
        $this->discriminatorMap[$value] = $this->name;
803 3
        $this->discriminatorValue = $value;
804 3
    }
805
806
    /**
807
     * Sets the slaveOkay option applied to collections for this class.
808
     *
809
     * @param boolean|null $slaveOkay
810
     *
811
     * @deprecated in version 1.2 and will be removed in 2.0.
812
     */
813 3
    public function setSlaveOkay($slaveOkay)
814
    {
815 3
        @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
816 3
            sprintf('%s was deprecated in version 1.2 and will be removed in 2.0.'),
817 3
            E_USER_DEPRECATED
818
        );
819 3
        $this->slaveOkay = $slaveOkay === null ? null : (boolean) $slaveOkay;
0 ignored issues
show
Deprecated Code introduced by
The property Doctrine\ODM\MongoDB\Map...etadataInfo::$slaveOkay has been deprecated with message: in version 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...
820 3
    }
821
822
    /**
823
     * Add a index for this Document.
824
     *
825
     * @param array $keys Array of keys for the index.
826
     * @param array $options Array of options for the index.
827
     */
828 232
    public function addIndex($keys, array $options = array())
829
    {
830 232
        $this->indexes[] = array(
831 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...
832 232
                if ($value == 1 || $value == -1) {
833 63
                    return (int) $value;
834
                }
835 224
                if (is_string($value)) {
836 224
                    $lower = strtolower($value);
837 224
                    if ($lower === 'asc') {
838 217
                        return 1;
839 11
                    } elseif ($lower === 'desc') {
840 4
                        return -1;
841
                    }
842
                }
843 7
                return $value;
844 232
            }, $keys),
845 232
            'options' => $options
846
        );
847 232
    }
848
849
    /**
850
     * Set whether or not queries on this document should require indexes.
851
     *
852
     * @param bool $requireIndexes
853
     *
854
     * @deprecated method was deprecated in 1.2 and will be removed in 2.0
855
     */
856 894
    public function setRequireIndexes($requireIndexes)
857
    {
858 894
        @trigger_error(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
859 894
            'requireIndexes was deprecated in version 1.2 and will be removed altogether in 2.0.',
860 894
            E_USER_DEPRECATED
861
        );
862 894
        $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...
863 894
    }
864
865
    /**
866
     * Returns the array of indexes for this Document.
867
     *
868
     * @return array $indexes The array of indexes.
869
     */
870 54
    public function getIndexes()
871
    {
872 54
        return $this->indexes;
873
    }
874
875
    /**
876
     * Checks whether this document has indexes or not.
877
     *
878
     * @return boolean
879
     */
880
    public function hasIndexes()
881
    {
882
        return $this->indexes ? true : false;
883
    }
884
885
    /**
886
     * Set shard key for this Document.
887
     *
888
     * @param array $keys Array of document keys.
889
     * @param array $options Array of sharding options.
890
     *
891
     * @throws MappingException
892
     */
893 77
    public function setShardKey(array $keys, array $options = array())
894
    {
895 77
        if ($this->inheritanceType === self::INHERITANCE_TYPE_SINGLE_COLLECTION && !is_null($this->shardKey)) {
896 2
            throw MappingException::shardKeyInSingleCollInheritanceSubclass($this->getName());
897
        }
898
899 77
        if ($this->isEmbeddedDocument) {
900 2
            throw MappingException::embeddedDocumentCantHaveShardKey($this->getName());
901
        }
902
903 75
        foreach (array_keys($keys) as $field) {
904 75
            if (! isset($this->fieldMappings[$field])) {
905 68
                continue;
906
            }
907
908 7
            if (in_array($this->fieldMappings[$field]['type'], ['many', 'collection'])) {
909 3
                throw MappingException::noMultiKeyShardKeys($this->getName(), $field);
910
            }
911
912 4
            if ($this->fieldMappings[$field]['strategy'] !== static::STORAGE_STRATEGY_SET) {
913 4
                throw MappingException::onlySetStrategyAllowedInShardKey($this->getName(), $field);
914
            }
915
        }
916
917 71
        $this->shardKey = array(
918 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...
919 71
                if ($value == 1 || $value == -1) {
920 6
                    return (int) $value;
921
                }
922 70
                if (is_string($value)) {
923 70
                    $lower = strtolower($value);
924 70
                    if ($lower === 'asc') {
925 69
                        return 1;
926 53
                    } elseif ($lower === 'desc') {
927
                        return -1;
928
                    }
929
                }
930 53
                return $value;
931 71
            }, $keys),
932 71
            'options' => $options
933
        );
934 71
    }
935
936
    /**
937
     * @return array
938
     */
939 18
    public function getShardKey()
940
    {
941 18
        return $this->shardKey;
942
    }
943
944
    /**
945
     * Checks whether this document has shard key or not.
946
     *
947
     * @return bool
948
     */
949 598
    public function isSharded()
950
    {
951 598
        return $this->shardKey ? true : false;
952
    }
953
954
    /**
955
     * Sets the write concern used by this class.
956
     *
957
     * @param string $writeConcern
958
     */
959 383
    public function setWriteConcern($writeConcern)
960
    {
961 383
        $this->writeConcern = $writeConcern;
962 383
    }
963
964
    /**
965
     * @return string
966
     */
967 12
    public function getWriteConcern()
968
    {
969 12
        return $this->writeConcern;
970
    }
971
972
    /**
973
     * Whether there is a write concern configured for this class.
974
     *
975
     * @return bool
976
     */
977 604
    public function hasWriteConcern()
978
    {
979 604
        return $this->writeConcern !== null;
980
    }
981
982
    /**
983
     * Sets the change tracking policy used by this class.
984
     *
985
     * @param integer $policy
986
     */
987 374
    public function setChangeTrackingPolicy($policy)
988
    {
989 374
        $this->changeTrackingPolicy = $policy;
990 374
    }
991
992
    /**
993
     * Whether the change tracking policy of this class is "deferred explicit".
994
     *
995
     * @return boolean
996
     */
997 73
    public function isChangeTrackingDeferredExplicit()
998
    {
999 73
        return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_EXPLICIT;
1000
    }
1001
1002
    /**
1003
     * Whether the change tracking policy of this class is "deferred implicit".
1004
     *
1005
     * @return boolean
1006
     */
1007 624
    public function isChangeTrackingDeferredImplicit()
1008
    {
1009 624
        return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_IMPLICIT;
1010
    }
1011
1012
    /**
1013
     * Whether the change tracking policy of this class is "notify".
1014
     *
1015
     * @return boolean
1016
     */
1017 347
    public function isChangeTrackingNotify()
1018
    {
1019 347
        return $this->changeTrackingPolicy == self::CHANGETRACKING_NOTIFY;
1020
    }
1021
1022
    /**
1023
     * Gets the ReflectionProperties of the mapped class.
1024
     *
1025
     * @return array An array of ReflectionProperty instances.
1026
     */
1027 98
    public function getReflectionProperties()
1028
    {
1029 98
        return $this->reflFields;
1030
    }
1031
1032
    /**
1033
     * Gets a ReflectionProperty for a specific field of the mapped class.
1034
     *
1035
     * @param string $name
1036
     *
1037
     * @return \ReflectionProperty
1038
     */
1039
    public function getReflectionProperty($name)
1040
    {
1041
        return $this->reflFields[$name];
1042
    }
1043
1044
    /**
1045
     * {@inheritDoc}
1046
     */
1047 909
    public function getName()
1048
    {
1049 909
        return $this->name;
1050
    }
1051
1052
    /**
1053
     * The namespace this Document class belongs to.
1054
     *
1055
     * @return string $namespace The namespace name.
1056
     */
1057
    public function getNamespace()
1058
    {
1059
        return $this->namespace;
1060
    }
1061
1062
    /**
1063
     * Returns the database this Document is mapped to.
1064
     *
1065
     * @return string $db The database name.
1066
     */
1067 829
    public function getDatabase()
1068
    {
1069 829
        return $this->db;
1070
    }
1071
1072
    /**
1073
     * Set the database this Document is mapped to.
1074
     *
1075
     * @param string $db The database name
1076
     */
1077 104
    public function setDatabase($db)
1078
    {
1079 104
        $this->db = $db;
1080 104
    }
1081
1082
    /**
1083
     * Get the collection this Document is mapped to.
1084
     *
1085
     * @return string $collection The collection name.
1086
     */
1087 834
    public function getCollection()
1088
    {
1089 834
        return $this->collection;
1090
    }
1091
1092
    /**
1093
     * Sets the collection this Document is mapped to.
1094
     *
1095
     * @param array|string $name
1096
     *
1097
     * @throws \InvalidArgumentException
1098
     */
1099 939
    public function setCollection($name)
1100
    {
1101 939
        if (is_array($name)) {
1102
            if ( ! isset($name['name'])) {
1103
                throw new \InvalidArgumentException('A name key is required when passing an array to setCollection()');
1104
            }
1105
            $this->collectionCapped = isset($name['capped']) ? $name['capped'] : false;
1106
            $this->collectionSize = isset($name['size']) ? $name['size'] : 0;
1107
            $this->collectionMax = isset($name['max']) ? $name['max'] : 0;
1108
            $this->collection = $name['name'];
1109
        } else {
1110 939
            $this->collection = $name;
1111
        }
1112 939
    }
1113
1114
    /**
1115
     * Get whether or not the documents collection is capped.
1116
     *
1117
     * @return boolean
1118
     */
1119 4
    public function getCollectionCapped()
1120
    {
1121 4
        return $this->collectionCapped;
1122
    }
1123
1124
    /**
1125
     * Set whether or not the documents collection is capped.
1126
     *
1127
     * @param boolean $bool
1128
     */
1129 1
    public function setCollectionCapped($bool)
1130
    {
1131 1
        $this->collectionCapped = $bool;
1132 1
    }
1133
1134
    /**
1135
     * Get the collection size
1136
     *
1137
     * @return integer
1138
     */
1139 4
    public function getCollectionSize()
1140
    {
1141 4
        return $this->collectionSize;
1142
    }
1143
1144
    /**
1145
     * Set the collection size.
1146
     *
1147
     * @param integer $size
1148
     */
1149 1
    public function setCollectionSize($size)
1150
    {
1151 1
        $this->collectionSize = $size;
1152 1
    }
1153
1154
    /**
1155
     * Get the collection max.
1156
     *
1157
     * @return integer
1158
     */
1159 4
    public function getCollectionMax()
1160
    {
1161 4
        return $this->collectionMax;
1162
    }
1163
1164
    /**
1165
     * Set the collection max.
1166
     *
1167
     * @param integer $max
1168
     */
1169 1
    public function setCollectionMax($max)
1170
    {
1171 1
        $this->collectionMax = $max;
1172 1
    }
1173
1174
    /**
1175
     * Returns TRUE if this Document is mapped to a collection FALSE otherwise.
1176
     *
1177
     * @return boolean
1178
     */
1179
    public function isMappedToCollection()
1180
    {
1181
        return $this->collection ? true : false;
1182
    }
1183
1184
    /**
1185
     * Returns TRUE if this Document is a file to be stored on the MongoGridFS FALSE otherwise.
1186
     *
1187
     * @return boolean
1188
     */
1189 775
    public function isFile()
1190
    {
1191 775
        return $this->file ? true : false;
1192
    }
1193
1194
    /**
1195
     * Returns the file field name.
1196
     *
1197
     * @return string $file The file field name.
1198
     */
1199 369
    public function getFile()
1200
    {
1201 369
        return $this->file;
1202
    }
1203
1204
    /**
1205
     * Set the field name that stores the grid file.
1206
     *
1207
     * @param string $file
1208
     */
1209 370
    public function setFile($file)
1210
    {
1211 370
        $this->file = $file;
1212 370
    }
1213
1214
    /**
1215
     * Returns the distance field name.
1216
     *
1217
     * @return string $distance The distance field name.
1218
     */
1219
    public function getDistance()
1220
    {
1221
        return $this->distance;
1222
    }
1223
1224
    /**
1225
     * Set the field name that stores the distance.
1226
     *
1227
     * @param string $distance
1228
     */
1229 1
    public function setDistance($distance)
1230
    {
1231 1
        $this->distance = $distance;
1232 1
    }
1233
1234
    /**
1235
     * Map a field.
1236
     *
1237
     * @param array $mapping The mapping information.
1238
     *
1239
     * @return array
1240
     *
1241
     * @throws MappingException
1242
     */
1243 953
    public function mapField(array $mapping)
1244
    {
1245 953
        if ( ! isset($mapping['fieldName']) && isset($mapping['name'])) {
1246 10
            $mapping['fieldName'] = $mapping['name'];
1247
        }
1248 953
        if ( ! isset($mapping['fieldName'])) {
1249
            throw MappingException::missingFieldName($this->name);
1250
        }
1251 953
        if ( ! isset($mapping['name'])) {
1252 943
            $mapping['name'] = $mapping['fieldName'];
1253
        }
1254 953
        if ($this->identifier === $mapping['name'] && empty($mapping['id'])) {
1255 1
            throw MappingException::mustNotChangeIdentifierFieldsType($this->name, $mapping['name']);
1256
        }
1257 952
        if (isset($this->fieldMappings[$mapping['fieldName']])) {
1258
            //throw MappingException::duplicateFieldMapping($this->name, $mapping['fieldName']);
1259
        }
1260 952
        if ($this->discriminatorField !== null && $this->discriminatorField == $mapping['name']) {
1261 1
            throw MappingException::discriminatorFieldConflict($this->name, $this->discriminatorField);
1262
        }
1263 951 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...
1264 616
            $mapping['targetDocument'] = $this->namespace . '\\' . $mapping['targetDocument'];
1265
        }
1266 951
        if (isset($mapping['collectionClass'])) {
1267 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...
1268 63
                $mapping['collectionClass'] = $this->namespace . '\\' . $mapping['collectionClass'];
1269
            }
1270 65
            $mapping['collectionClass'] = ltrim($mapping['collectionClass'], '\\');
1271
        }
1272 951
        if ( ! empty($mapping['collectionClass'])) {
1273 65
            $rColl = new \ReflectionClass($mapping['collectionClass']);
1274 65
            if ( ! $rColl->implementsInterface('Doctrine\\Common\\Collections\\Collection')) {
1275 1
                throw MappingException::collectionClassDoesNotImplementCommonInterface($this->name, $mapping['fieldName'], $mapping['collectionClass']);
1276
            }
1277
        }
1278
1279 950
        if (isset($mapping['discriminatorMap'])) {
1280 123
            foreach ($mapping['discriminatorMap'] as $key => $class) {
1281 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...
1282 123
                    $mapping['discriminatorMap'][$key] = $this->namespace . '\\' . $class;
1283
                }
1284
            }
1285
        }
1286
1287 950
        if (isset($mapping['cascade']) && isset($mapping['embedded'])) {
1288 1
            throw MappingException::cascadeOnEmbeddedNotAllowed($this->name, $mapping['fieldName']);
1289
        }
1290
1291 949
        $cascades = isset($mapping['cascade']) ? array_map('strtolower', (array) $mapping['cascade']) : array();
1292
1293 949
        if (in_array('all', $cascades) || isset($mapping['embedded'])) {
1294 644
            $cascades = array('remove', 'persist', 'refresh', 'merge', 'detach');
1295
        }
1296
1297 949
        if (isset($mapping['embedded'])) {
1298 601
            unset($mapping['cascade']);
1299 944
        } elseif (isset($mapping['cascade'])) {
1300 408
            $mapping['cascade'] = $cascades;
1301
        }
1302
1303 949
        $mapping['isCascadeRemove'] = in_array('remove', $cascades);
1304 949
        $mapping['isCascadePersist'] = in_array('persist', $cascades);
1305 949
        $mapping['isCascadeRefresh'] = in_array('refresh', $cascades);
1306 949
        $mapping['isCascadeMerge'] = in_array('merge', $cascades);
1307 949
        $mapping['isCascadeDetach'] = in_array('detach', $cascades);
1308
1309 949
        if (isset($mapping['type']) && $mapping['type'] === 'file') {
1310 63
            $mapping['file'] = true;
1311
        }
1312 949
        if (isset($mapping['type']) && $mapping['type'] === 'increment') {
1313 1
            $mapping['strategy'] = self::STORAGE_STRATEGY_INCREMENT;
1314
        }
1315 949 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...
1316 63
            $this->file = $mapping['fieldName'];
1317 63
            $mapping['name'] = 'file';
1318
        }
1319 949 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...
1320 7
            $this->distance = $mapping['fieldName'];
1321
        }
1322 949
        if (isset($mapping['id']) && $mapping['id'] === true) {
1323 921
            $mapping['name'] = '_id';
1324 921
            $this->identifier = $mapping['fieldName'];
1325 921 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...
1326 902
                $this->generatorType = constant(ClassMetadata::class . '::GENERATOR_TYPE_' . strtoupper($mapping['strategy']));
1327
            }
1328 921
            $this->generatorOptions = isset($mapping['options']) ? $mapping['options'] : array();
1329 921
            switch ($this->generatorType) {
1330 921
                case self::GENERATOR_TYPE_AUTO:
1331 847
                    $mapping['type'] = 'id';
1332 847
                    break;
1333
                default:
1334 153
                    if ( ! empty($this->generatorOptions['type'])) {
1335 52
                        $mapping['type'] = $this->generatorOptions['type'];
1336 101
                    } elseif (empty($mapping['type'])) {
1337 86
                        $mapping['type'] = $this->generatorType === self::GENERATOR_TYPE_INCREMENT ? 'int_id' : 'custom_id';
1338
                    }
1339
            }
1340 921
            unset($this->generatorOptions['type']);
1341
        }
1342
1343 949
        if ( ! isset($mapping['nullable'])) {
1344 53
            $mapping['nullable'] = false;
1345
        }
1346
1347
        // Synchronize the "simple" and "storeAs" mapping information for backwards compatibility
1348 949
        if (isset($mapping['simple']) && ($mapping['simple'] === true || $mapping['simple'] === 'true')) {
1349 293
            $mapping['storeAs'] = ClassMetadataInfo::REFERENCE_STORE_AS_ID;
1350 293
            @trigger_error('"simple" attribute of a reference is deprecated - use storeAs="id" instead.', E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

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