Completed
Pull Request — master (#1333)
by Maciej
10:44
created

ClassMetadataInfo::setInheritanceType()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

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