Completed
Push — 1.0.x ( bcb4f8...f4d4ca )
by Andreas
9s
created

ClassMetadataInfo::getAssociationNames()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ODM\MongoDB\Mapping;
21
22
use Doctrine\ODM\MongoDB\Utility\CollectionHelper;
23
use Doctrine\ODM\MongoDB\LockException;
24
use Doctrine\ODM\MongoDB\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 820
    public function __construct($documentName)
423
    {
424 820
        $this->name = $documentName;
425 820
        $this->rootDocumentName = $documentName;
426 820
    }
427
428
    /**
429
     * {@inheritDoc}
430
     */
431 774
    public function getReflectionClass()
432
    {
433 774
        if ( ! $this->reflClass) {
434 2
            $this->reflClass = new \ReflectionClass($this->name);
435 2
        }
436
437 774
        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 291
    public function setIdentifier($identifier)
455
    {
456 291
        $this->identifier = $identifier;
457 291
    }
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 307
    public function setInheritanceType($type)
495
    {
496 307
        $this->inheritanceType = $type;
497 307
    }
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 774
    public function isInheritedField($fieldName)
507
    {
508 774
        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 290
    public function setLifecycleCallbacks(array $callbacks)
602
    {
603 290
        $this->lifecycleCallbacks = $callbacks;
604 290
    }
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 290
    public function setAlsoLoadMethods(array $methods)
628
    {
629 290
        $this->alsoLoadMethods = $methods;
630 290
    }
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 316
    public function setDiscriminatorField($discriminatorField)
645
    {
646 316
        if ($discriminatorField === null) {
647 262
            $this->discriminatorField = null;
648
649 262
            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 312
    public function setDiscriminatorMap(array $map)
679
    {
680 312
        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 312
        }
696 312
    }
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 296
    public function setDefaultDiscriminatorValue($defaultDiscriminatorValue)
707
    {
708 296
        if ($defaultDiscriminatorValue === null) {
709 290
            $this->defaultDiscriminatorValue = null;
710
711 290
            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 766
    public function setRequireIndexes($requireIndexes)
777
    {
778 766
        $this->requireIndexes = $requireIndexes;
779 766
    }
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 294
    public function setChangeTrackingPolicy($policy)
807
    {
808 294
        $this->changeTrackingPolicy = $policy;
809 294
    }
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 565
    public function isChangeTrackingDeferredImplicit()
827
    {
828 565
        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 327
    public function isChangeTrackingNotify()
837
    {
838 327
        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 771
    public function getName()
867
    {
868 771
        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 708
    public function getDatabase()
887
    {
888 708
        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 712
    public function getCollection()
907
    {
908 712
        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 801
    public function setCollection($name)
919
    {
920 801
        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 801
            $this->collection = $name;
930
        }
931 801
    }
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 690
    public function isFile()
1009
    {
1010 690
        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 290
    public function getFile()
1019
    {
1020 290
        return $this->file;
1021
    }
1022
1023
    /**
1024
     * Set the field name that stores the grid file.
1025
     *
1026
     * @param string $file
1027
     */
1028 291
    public function setFile($file)
1029
    {
1030 291
        $this->file = $file;
1031 291
    }
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 806
    public function mapField(array $mapping)
1063
    {
1064 806
        if ( ! isset($mapping['fieldName']) && isset($mapping['name'])) {
1065 6
            $mapping['fieldName'] = $mapping['name'];
1066 6
        }
1067 806
        if ( ! isset($mapping['fieldName'])) {
1068
            throw MappingException::missingFieldName($this->name);
1069
        }
1070 806
        if ( ! isset($mapping['name'])) {
1071 800
            $mapping['name'] = $mapping['fieldName'];
1072 800
        }
1073 806
        if ($this->identifier === $mapping['name'] && empty($mapping['id'])) {
1074 1
            throw MappingException::mustNotChangeIdentifierFieldsType($this->name, $mapping['name']);
1075
        }
1076 805
        if (isset($this->fieldMappings[$mapping['fieldName']])) {
1077
            //throw MappingException::duplicateFieldMapping($this->name, $mapping['fieldName']);
1078 24
        }
1079 805
        if ($this->discriminatorField !== null && $this->discriminatorField == $mapping['name']) {
1080 1
            throw MappingException::discriminatorFieldConflict($this->name, $this->discriminatorField);
1081
        }
1082 804
        if (isset($mapping['targetDocument']) && strpos($mapping['targetDocument'], '\\') === false && strlen($this->namespace)) {
1083 496
            $mapping['targetDocument'] = $this->namespace . '\\' . $mapping['targetDocument'];
1084 496
        }
1085
1086 804
        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 804
        if (isset($mapping['cascade']) && isset($mapping['embedded'])) {
1095 1
            throw MappingException::cascadeOnEmbeddedNotAllowed($this->name, $mapping['fieldName']);
1096
        }
1097
1098 803
        $cascades = isset($mapping['cascade']) ? array_map('strtolower', (array) $mapping['cascade']) : array();
1099
1100 803
        if (in_array('all', $cascades) || isset($mapping['embedded'])) {
1101 527
            $cascades = array('remove', 'persist', 'refresh', 'merge', 'detach');
1102 527
        }
1103
1104 803
        if (isset($mapping['embedded'])) {
1105 500
            unset($mapping['cascade']);
1106 803
        } elseif (isset($mapping['cascade'])) {
1107 328
            $mapping['cascade'] = $cascades;
1108 328
        }
1109
1110 803
        $mapping['isCascadeRemove'] = in_array('remove', $cascades);
1111 803
        $mapping['isCascadePersist'] = in_array('persist', $cascades);
1112 803
        $mapping['isCascadeRefresh'] = in_array('refresh', $cascades);
1113 803
        $mapping['isCascadeMerge'] = in_array('merge', $cascades);
1114 803
        $mapping['isCascadeDetach'] = in_array('detach', $cascades);
1115
        
1116 803
        if (isset($mapping['type']) && $mapping['type'] === 'file') {
1117 27
            $mapping['file'] = true;
1118 27
        }
1119 803 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 803 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 803
        if (isset($mapping['id']) && $mapping['id'] === true) {
1127 784
            $mapping['name'] = '_id';
1128 784
            $this->identifier = $mapping['fieldName'];
1129 784
            if (isset($mapping['strategy'])) {
1130 772
                $this->generatorType = constant('Doctrine\ODM\MongoDB\Mapping\ClassMetadata::GENERATOR_TYPE_' . strtoupper($mapping['strategy']));
1131 772
            }
1132 784
            $this->generatorOptions = isset($mapping['options']) ? $mapping['options'] : array();
1133 784
            switch ($this->generatorType) {
1134 784
                case self::GENERATOR_TYPE_AUTO:
1135 717
                    $mapping['type'] = 'id';
1136 717
                    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 784
            }
1144 784
            unset($this->generatorOptions['type']);
1145 784
        }
1146 803
        if ( ! isset($mapping['nullable'])) {
1147 36
            $mapping['nullable'] = false;
1148 36
        }
1149
1150 803
        if (isset($mapping['reference']) && ! empty($mapping['simple']) && ! isset($mapping['targetDocument'])) {
1151 1
            throw MappingException::simpleReferenceRequiresTargetDocument($this->name, $mapping['fieldName']);
1152
        }
1153
1154 802
        if (isset($mapping['reference']) && empty($mapping['targetDocument']) && empty($mapping['discriminatorMap']) &&
1155 802
                (isset($mapping['mappedBy']) || isset($mapping['inversedBy']))) {
1156 4
            throw MappingException::owningAndInverseReferencesRequireTargetDocument($this->name, $mapping['fieldName']);
1157
        }
1158
        
1159 798
        if ($this->isEmbeddedDocument && $mapping['type'] === 'many' && CollectionHelper::isAtomic($mapping['strategy'])) {
1160 1
            throw MappingException::atomicCollectionStrategyNotAllowed($mapping['strategy'], $this->name, $mapping['fieldName']);
1161
        }
1162
1163 797 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 797 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 797 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 370
            $mapping['association'] = self::EMBED_ONE;
1171 370
        }
1172 797 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 429
            $mapping['association'] = self::EMBED_MANY;
1174 429
        }
1175
1176 797
        if (isset($mapping['association']) && ! isset($mapping['targetDocument']) && ! isset($mapping['discriminatorField'])) {
1177 84
            $mapping['discriminatorField'] = self::DEFAULT_DISCRIMINATOR_FIELD;
1178 84
        }
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 797
        if (isset($mapping['version'])) {
1186 63
            $mapping['notSaved'] = true;
1187 63
            $this->setVersionMapping($mapping);
1188 62
        }
1189 797
        if (isset($mapping['lock'])) {
1190 26
            $mapping['notSaved'] = true;
1191 26
            $this->setLockMapping($mapping);
1192 25
        }
1193 797
        $mapping['isOwningSide'] = true;
1194 797
        $mapping['isInverseSide'] = false;
1195 797
        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 797
        if (isset($mapping['reference']) && $mapping['type'] === 'many' && $mapping['isOwningSide']
1214 797
            && ! empty($mapping['sort']) && ! CollectionHelper::usesSet($mapping['strategy'])) {
1215 1
            throw MappingException::referenceManySortMustNotBeUsedWithNonSetCollectionStrategy($this->name, $mapping['fieldName'], $mapping['strategy']);
1216
        }
1217
1218 796
        $this->fieldMappings[$mapping['fieldName']] = $mapping;
1219 796
        if (isset($mapping['association'])) {
1220 621
            $this->associationMappings[$mapping['fieldName']] = $mapping;
1221 621
        }
1222
1223 796
        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 74
    public function addInheritedFieldMapping(array $fieldMapping)
1294
    {
1295 74
        $this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping;
1296
1297 74
        if (isset($fieldMapping['association'])) {
1298 41
            $this->associationMappings[$fieldMapping['fieldName']] = $fieldMapping;
1299 41
        }
1300 74
    }
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 42
    public function addInheritedAssociationMapping(array $mapping/*, $owningClassName = null*/)
1314
    {
1315 42
        $this->associationMappings[$mapping['fieldName']] = $mapping;
1316 42
    }
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 714
    public function setIdGenerator($generator)
1430
    {
1431 714
        $this->idGenerator = $generator;
1432 714
    }
1433
1434
    /**
1435
     * Casts the identifier to its portable PHP type.
1436
     *
1437
     * @param mixed $id
1438
     * @return mixed $id
1439
     */
1440 579
    public function getPHPIdentifierValue($id)
1441
    {
1442 579
        $idType = $this->fieldMappings[$this->identifier]['type'];
1443 579
        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 641
    public function getDatabaseIdentifierValue($id)
1453
    {
1454 641
        $idType = $this->fieldMappings[$this->identifier]['type'];
1455 641
        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 512
    public function setIdentifierValue($document, $id)
1467
    {
1468 512
        $id = $this->getPHPIdentifierValue($id);
1469 512
        $this->reflFields[$this->identifier]->setValue($document, $id);
1470 512
    }
1471
1472
    /**
1473
     * Gets the document identifier as a PHP type.
1474
     *
1475
     * @param object $document
1476
     * @return mixed $id
1477
     */
1478 592
    public function getIdentifierValue($document)
1479
    {
1480 592
        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 296
    public function setIdGeneratorType($generatorType)
1591
    {
1592 296
        $this->generatorType = $generatorType;
1593 296
    }
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 563
    public function isInheritanceTypeNone()
1607
    {
1608 563
        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 290
    public function isInheritanceTypeSingleCollection()
1617
    {
1618 290
        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 769
    public function setParentClasses(array $classNames)
1655
    {
1656 769
        $this->parentClasses = $classNames;
1657
1658 769
        if (count($classNames) > 0) {
1659 60
            $this->rootDocumentName = array_pop($classNames);
1660 60
        }
1661 769
    }
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 290
    public function setVersioned($bool)
1727
    {
1728 290
        $this->isVersioned = $bool;
1729 290
    }
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 290
    public function setVersionField($versionField)
1738
    {
1739 290
        $this->versionField = $versionField;
1740 290
    }
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