Completed
Pull Request — master (#1523)
by
unknown
11:07
created

ClassMetadataInfo::getTypeNameOfField()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

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