Completed
Pull Request — 1.0.x (#1431)
by Andreas
05:30
created

ClassMetadataInfo::getDatabase()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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