Completed
Pull Request — master (#1219)
by Maciej
09:25
created

ClassMetadataInfo::isIdGeneratorNone()   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
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
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\Mapping\ClassMetadata;
23
use Doctrine\ODM\MongoDB\Utility\CollectionHelper;
24
use Doctrine\ODM\MongoDB\LockException;
25
use Doctrine\ODM\MongoDB\Mapping\MappingException;
26
use Doctrine\ODM\MongoDB\Proxy\Proxy;
27
use Doctrine\ODM\MongoDB\Types\Type;
28
use InvalidArgumentException;
29
30
/**
31
 * A <tt>ClassMetadata</tt> instance holds all the object-document mapping metadata
32
 * of a document and it's references.
33
 *
34
 * Once populated, ClassMetadata instances are usually cached in a serialized form.
35
 *
36
 * <b>IMPORTANT NOTE:</b>
37
 *
38
 * The fields of this class are only public for 2 reasons:
39
 * 1) To allow fast READ access.
40
 * 2) To drastically reduce the size of a serialized instance (private/protected members
41
 *    get the whole class name, namespace inclusive, prepended to every property in
42
 *    the serialized representation).
43
 *
44
 * @since       1.0
45
 * @author      Jonathan H. Wage <[email protected]>
46
 * @author      Roman Borschel <[email protected]>
47
 */
48
class ClassMetadataInfo implements \Doctrine\Common\Persistence\Mapping\ClassMetadata
49
{
50
    /* The Id generator types. */
51
    /**
52
     * AUTO means Doctrine will automatically create a new \MongoId instance for us.
53
     */
54
    const GENERATOR_TYPE_AUTO = 1;
55
56
    /**
57
     * INCREMENT means a separate collection is used for maintaining and incrementing id generation.
58
     * Offers full portability.
59
     */
60
    const GENERATOR_TYPE_INCREMENT = 2;
61
62
    /**
63
     * UUID means Doctrine will generate a uuid for us.
64
     */
65
    const GENERATOR_TYPE_UUID = 3;
66
67
    /**
68
     * ALNUM means Doctrine will generate Alpha-numeric string identifiers, using the INCREMENT
69
     * generator to ensure identifier uniqueness
70
     */
71
    const GENERATOR_TYPE_ALNUM = 4;
72
73
    /**
74
     * CUSTOM means Doctrine expect a class parameter. It will then try to initiate that class
75
     * and pass other options to the generator. It will throw an Exception if the class
76
     * does not exist or if an option was passed for that there is not setter in the new
77
     * generator class.
78
     *
79
     * The class  will have to be a subtype of AbstractIdGenerator.
80
     */
81
    const GENERATOR_TYPE_CUSTOM = 5;
82
83
    /**
84
     * NONE means Doctrine will not generate any id for us and you are responsible for manually
85
     * assigning an id.
86
     */
87
    const GENERATOR_TYPE_NONE = 6;
88
89
    /**
90
     * Default discriminator field name.
91
     *
92
     * This is used for associations value for associations where a that do not define a "targetDocument" or
93
     * "discriminatorField" option in their mapping.
94
     */
95
    const DEFAULT_DISCRIMINATOR_FIELD = '_doctrine_class_name';
96
97
    const REFERENCE_ONE = 1;
98
    const REFERENCE_MANY = 2;
99
    const EMBED_ONE = 3;
100
    const EMBED_MANY = 4;
101
    const MANY = 'many';
102
    const ONE = 'one';
103
104
    /* The inheritance mapping types */
105
    /**
106
     * NONE means the class does not participate in an inheritance hierarchy
107
     * and therefore does not need an inheritance mapping type.
108
     */
109
    const INHERITANCE_TYPE_NONE = 1;
110
111
    /**
112
     * SINGLE_COLLECTION means the class will be persisted according to the rules of
113
     * <tt>Single Collection Inheritance</tt>.
114
     */
115
    const INHERITANCE_TYPE_SINGLE_COLLECTION = 2;
116
117
    /**
118
     * COLLECTION_PER_CLASS means the class will be persisted according to the rules
119
     * of <tt>Concrete Collection Inheritance</tt>.
120
     */
121
    const INHERITANCE_TYPE_COLLECTION_PER_CLASS = 3;
122
123
    /**
124
     * DEFERRED_IMPLICIT means that changes of entities are calculated at commit-time
125
     * by doing a property-by-property comparison with the original data. This will
126
     * be done for all entities that are in MANAGED state at commit-time.
127
     *
128
     * This is the default change tracking policy.
129
     */
130
    const CHANGETRACKING_DEFERRED_IMPLICIT = 1;
131
132
    /**
133
     * DEFERRED_EXPLICIT means that changes of entities are calculated at commit-time
134
     * by doing a property-by-property comparison with the original data. This will
135
     * be done only for entities that were explicitly saved (through persist() or a cascade).
136
     */
137
    const CHANGETRACKING_DEFERRED_EXPLICIT = 2;
138
139
    /**
140
     * NOTIFY means that Doctrine relies on the entities sending out notifications
141
     * when their properties change. Such entity classes must implement
142
     * the <tt>NotifyPropertyChanged</tt> interface.
143
     */
144
    const CHANGETRACKING_NOTIFY = 3;
145
146
    /**
147
     * READ-ONLY: The name of the mongo database the document is mapped to.
148
     */
149
    public $db;
150
151
    /**
152
     * READ-ONLY: The name of the mongo collection the document is mapped to.
153
     */
154
    public $collection;
155
156
    /**
157
     * READ-ONLY: If the collection should be a fixed size.
158
     */
159
    public $collectionCapped;
160
161
    /**
162
     * READ-ONLY: If the collection is fixed size, its size in bytes.
163
     */
164
    public $collectionSize;
165
166
    /**
167
     * READ-ONLY: If the collection is fixed size, the maximum number of elements to store in the collection.
168
     */
169
    public $collectionMax;
170
171
    /**
172
     * READ-ONLY: The field name of the document identifier.
173
     */
174
    public $identifier;
175
176
    /**
177
     * READ-ONLY: The field that stores a file reference and indicates the
178
     * document is a file and should be stored on the MongoGridFS.
179
     */
180
    public $file;
181
182
    /**
183
     * READ-ONLY: The field that stores the calculated distance when performing geo spatial
184
     * queries.
185
     */
186
    public $distance;
187
188
    /**
189
     * READ-ONLY: Whether or not reads for this class are okay to read from a slave.
190
     */
191
    public $slaveOkay;
192
193
    /**
194
     * READ-ONLY: The array of indexes for the document collection.
195
     */
196
    public $indexes = array();
197
198
    /**
199
     * READ-ONLY: Whether or not queries on this document should require indexes.
200
     */
201
    public $requireIndexes = false;
202
203
    /**
204
     * READ-ONLY: The name of the document class.
205
     */
206
    public $name;
207
208
    /**
209
     * READ-ONLY: The namespace the document class is contained in.
210
     *
211
     * @var string
212
     * @todo Not really needed. Usage could be localized.
213
     */
214
    public $namespace;
215
216
    /**
217
     * READ-ONLY: The name of the document class that is at the root of the mapped document inheritance
218
     * hierarchy. If the document is not part of a mapped inheritance hierarchy this is the same
219
     * as {@link $documentName}.
220
     *
221
     * @var string
222
     */
223
    public $rootDocumentName;
224
225
    /**
226
     * The name of the custom repository class used for the document class.
227
     * (Optional).
228
     *
229
     * @var string
230
     */
231
    public $customRepositoryClassName;
232
233
    /**
234
     * READ-ONLY: The names of the parent classes (ancestors).
235
     *
236
     * @var array
237
     */
238
    public $parentClasses = array();
239
240
    /**
241
     * READ-ONLY: The names of all subclasses (descendants).
242
     *
243
     * @var array
244
     */
245
    public $subClasses = array();
246
247
    /**
248
     * The ReflectionProperty instances of the mapped class.
249
     *
250
     * @var \ReflectionProperty[]
251
     */
252
    public $reflFields = array();
253
254
    /**
255
     * READ-ONLY: The inheritance mapping type used by the class.
256
     *
257
     * @var integer
258
     */
259
    public $inheritanceType = self::INHERITANCE_TYPE_NONE;
260
261
    /**
262
     * READ-ONLY: The Id generator type used by the class.
263
     *
264
     * @var string
265
     */
266
    public $generatorType = self::GENERATOR_TYPE_AUTO;
267
268
    /**
269
     * READ-ONLY: The Id generator options.
270
     *
271
     * @var array
272
     */
273
    public $generatorOptions = array();
274
275
    /**
276
     * READ-ONLY: The ID generator used for generating IDs for this class.
277
     *
278
     * @var \Doctrine\ODM\MongoDB\Id\AbstractIdGenerator
279
     */
280
    public $idGenerator;
281
282
    /**
283
     * READ-ONLY: The field mappings of the class.
284
     * Keys are field names and values are mapping definitions.
285
     *
286
     * The mapping definition array has the following values:
287
     *
288
     * - <b>fieldName</b> (string)
289
     * The name of the field in the Document.
290
     *
291
     * - <b>id</b> (boolean, optional)
292
     * Marks the field as the primary key of the document. Multiple fields of an
293
     * document can have the id attribute, forming a composite key.
294
     *
295
     * @var array
296
     */
297
    public $fieldMappings = array();
298
299
    /**
300
     * READ-ONLY: The association mappings of the class.
301
     * Keys are field names and values are mapping definitions.
302
     *
303
     * @var array
304
     */
305
    public $associationMappings = array();
306
307
    /**
308
     * READ-ONLY: Array of fields to also load with a given method.
309
     *
310
     * @var array
311
     */
312
    public $alsoLoadMethods = array();
313
314
    /**
315
     * READ-ONLY: The registered lifecycle callbacks for documents of this class.
316
     *
317
     * @var array
318
     */
319
    public $lifecycleCallbacks = array();
320
321
    /**
322
     * READ-ONLY: The discriminator value of this class.
323
     *
324
     * <b>This does only apply to the JOINED and SINGLE_COLLECTION inheritance mapping strategies
325
     * where a discriminator field is used.</b>
326
     *
327
     * @var mixed
328
     * @see discriminatorField
329
     */
330
    public $discriminatorValue;
331
332
    /**
333
     * READ-ONLY: The discriminator map of all mapped classes in the hierarchy.
334
     *
335
     * <b>This does only apply to the SINGLE_COLLECTION inheritance mapping strategy
336
     * where a discriminator field is used.</b>
337
     *
338
     * @var mixed
339
     * @see discriminatorField
340
     */
341
    public $discriminatorMap = array();
342
343
    /**
344
     * READ-ONLY: The definition of the discriminator field used in SINGLE_COLLECTION
345
     * inheritance mapping.
346
     *
347
     * @var string
348
     */
349
    public $discriminatorField;
350
351
    /**
352
     * READ-ONLY: The default value for discriminatorField in case it's not set in the document
353
     *
354
     * @var string
355
     * @see discriminatorField
356
     */
357
    public $defaultDiscriminatorValue;
358
359
    /**
360
     * READ-ONLY: Whether this class describes the mapping of a mapped superclass.
361
     *
362
     * @var boolean
363
     */
364
    public $isMappedSuperclass = false;
365
366
    /**
367
     * READ-ONLY: Whether this class describes the mapping of a embedded document.
368
     *
369
     * @var boolean
370
     */
371
    public $isEmbeddedDocument = false;
372
373
    /**
374
     * READ-ONLY: The policy used for change-tracking on entities of this class.
375
     *
376
     * @var integer
377
     */
378
    public $changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT;
379
380
    /**
381
     * READ-ONLY: A flag for whether or not instances of this class are to be versioned
382
     * with optimistic locking.
383
     *
384
     * @var boolean $isVersioned
385
     */
386
    public $isVersioned;
387
388
    /**
389
     * READ-ONLY: The name of the field which is used for versioning in optimistic locking (if any).
390
     *
391
     * @var mixed $versionField
392
     */
393
    public $versionField;
394
395
    /**
396
     * READ-ONLY: A flag for whether or not instances of this class are to allow pessimistic
397
     * locking.
398
     *
399
     * @var boolean $isLockable
400
     */
401
    public $isLockable;
402
403
    /**
404
     * READ-ONLY: The name of the field which is used for locking a document.
405
     *
406
     * @var mixed $lockField
407
     */
408
    public $lockField;
409
410
    /**
411
     * The ReflectionClass instance of the mapped class.
412
     *
413
     * @var \ReflectionClass
414
     */
415
    public $reflClass;
416
417
    /**
418
     * Initializes a new ClassMetadata instance that will hold the object-document mapping
419
     * metadata of the class with the given name.
420
     *
421
     * @param string $documentName The name of the document class the new instance is used for.
422
     */
423 809
    public function __construct($documentName)
424
    {
425 809
        $this->name = $documentName;
426 809
        $this->rootDocumentName = $documentName;
427 809
    }
428
429
    /**
430
     * {@inheritDoc}
431
     */
432 763
    public function getReflectionClass()
433
    {
434 763
        if ( ! $this->reflClass) {
435 2
            $this->reflClass = new \ReflectionClass($this->name);
436 2
        }
437
438 763
        return $this->reflClass;
439
    }
440
441
    /**
442
     * {@inheritDoc}
443
     */
444 289
    public function isIdentifier($fieldName)
445
    {
446 289
        return $this->identifier === $fieldName;
447
    }
448
449
    /**
450
     * INTERNAL:
451
     * Sets the mapped identifier field of this class.
452
     *
453
     * @param string $identifier
454
     */
455 291
    public function setIdentifier($identifier)
456
    {
457 291
        $this->identifier = $identifier;
458 291
    }
459
460
    /**
461
     * {@inheritDoc}
462
     *
463
     * Since MongoDB only allows exactly one identifier field
464
     * this will always return an array with only one value
465
     */
466 25
    public function getIdentifier()
467
    {
468 25
        return array($this->identifier);
469
    }
470
471
    /**
472
     * {@inheritDoc}
473
     *
474
     * Since MongoDB only allows exactly one identifier field
475
     * this will always return an array with only one value
476
     */
477 89
    public function getIdentifierFieldNames()
478
    {
479 89
        return array($this->identifier);
480
    }
481
482
    /**
483
     * {@inheritDoc}
484
     */
485 506
    public function hasField($fieldName)
486
    {
487 506
        return isset($this->fieldMappings[$fieldName]);
488
    }
489
490
    /**
491
     * Sets the inheritance type used by the class and it's subclasses.
492
     *
493
     * @param integer $type
494
     */
495 302
    public function setInheritanceType($type)
496
    {
497 302
        $this->inheritanceType = $type;
498 302
    }
499
500
    /**
501
     * Checks whether a mapped field is inherited from an entity superclass.
502
     *
503
     * @param  string $fieldName
504
     *
505
     * @return boolean TRUE if the field is inherited, FALSE otherwise.
506
     */
507 763
    public function isInheritedField($fieldName)
508
    {
509 763
        return isset($this->fieldMappings[$fieldName]['inherited']);
510
    }
511
512
    /**
513
     * Registers a custom repository class for the document class.
514
     *
515
     * @param string $repositoryClassName The class name of the custom repository.
516
     */
517 255 View Code Duplication
    public function setCustomRepositoryClass($repositoryClassName)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
518
    {
519 255
        if ($this->isEmbeddedDocument) {
520
            return;
521
        }
522
        
523 255
        if ($repositoryClassName && strpos($repositoryClassName, '\\') === false && strlen($this->namespace)) {
524 3
            $repositoryClassName = $this->namespace . '\\' . $repositoryClassName;
525 3
        }
526
527 255
        $this->customRepositoryClassName = $repositoryClassName;
528 255
    }
529
530
    /**
531
     * Dispatches the lifecycle event of the given document by invoking all
532
     * registered callbacks.
533
     *
534
     * @param string $event     Lifecycle event
535
     * @param object $document  Document on which the event occurred
536
     * @param array  $arguments Arguments to pass to all callbacks
537
     * @throws \InvalidArgumentException if document class is not this class or
538
     *                                   a Proxy of this class
539
     */
540 175
    public function invokeLifecycleCallbacks($event, $document, array $arguments = null)
541
    {
542 175
        if (!$document instanceof $this->name) {
543 1
            throw new \InvalidArgumentException(sprintf('Expected document class "%s"; found: "%s"', $this->name, get_class($document)));
544
        }
545
546 174
        foreach ($this->lifecycleCallbacks[$event] as $callback) {
547 174
            if ($arguments !== null) {
548 173
                call_user_func_array(array($document, $callback), $arguments);
549 173
            } else {
550 2
                $document->$callback();
551
            }
552 174
        }
553 174
    }
554
555
    /**
556
     * Checks whether the class has callbacks registered for a lifecycle event.
557
     *
558
     * @param string $event Lifecycle event
559
     *
560
     * @return boolean
561
     */
562
    public function hasLifecycleCallbacks($event)
563
    {
564
        return ! empty($this->lifecycleCallbacks[$event]);
565
    }
566
567
    /**
568
     * Gets the registered lifecycle callbacks for an event.
569
     *
570
     * @param string $event
571
     * @return array
572
     */
573
    public function getLifecycleCallbacks($event)
574
    {
575
        return isset($this->lifecycleCallbacks[$event]) ? $this->lifecycleCallbacks[$event] : array();
576
    }
577
578
    /**
579
     * Adds a lifecycle callback for documents of this class.
580
     *
581
     * If the callback is already registered, this is a NOOP.
582
     *
583
     * @param string $callback
584
     * @param string $event
585
     */
586 235
    public function addLifecycleCallback($callback, $event)
587
    {
588 235
        if (isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event])) {
589 1
            return;
590
        }
591
592 235
        $this->lifecycleCallbacks[$event][] = $callback;
593 235
    }
594
595
    /**
596
     * Sets the lifecycle callbacks for documents of this class.
597
     *
598
     * Any previously registered callbacks are overwritten.
599
     *
600
     * @param array $callbacks
601
     */
602 290
    public function setLifecycleCallbacks(array $callbacks)
603
    {
604 290
        $this->lifecycleCallbacks = $callbacks;
605 290
    }
606
607
    /**
608
     * Registers a method for loading document data before field hydration.
609
     *
610
     * Note: A method may be registered multiple times for different fields.
611
     * it will be invoked only once for the first field found.
612
     *
613
     * @param string       $method Method name
614
     * @param array|string $fields Database field name(s)
615
     */
616 15
    public function registerAlsoLoadMethod($method, $fields)
617
    {
618 15
        $this->alsoLoadMethods[$method] = is_array($fields) ? $fields : array($fields);
619 15
    }
620
621
    /**
622
     * Sets the AlsoLoad methods for documents of this class.
623
     *
624
     * Any previously registered methods are overwritten.
625
     *
626
     * @param array $methods
627
     */
628 290
    public function setAlsoLoadMethods(array $methods)
629
    {
630 290
        $this->alsoLoadMethods = $methods;
631 290
    }
632
633
    /**
634
     * Sets the discriminator field.
635
     *
636
     * The field name is the the unmapped database field. Discriminator values
637
     * are only used to discern the hydration class and are not mapped to class
638
     * properties.
639
     *
640
     * @param string $discriminatorField
641
     *
642
     * @throws MappingException If the discriminator field conflicts with the
643
     *                          "name" attribute of a mapped field.
644
     */
645 311
    public function setDiscriminatorField($discriminatorField)
646
    {
647 311
        if ($discriminatorField === null) {
648 260
            $this->discriminatorField = null;
649
650 260
            return;
651
        }
652
653
        // Handle array argument with name/fieldName keys for BC
654 77
        if (is_array($discriminatorField)) {
655
            if (isset($discriminatorField['name'])) {
656
                $discriminatorField = $discriminatorField['name'];
657
            } elseif (isset($discriminatorField['fieldName'])) {
658
                $discriminatorField = $discriminatorField['fieldName'];
659
            }
660
        }
661
662 77
        foreach ($this->fieldMappings as $fieldMapping) {
663 4
            if ($discriminatorField == $fieldMapping['name']) {
664 1
                throw MappingException::discriminatorFieldConflict($this->name, $discriminatorField);
665
            }
666 76
        }
667
668 76
        $this->discriminatorField = $discriminatorField;
669 76
    }
670
671
    /**
672
     * Sets the discriminator values used by this class.
673
     * Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
674
     *
675
     * @param array $map
676
     *
677
     * @throws MappingException
678
     */
679 307
    public function setDiscriminatorMap(array $map)
680
    {
681 307
        foreach ($map as $value => $className) {
682 75
            if (strpos($className, '\\') === false && strlen($this->namespace)) {
683 43
                $className = $this->namespace . '\\' . $className;
684 43
            }
685 75
            $this->discriminatorMap[$value] = $className;
686 75
            if ($this->name == $className) {
687 67
                $this->discriminatorValue = $value;
688 67
            } else {
689 67
                if ( ! class_exists($className)) {
690
                    throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
691
                }
692 67
                if (is_subclass_of($className, $this->name)) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of might return inconsistent results on some PHP versions if $this->name can be an interface. If so, you could instead use ReflectionClass::implementsInterface.
Loading history...
693 53
                    $this->subClasses[] = $className;
694 53
                }
695
            }
696 307
        }
697 307
    }
698
699
    /**
700
     * Sets the default discriminator value to be used for this class
701
     * Used for JOINED and SINGLE_TABLE inheritance mapping strategies if the document has no discriminator value
702
     *
703
     * @param string $defaultDiscriminatorValue
704
     *
705
     * @throws MappingException
706
     */
707 296
    public function setDefaultDiscriminatorValue($defaultDiscriminatorValue)
708
    {
709 296
        if ($defaultDiscriminatorValue === null) {
710 290
            $this->defaultDiscriminatorValue = null;
711
712 290
            return;
713
        }
714
715 24
        if (!array_key_exists($defaultDiscriminatorValue, $this->discriminatorMap)) {
716
            throw MappingException::invalidDiscriminatorValue($defaultDiscriminatorValue, $this->name);
717
        }
718
719 24
        $this->defaultDiscriminatorValue = $defaultDiscriminatorValue;
720 24
    }
721
722
    /**
723
     * Sets the discriminator value for this class.
724
     * Used for JOINED/SINGLE_TABLE inheritance and multiple document types in a single
725
     * collection.
726
     *
727
     * @param string $value
728
     */
729
    public function setDiscriminatorValue($value)
730
    {
731
        $this->discriminatorMap[$value] = $this->name;
732
        $this->discriminatorValue = $value;
733
    }
734
735
    /**
736
     * Sets the slaveOkay option applied to collections for this class.
737
     *
738
     * @param boolean|null $slaveOkay
739
     */
740 3
    public function setSlaveOkay($slaveOkay)
741
    {
742 3
        $this->slaveOkay = $slaveOkay === null ? null : (boolean) $slaveOkay;
743 3
    }
744
745
    /**
746
     * Add a index for this Document.
747
     *
748
     * @param array $keys Array of keys for the index.
749
     * @param array $options Array of options for the index.
750
     */
751 186
    public function addIndex($keys, array $options = array())
752
    {
753 186
        $this->indexes[] = array(
754 186
            'keys' => array_map(function($value) {
755 186
                if ($value == 1 || $value == -1) {
756 26
                    return (int) $value;
757
                }
758 178
                if (is_string($value)) {
759 178
                    $lower = strtolower($value);
760 178
                    if ($lower === 'asc') {
761 171
                        return 1;
762 10
                    } elseif ($lower === 'desc') {
763 3
                        return -1;
764
                    }
765 7
                }
766 7
                return $value;
767 186
            }, $keys),
768
            'options' => $options
769 186
        );
770 186
    }
771
772
    /**
773
     * Set whether or not queries on this document should require indexes.
774
     *
775
     * @param bool $requireIndexes
776
     */
777 755
    public function setRequireIndexes($requireIndexes)
778
    {
779 755
        $this->requireIndexes = $requireIndexes;
780 755
    }
781
782
    /**
783
     * Returns the array of indexes for this Document.
784
     *
785
     * @return array $indexes The array of indexes.
786
     */
787 50
    public function getIndexes()
788
    {
789 50
        return $this->indexes;
790
    }
791
792
    /**
793
     * Checks whether this document has indexes or not.
794
     *
795
     * @return boolean
796
     */
797
    public function hasIndexes()
798
    {
799
        return $this->indexes ? true : false;
800
    }
801
802
    /**
803
     * Sets the change tracking policy used by this class.
804
     *
805
     * @param integer $policy
806
     */
807 294
    public function setChangeTrackingPolicy($policy)
808
    {
809 294
        $this->changeTrackingPolicy = $policy;
810 294
    }
811
812
    /**
813
     * Whether the change tracking policy of this class is "deferred explicit".
814
     *
815
     * @return boolean
816
     */
817 56
    public function isChangeTrackingDeferredExplicit()
818
    {
819 56
        return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_EXPLICIT;
820
    }
821
822
    /**
823
     * Whether the change tracking policy of this class is "deferred implicit".
824
     *
825
     * @return boolean
826
     */
827 560
    public function isChangeTrackingDeferredImplicit()
828
    {
829 560
        return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_IMPLICIT;
830
    }
831
832
    /**
833
     * Whether the change tracking policy of this class is "notify".
834
     *
835
     * @return boolean
836
     */
837 325
    public function isChangeTrackingNotify()
838
    {
839 325
        return $this->changeTrackingPolicy == self::CHANGETRACKING_NOTIFY;
840
    }
841
842
    /**
843
     * Gets the ReflectionProperties of the mapped class.
844
     *
845
     * @return array An array of ReflectionProperty instances.
846
     */
847 89
    public function getReflectionProperties()
848
    {
849 89
        return $this->reflFields;
850
    }
851
852
    /**
853
     * Gets a ReflectionProperty for a specific field of the mapped class.
854
     *
855
     * @param string $name
856
     *
857
     * @return \ReflectionProperty
858
     */
859
    public function getReflectionProperty($name)
860
    {
861
        return $this->reflFields[$name];
862
    }
863
864
    /**
865
     * {@inheritDoc}
866
     */
867 760
    public function getName()
868
    {
869 760
        return $this->name;
870
    }
871
872
    /**
873
     * The namespace this Document class belongs to.
874
     *
875
     * @return string $namespace The namespace name.
876
     */
877
    public function getNamespace()
878
    {
879
        return $this->namespace;
880
    }
881
882
    /**
883
     * Returns the database this Document is mapped to.
884
     *
885
     * @return string $db The database name.
886
     */
887 700
    public function getDatabase()
888
    {
889 700
        return $this->db;
890
    }
891
892
    /**
893
     * Set the database this Document is mapped to.
894
     *
895
     * @param string $db The database name
896
     */
897 52
    public function setDatabase($db)
898
    {
899 52
        $this->db = $db;
900 52
    }
901
902
    /**
903
     * Get the collection this Document is mapped to.
904
     *
905
     * @return string $collection The collection name.
906
     */
907 704
    public function getCollection()
908
    {
909 704
        return $this->collection;
910
    }
911
912
    /**
913
     * Sets the collection this Document is mapped to.
914
     *
915
     * @param array|string $name
916
     *
917
     * @throws \InvalidArgumentException
918
     */
919 789
    public function setCollection($name)
920
    {
921 789
        if (is_array($name)) {
922
            if ( ! isset($name['name'])) {
923
                throw new \InvalidArgumentException('A name key is required when passing an array to setCollection()');
924
            }
925
            $this->collectionCapped = isset($name['capped']) ? $name['capped'] : false;
926
            $this->collectionSize = isset($name['size']) ? $name['size'] : 0;
927
            $this->collectionMax = isset($name['max']) ? $name['max'] : 0;
928
            $this->collection = $name['name'];
929
        } else {
930 789
            $this->collection = $name;
931
        }
932 789
    }
933
934
    /**
935
     * Get whether or not the documents collection is capped.
936
     *
937
     * @return boolean
938
     */
939 4
    public function getCollectionCapped()
940
    {
941 4
        return $this->collectionCapped;
942
    }
943
944
    /**
945
     * Set whether or not the documents collection is capped.
946
     *
947
     * @param boolean $bool
948
     */
949 1
    public function setCollectionCapped($bool)
950
    {
951 1
        $this->collectionCapped = $bool;
952 1
    }
953
954
    /**
955
     * Get the collection size
956
     *
957
     * @return integer
958
     */
959 4
    public function getCollectionSize()
960
    {
961 4
        return $this->collectionSize;
962
    }
963
964
    /**
965
     * Set the collection size.
966
     *
967
     * @param integer $size
968
     */
969 1
    public function setCollectionSize($size)
970
    {
971 1
        $this->collectionSize = $size;
972 1
    }
973
974
    /**
975
     * Get the collection max.
976
     *
977
     * @return integer
978
     */
979 4
    public function getCollectionMax()
980
    {
981 4
        return $this->collectionMax;
982
    }
983
984
    /**
985
     * Set the collection max.
986
     *
987
     * @param integer $max
988
     */
989 1
    public function setCollectionMax($max)
990
    {
991 1
        $this->collectionMax = $max;
992 1
    }
993
994
    /**
995
     * Returns TRUE if this Document is mapped to a collection FALSE otherwise.
996
     *
997
     * @return boolean
998
     */
999
    public function isMappedToCollection()
1000
    {
1001
        return $this->collection ? true : false;
1002
    }
1003
1004
    /**
1005
     * Returns TRUE if this Document is a file to be stored on the MongoGridFS FALSE otherwise.
1006
     *
1007
     * @return boolean
1008
     */
1009 682
    public function isFile()
1010
    {
1011 682
        return $this->file ? true : false;
1012
    }
1013
1014
    /**
1015
     * Returns the file field name.
1016
     *
1017
     * @return string $file The file field name.
1018
     */
1019 290
    public function getFile()
1020
    {
1021 290
        return $this->file;
1022
    }
1023
1024
    /**
1025
     * Set the field name that stores the grid file.
1026
     *
1027
     * @param string $file
1028
     */
1029 291
    public function setFile($file)
1030
    {
1031 291
        $this->file = $file;
1032 291
    }
1033
1034
    /**
1035
     * Returns the distance field name.
1036
     *
1037
     * @return string $distance The distance field name.
1038
     */
1039
    public function getDistance()
1040
    {
1041
        return $this->distance;
1042
    }
1043
1044
    /**
1045
     * Set the field name that stores the distance.
1046
     *
1047
     * @param string $distance
1048
     */
1049 1
    public function setDistance($distance)
1050
    {
1051 1
        $this->distance = $distance;
1052 1
    }
1053
1054
    /**
1055
     * Map a field.
1056
     *
1057
     * @param array $mapping The mapping information.
1058
     *
1059
     * @return array
1060
     *
1061
     * @throws MappingException
1062
     */
1063 795
    public function mapField(array $mapping)
1064
    {
1065 795
        if ( ! isset($mapping['fieldName']) && isset($mapping['name'])) {
1066 6
            $mapping['fieldName'] = $mapping['name'];
1067 6
        }
1068 795
        if ( ! isset($mapping['fieldName'])) {
1069
            throw MappingException::missingFieldName($this->name);
1070
        }
1071 795
        if ( ! isset($mapping['name'])) {
1072 789
            $mapping['name'] = $mapping['fieldName'];
1073 789
        }
1074 795
        if ($this->identifier === $mapping['name'] && empty($mapping['id'])) {
1075 1
            throw MappingException::mustNotChangeIdentifierFieldsType($this->name, $mapping['name']);
1076
        }
1077 794
        if (isset($this->fieldMappings[$mapping['fieldName']])) {
1078
            //throw MappingException::duplicateFieldMapping($this->name, $mapping['fieldName']);
1079 24
        }
1080 794
        if ($this->discriminatorField !== null && $this->discriminatorField == $mapping['name']) {
1081 1
            throw MappingException::discriminatorFieldConflict($this->name, $this->discriminatorField);
1082
        }
1083 793 View Code Duplication
        if (isset($mapping['targetDocument']) && strpos($mapping['targetDocument'], '\\') === false && strlen($this->namespace)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1084 497
            $mapping['targetDocument'] = $this->namespace . '\\' . $mapping['targetDocument'];
1085 497
        }
1086 793 View Code Duplication
        if (isset($mapping['collectionClass']) && strpos($mapping['collectionClass'], '\\') === false && strlen($this->namespace)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1087 3
            $mapping['collectionClass'] = $this->namespace . '\\' . $mapping['collectionClass'];
1088 3
        }
1089 793
        if ( ! empty($mapping['collectionClass'])) {
1090 4
            $rColl = new \ReflectionClass($mapping['collectionClass']);
1091 4
            if ( ! $rColl->implementsInterface('Doctrine\\Common\\Collections\\Collection')) {
1092 1
                throw MappingException::collectionClassDoesNotImplementCommonInterface($this->name, $mapping['fieldName'], $mapping['collectionClass']);
1093
            }
1094 3
        }
1095
1096 792
        if (isset($mapping['discriminatorMap'])) {
1097 74
            foreach ($mapping['discriminatorMap'] as $key => $class) {
1098 74
                if (strpos($class, '\\') === false && strlen($this->namespace)) {
1099 39
                    $mapping['discriminatorMap'][$key] = $this->namespace . '\\' . $class;
1100 39
                }
1101 74
            }
1102 74
        }
1103
1104 792
        if (isset($mapping['cascade']) && isset($mapping['embedded'])) {
1105 1
            throw MappingException::cascadeOnEmbeddedNotAllowed($this->name, $mapping['fieldName']);
1106
        }
1107
1108 791
        $cascades = isset($mapping['cascade']) ? array_map('strtolower', (array) $mapping['cascade']) : array();
1109
1110 791
        if (in_array('all', $cascades) || isset($mapping['embedded'])) {
1111 521
            $cascades = array('remove', 'persist', 'refresh', 'merge', 'detach');
1112 521
        }
1113
1114 791
        if (isset($mapping['embedded'])) {
1115 493
            unset($mapping['cascade']);
1116 791
        } elseif (isset($mapping['cascade'])) {
1117 329
            $mapping['cascade'] = $cascades;
1118 329
        }
1119
1120 791
        $mapping['isCascadeRemove'] = in_array('remove', $cascades);
1121 791
        $mapping['isCascadePersist'] = in_array('persist', $cascades);
1122 791
        $mapping['isCascadeRefresh'] = in_array('refresh', $cascades);
1123 791
        $mapping['isCascadeMerge'] = in_array('merge', $cascades);
1124 791
        $mapping['isCascadeDetach'] = in_array('detach', $cascades);
1125
        
1126 791
        if (isset($mapping['type']) && $mapping['type'] === 'file') {
1127 27
            $mapping['file'] = true;
1128 27
        }
1129 791 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...
1130 27
            $this->file = $mapping['fieldName'];
1131 27
            $mapping['name'] = 'file';
1132 27
        }
1133 791 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...
1134 7
            $this->distance = $mapping['fieldName'];
1135 7
        }
1136 791
        if (isset($mapping['id']) && $mapping['id'] === true) {
1137 773
            $mapping['name'] = '_id';
1138 773
            $this->identifier = $mapping['fieldName'];
1139 773 View Code Duplication
            if (isset($mapping['strategy'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1140 761
                $this->generatorType = constant(ClassMetadata::class . '::GENERATOR_TYPE_' . strtoupper($mapping['strategy']));
1141 761
            }
1142 773
            $this->generatorOptions = isset($mapping['options']) ? $mapping['options'] : array();
1143 773
            switch ($this->generatorType) {
1144 773
                case self::GENERATOR_TYPE_AUTO:
1145 706
                    $mapping['type'] = 'id';
1146 706
                    break;
1147 120
                default:
1148 120
                    if ( ! empty($this->generatorOptions['type'])) {
1149 52
                        $mapping['type'] = $this->generatorOptions['type'];
1150 120
                    } elseif (empty($mapping['type'])) {
1151 45
                        $mapping['type'] = $this->generatorType === self::GENERATOR_TYPE_INCREMENT ? 'int_id' : 'custom_id';
1152 45
                    }
1153 773
            }
1154 773
            unset($this->generatorOptions['type']);
1155 773
        }
1156 791
        if ( ! isset($mapping['nullable'])) {
1157 35
            $mapping['nullable'] = false;
1158 35
        }
1159
1160 791
        if (isset($mapping['reference']) && ! empty($mapping['simple']) && ! isset($mapping['targetDocument'])) {
1161 1
            throw MappingException::simpleReferenceRequiresTargetDocument($this->name, $mapping['fieldName']);
1162
        }
1163
1164 790
        if (isset($mapping['reference']) && empty($mapping['targetDocument']) && empty($mapping['discriminatorMap']) &&
1165 790
                (isset($mapping['mappedBy']) || isset($mapping['inversedBy']))) {
1166 4
            throw MappingException::owningAndInverseReferencesRequireTargetDocument($this->name, $mapping['fieldName']);
1167
        }
1168
        
1169 786
        if ($this->isEmbeddedDocument && $mapping['type'] === 'many' && CollectionHelper::isAtomic($mapping['strategy'])) {
1170 1
            throw MappingException::atomicCollectionStrategyNotAllowed($mapping['strategy'], $this->name, $mapping['fieldName']);
1171
        }
1172
1173 785 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...
1174 417
            $mapping['association'] = self::REFERENCE_ONE;
1175 417
        }
1176 785 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...
1177 363
            $mapping['association'] = self::REFERENCE_MANY;
1178 363
        }
1179 785 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...
1180 374
            $mapping['association'] = self::EMBED_ONE;
1181 374
        }
1182 785 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...
1183 425
            $mapping['association'] = self::EMBED_MANY;
1184 425
        }
1185
1186 785
        if (isset($mapping['association']) && ! isset($mapping['targetDocument']) && ! isset($mapping['discriminatorField'])) {
1187 73
            $mapping['discriminatorField'] = self::DEFAULT_DISCRIMINATOR_FIELD;
1188 73
        }
1189
1190
        /*
1191
        if (isset($mapping['type']) && ($mapping['type'] === 'one' || $mapping['type'] === 'many')) {
1192
            $mapping['type'] = $mapping['type'] === 'one' ? self::ONE : self::MANY;
1193
        }
1194
        */
1195 785
        if (isset($mapping['version'])) {
1196 63
            $mapping['notSaved'] = true;
1197 63
            $this->setVersionMapping($mapping);
1198 62
        }
1199 785
        if (isset($mapping['lock'])) {
1200 26
            $mapping['notSaved'] = true;
1201 26
            $this->setLockMapping($mapping);
1202 25
        }
1203 785
        $mapping['isOwningSide'] = true;
1204 785
        $mapping['isInverseSide'] = false;
1205 785
        if (isset($mapping['reference'])) {
1206 476 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...
1207 177
                $mapping['isOwningSide'] = true;
1208 177
                $mapping['isInverseSide'] = false;
1209 177
            }
1210 476 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...
1211 222
                $mapping['isInverseSide'] = true;
1212 222
                $mapping['isOwningSide'] = false;
1213 222
            }
1214 476 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...
1215 164
                $mapping['isInverseSide'] = true;
1216 164
                $mapping['isOwningSide'] = false;
1217 164
            }
1218 476
            if (!isset($mapping['orphanRemoval'])) {
1219 456
                $mapping['orphanRemoval'] = false;
1220 456
            }
1221 476
        }
1222
1223 785
        if (isset($mapping['reference']) && $mapping['type'] === 'many' && $mapping['isOwningSide']
1224 785
            && ! empty($mapping['sort']) && ! CollectionHelper::usesSet($mapping['strategy'])) {
1225 1
            throw MappingException::referenceManySortMustNotBeUsedWithNonSetCollectionStrategy($this->name, $mapping['fieldName'], $mapping['strategy']);
1226
        }
1227
1228 784
        $this->fieldMappings[$mapping['fieldName']] = $mapping;
1229 784
        if (isset($mapping['association'])) {
1230 610
            $this->associationMappings[$mapping['fieldName']] = $mapping;
1231 610
        }
1232
1233 784
        return $mapping;
1234
    }
1235
1236
    /**
1237
     * Map a MongoGridFSFile.
1238
     *
1239
     * @param array $mapping The mapping information.
1240
     */
1241
    public function mapFile(array $mapping)
1242
    {
1243
        $mapping['file'] = true;
1244
        $mapping['type'] = 'file';
1245
        $this->mapField($mapping);
1246
    }
1247
1248
    /**
1249
     * Map a single embedded document.
1250
     *
1251
     * @param array $mapping The mapping information.
1252
     */
1253 6
    public function mapOneEmbedded(array $mapping)
1254
    {
1255 6
        $mapping['embedded'] = true;
1256 6
        $mapping['type'] = 'one';
1257 6
        $this->mapField($mapping);
1258 5
    }
1259
1260
    /**
1261
     * Map a collection of embedded documents.
1262
     *
1263
     * @param array $mapping The mapping information.
1264
     */
1265 3
    public function mapManyEmbedded(array $mapping)
1266
    {
1267 3
        $mapping['embedded'] = true;
1268 3
        $mapping['type'] = 'many';
1269 3
        $this->mapField($mapping);
1270 3
    }
1271
1272
    /**
1273
     * Map a single document reference.
1274
     *
1275
     * @param array $mapping The mapping information.
1276
     */
1277 8
    public function mapOneReference(array $mapping)
1278
    {
1279 8
        $mapping['reference'] = true;
1280 8
        $mapping['type'] = 'one';
1281 8
        $this->mapField($mapping);
1282 8
    }
1283
1284
    /**
1285
     * Map a collection of document references.
1286
     *
1287
     * @param array $mapping The mapping information.
1288
     */
1289 8
    public function mapManyReference(array $mapping)
1290
    {
1291 8
        $mapping['reference'] = true;
1292 8
        $mapping['type'] = 'many';
1293 8
        $this->mapField($mapping);
1294 8
    }
1295
1296
    /**
1297
     * INTERNAL:
1298
     * Adds a field mapping without completing/validating it.
1299
     * This is mainly used to add inherited field mappings to derived classes.
1300
     *
1301
     * @param array $fieldMapping
1302
     */
1303 77
    public function addInheritedFieldMapping(array $fieldMapping)
1304
    {
1305 77
        $this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping;
1306
1307 77
        if (isset($fieldMapping['association'])) {
1308 44
            $this->associationMappings[$fieldMapping['fieldName']] = $fieldMapping;
1309 44
        }
1310 77
    }
1311
1312
    /**
1313
     * INTERNAL:
1314
     * Adds an association mapping without completing/validating it.
1315
     * This is mainly used to add inherited association mappings to derived classes.
1316
     *
1317
     * @param array $mapping
1318
     *
1319
     * @return void
1320
     *
1321
     * @throws MappingException
1322
     */
1323 45
    public function addInheritedAssociationMapping(array $mapping/*, $owningClassName = null*/)
1324
    {
1325 45
        $this->associationMappings[$mapping['fieldName']] = $mapping;
1326 45
    }
1327
1328
    /**
1329
     * Checks whether the class has a mapped association with the given field name.
1330
     *
1331
     * @param string $fieldName
1332
     * @return boolean
1333
     */
1334 1
    public function hasReference($fieldName)
1335
    {
1336 1
        return isset($this->fieldMappings[$fieldName]['reference']);
1337
    }
1338
1339
    /**
1340
     * Checks whether the class has a mapped embed with the given field name.
1341
     *
1342
     * @param string $fieldName
1343
     * @return boolean
1344
     */
1345 1
    public function hasEmbed($fieldName)
1346
    {
1347 1
        return isset($this->fieldMappings[$fieldName]['embedded']);
1348
    }
1349
1350
    /**
1351
     * {@inheritDoc}
1352
     *
1353
     * Checks whether the class has a mapped association (embed or reference) with the given field name.
1354
     */
1355 1
    public function hasAssociation($fieldName)
1356
    {
1357 1
        return $this->hasReference($fieldName) || $this->hasEmbed($fieldName);
1358
    }
1359
1360
    /**
1361
     * {@inheritDoc}
1362
     *
1363
     * Checks whether the class has a mapped reference or embed for the specified field and
1364
     * is a single valued association.
1365
     */
1366
    public function isSingleValuedAssociation($fieldName)
1367
    {
1368
        return $this->isSingleValuedReference($fieldName) || $this->isSingleValuedEmbed($fieldName);
1369
    }
1370
1371
    /**
1372
     * {@inheritDoc}
1373
     *
1374
     * Checks whether the class has a mapped reference or embed for the specified field and
1375
     * is a collection valued association.
1376
     */
1377
    public function isCollectionValuedAssociation($fieldName)
1378
    {
1379
        return $this->isCollectionValuedReference($fieldName) || $this->isCollectionValuedEmbed($fieldName);
1380
    }
1381
1382
    /**
1383
     * Checks whether the class has a mapped association for the specified field
1384
     * and if yes, checks whether it is a single-valued association (to-one).
1385
     *
1386
     * @param string $fieldName
1387
     * @return boolean TRUE if the association exists and is single-valued, FALSE otherwise.
1388
     */
1389
    public function isSingleValuedReference($fieldName)
1390
    {
1391
        return isset($this->fieldMappings[$fieldName]['association']) &&
1392
            $this->fieldMappings[$fieldName]['association'] === self::REFERENCE_ONE;
1393
    }
1394
1395
    /**
1396
     * Checks whether the class has a mapped association for the specified field
1397
     * and if yes, checks whether it is a collection-valued association (to-many).
1398
     *
1399
     * @param string $fieldName
1400
     * @return boolean TRUE if the association exists and is collection-valued, FALSE otherwise.
1401
     */
1402
    public function isCollectionValuedReference($fieldName)
1403
    {
1404
        return isset($this->fieldMappings[$fieldName]['association']) &&
1405
            $this->fieldMappings[$fieldName]['association'] === self::REFERENCE_MANY;
1406
    }
1407
1408
    /**
1409
     * Checks whether the class has a mapped embedded document for the specified field
1410
     * and if yes, checks whether it is a single-valued association (to-one).
1411
     *
1412
     * @param string $fieldName
1413
     * @return boolean TRUE if the association exists and is single-valued, FALSE otherwise.
1414
     */
1415
    public function isSingleValuedEmbed($fieldName)
1416
    {
1417
        return isset($this->fieldMappings[$fieldName]['association']) &&
1418
            $this->fieldMappings[$fieldName]['association'] === self::EMBED_ONE;
1419
    }
1420
1421
    /**
1422
     * Checks whether the class has a mapped embedded document for the specified field
1423
     * and if yes, checks whether it is a collection-valued association (to-many).
1424
     *
1425
     * @param string $fieldName
1426
     * @return boolean TRUE if the association exists and is collection-valued, FALSE otherwise.
1427
     */
1428
    public function isCollectionValuedEmbed($fieldName)
1429
    {
1430
        return isset($this->fieldMappings[$fieldName]['association']) &&
1431
            $this->fieldMappings[$fieldName]['association'] === self::EMBED_MANY;
1432
    }
1433
1434
    /**
1435
     * Sets the ID generator used to generate IDs for instances of this class.
1436
     *
1437
     * @param \Doctrine\ODM\MongoDB\Id\AbstractIdGenerator $generator
1438
     */
1439 703
    public function setIdGenerator($generator)
1440
    {
1441 703
        $this->idGenerator = $generator;
1442 703
    }
1443
1444
    /**
1445
     * Casts the identifier to its portable PHP type.
1446
     *
1447
     * @param mixed $id
1448
     * @return mixed $id
1449
     */
1450 569
    public function getPHPIdentifierValue($id)
1451
    {
1452 569
        $idType = $this->fieldMappings[$this->identifier]['type'];
1453 569
        return Type::getType($idType)->convertToPHPValue($id);
1454
    }
1455
1456
    /**
1457
     * Casts the identifier to its database type.
1458
     *
1459
     * @param mixed $id
1460
     * @return mixed $id
1461
     */
1462 631
    public function getDatabaseIdentifierValue($id)
1463
    {
1464 631
        $idType = $this->fieldMappings[$this->identifier]['type'];
1465 631
        return Type::getType($idType)->convertToDatabaseValue($id);
1466
    }
1467
1468
    /**
1469
     * Sets the document identifier of a document.
1470
     *
1471
     * The value will be converted to a PHP type before being set.
1472
     *
1473
     * @param object $document
1474
     * @param mixed $id
1475
     */
1476 504
    public function setIdentifierValue($document, $id)
1477
    {
1478 504
        $id = $this->getPHPIdentifierValue($id);
1479 504
        $this->reflFields[$this->identifier]->setValue($document, $id);
1480 504
    }
1481
1482
    /**
1483
     * Gets the document identifier as a PHP type.
1484
     *
1485
     * @param object $document
1486
     * @return mixed $id
1487
     */
1488 584
    public function getIdentifierValue($document)
1489
    {
1490 584
        return $this->reflFields[$this->identifier]->getValue($document);
1491
    }
1492
1493
    /**
1494
     * {@inheritDoc}
1495
     *
1496
     * Since MongoDB only allows exactly one identifier field this is a proxy
1497
     * to {@see getIdentifierValue()} and returns an array with the identifier
1498
     * field as a key.
1499
     */
1500
    public function getIdentifierValues($object)
1501
    {
1502
        return array($this->identifier => $this->getIdentifierValue($object));
1503
    }
1504
1505
    /**
1506
     * Get the document identifier object as a database type.
1507
     *
1508
     * @param object $document
1509
     *
1510
     * @return \MongoId $id The MongoID object.
1511
     */
1512 32
    public function getIdentifierObject($document)
1513
    {
1514 32
        return $this->getDatabaseIdentifierValue($this->getIdentifierValue($document));
1515
    }
1516
1517
    /**
1518
     * Sets the specified field to the specified value on the given document.
1519
     *
1520
     * @param object $document
1521
     * @param string $field
1522
     * @param mixed $value
1523
     */
1524 7
    public function setFieldValue($document, $field, $value)
1525
    {
1526 7
        if ($document instanceof Proxy && ! $document->__isInitialized()) {
1527
            //property changes to an uninitialized proxy will not be tracked or persisted,
1528
            //so the proxy needs to be loaded first.
1529 1
            $document->__load();
1530 1
        }
1531
        
1532 7
        $this->reflFields[$field]->setValue($document, $value);
1533 7
    }
1534
1535
    /**
1536
     * Gets the specified field's value off the given document.
1537
     *
1538
     * @param object $document
1539
     * @param string $field
1540
     *
1541
     * @return mixed
1542
     */
1543 24
    public function getFieldValue($document, $field)
1544
    {
1545 24
        if ($document instanceof Proxy && $field !== $this->identifier && ! $document->__isInitialized()) {
1546 1
            $document->__load();
1547 1
        }
1548
        
1549 24
        return $this->reflFields[$field]->getValue($document);
1550
    }
1551
1552
    /**
1553
     * Gets the mapping of a field.
1554
     *
1555
     * @param string $fieldName  The field name.
1556
     *
1557
     * @return array  The field mapping.
1558
     *
1559
     * @throws MappingException if the $fieldName is not found in the fieldMappings array
1560
     *
1561
     * @throws MappingException
1562
     */
1563 84
    public function getFieldMapping($fieldName)
1564
    {
1565 84
        if ( ! isset($this->fieldMappings[$fieldName])) {
1566
            throw MappingException::mappingNotFound($this->name, $fieldName);
1567
        }
1568 84
        return $this->fieldMappings[$fieldName];
1569
    }
1570
1571
    /**
1572
     * Check if the field is not null.
1573
     *
1574
     * @param string $fieldName  The field name
1575
     *
1576
     * @return boolean  TRUE if the field is not null, FALSE otherwise.
1577
     */
1578 1
    public function isNullable($fieldName)
1579
    {
1580 1
        $mapping = $this->getFieldMapping($fieldName);
1581 1
        if ($mapping !== false) {
1582 1
            return isset($mapping['nullable']) && $mapping['nullable'] == true;
1583
        }
1584
        return false;
1585
    }
1586
1587
    /**
1588
     * Checks whether the document has a discriminator field and value configured.
1589
     *
1590
     * @return boolean
1591
     */
1592 469
    public function hasDiscriminator()
1593
    {
1594 469
        return isset($this->discriminatorField, $this->discriminatorValue);
1595
    }
1596
1597
    /**
1598
     * Sets the type of Id generator to use for the mapped class.
1599
     */
1600 296
    public function setIdGeneratorType($generatorType)
1601
    {
1602 296
        $this->generatorType = $generatorType;
1603 296
    }
1604
1605
    /**
1606
     * Sets the Id generator options.
1607
     */
1608
    public function setIdGeneratorOptions($generatorOptions)
1609
    {
1610
        $this->generatorOptions = $generatorOptions;
1611
    }
1612
1613
    /**
1614
     * @return boolean
1615
     */
1616 558
    public function isInheritanceTypeNone()
1617
    {
1618 558
        return $this->inheritanceType == self::INHERITANCE_TYPE_NONE;
1619
    }
1620
1621
    /**
1622
     * Checks whether the mapped class uses the SINGLE_COLLECTION inheritance mapping strategy.
1623
     *
1624
     * @return boolean
1625
     */
1626 290
    public function isInheritanceTypeSingleCollection()
1627
    {
1628 290
        return $this->inheritanceType == self::INHERITANCE_TYPE_SINGLE_COLLECTION;
1629
    }
1630
1631
    /**
1632
     * Checks whether the mapped class uses the COLLECTION_PER_CLASS inheritance mapping strategy.
1633
     *
1634
     * @return boolean
1635
     */
1636
    public function isInheritanceTypeCollectionPerClass()
1637
    {
1638
        return $this->inheritanceType == self::INHERITANCE_TYPE_COLLECTION_PER_CLASS;
1639
    }
1640
1641
    /**
1642
     * Sets the mapped subclasses of this class.
1643
     *
1644
     * @param string[] $subclasses The names of all mapped subclasses.
1645
     */
1646 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...
1647
    {
1648 2
        foreach ($subclasses as $subclass) {
1649 2
            if (strpos($subclass, '\\') === false && strlen($this->namespace)) {
1650 1
                $this->subClasses[] = $this->namespace . '\\' . $subclass;
1651 1
            } else {
1652 1
                $this->subClasses[] = $subclass;
1653
            }
1654 2
        }
1655 2
    }
1656
1657
    /**
1658
     * Sets the parent class names.
1659
     * Assumes that the class names in the passed array are in the order:
1660
     * directParent -> directParentParent -> directParentParentParent ... -> root.
1661
     *
1662
     * @param string[] $classNames
1663
     */
1664 758
    public function setParentClasses(array $classNames)
1665
    {
1666 758
        $this->parentClasses = $classNames;
1667
1668 758
        if (count($classNames) > 0) {
1669 63
            $this->rootDocumentName = array_pop($classNames);
1670 63
        }
1671 758
    }
1672
1673
    /**
1674
     * Checks whether the class will generate a new \MongoId instance for us.
1675
     *
1676
     * @return boolean TRUE if the class uses the AUTO generator, FALSE otherwise.
1677
     */
1678
    public function isIdGeneratorAuto()
1679
    {
1680
        return $this->generatorType == self::GENERATOR_TYPE_AUTO;
1681
    }
1682
1683
    /**
1684
     * Checks whether the class will use a collection to generate incremented identifiers.
1685
     *
1686
     * @return boolean TRUE if the class uses the INCREMENT generator, FALSE otherwise.
1687
     */
1688
    public function isIdGeneratorIncrement()
1689
    {
1690
        return $this->generatorType == self::GENERATOR_TYPE_INCREMENT;
1691
    }
1692
1693
    /**
1694
     * Checks whether the class will generate a uuid id.
1695
     *
1696
     * @return boolean TRUE if the class uses the UUID generator, FALSE otherwise.
1697
     */
1698
    public function isIdGeneratorUuid()
1699
    {
1700
        return $this->generatorType == self::GENERATOR_TYPE_UUID;
1701
    }
1702
1703
    /**
1704
     * Checks whether the class uses no id generator.
1705
     *
1706
     * @return boolean TRUE if the class does not use any id generator, FALSE otherwise.
1707
     */
1708
    public function isIdGeneratorNone()
1709
    {
1710
        return $this->generatorType == self::GENERATOR_TYPE_NONE;
1711
    }
1712
1713
    /**
1714
     * Sets the version field mapping used for versioning. Sets the default
1715
     * value to use depending on the column type.
1716
     *
1717
     * @param array $mapping   The version field mapping array
1718
     * 
1719
     * @throws LockException
1720
     */
1721 63
    public function setVersionMapping(array &$mapping)
1722
    {
1723 63
        if ($mapping['type'] !== 'int' && $mapping['type'] !== 'date') {
1724 1
            throw LockException::invalidVersionFieldType($mapping['type']);
1725
        }
1726
1727 62
        $this->isVersioned  = true;
1728 62
        $this->versionField = $mapping['fieldName'];
1729 62
    }
1730
1731
    /**
1732
     * Sets whether this class is to be versioned for optimistic locking.
1733
     *
1734
     * @param boolean $bool
1735
     */
1736 290
    public function setVersioned($bool)
1737
    {
1738 290
        $this->isVersioned = $bool;
1739 290
    }
1740
1741
    /**
1742
     * Sets the name of the field that is to be used for versioning if this class is
1743
     * versioned for optimistic locking.
1744
     *
1745
     * @param string $versionField
1746
     */
1747 290
    public function setVersionField($versionField)
1748
    {
1749 290
        $this->versionField = $versionField;
1750 290
    }
1751
1752
    /**
1753
     * Sets the version field mapping used for versioning. Sets the default
1754
     * value to use depending on the column type.
1755
     *
1756
     * @param array $mapping   The version field mapping array
1757
     *
1758
     * @throws \Doctrine\ODM\MongoDB\LockException
1759
     */
1760 26
    public function setLockMapping(array &$mapping)
1761
    {
1762 26
        if ($mapping['type'] !== 'int') {
1763 1
            throw LockException::invalidLockFieldType($mapping['type']);
1764
        }
1765
1766 25
        $this->isLockable = true;
1767 25
        $this->lockField = $mapping['fieldName'];
1768 25
    }
1769
1770
    /**
1771
     * Sets whether this class is to allow pessimistic locking.
1772
     *
1773
     * @param boolean $bool
1774
     */
1775
    public function setLockable($bool)
1776
    {
1777
        $this->isLockable = $bool;
1778
    }
1779
1780
    /**
1781
     * Sets the name of the field that is to be used for storing whether a document
1782
     * is currently locked or not.
1783
     *
1784
     * @param string $lockField
1785
     */
1786
    public function setLockField($lockField)
1787
    {
1788
        $this->lockField = $lockField;
1789
    }
1790
1791
    /**
1792
     * {@inheritDoc}
1793
     */
1794
    public function getFieldNames()
1795
    {
1796
        return array_keys($this->fieldMappings);
1797
    }
1798
1799
    /**
1800
     * {@inheritDoc}
1801
     */
1802
    public function getAssociationNames()
1803
    {
1804
        return array_keys($this->associationMappings);
1805
    }
1806
1807
    /**
1808
     * {@inheritDoc}
1809
     */
1810 21
    public function getTypeOfField($fieldName)
1811
    {
1812 21
        return isset($this->fieldMappings[$fieldName]) ?
1813 21
            $this->fieldMappings[$fieldName]['type'] : null;
1814
    }
1815
1816
    /**
1817
     * {@inheritDoc}
1818
     */
1819 6
    public function getAssociationTargetClass($assocName)
1820
    {
1821 6
        if ( ! isset($this->associationMappings[$assocName])) {
1822 3
            throw new InvalidArgumentException("Association name expected, '" . $assocName . "' is not an association.");
1823
        }
1824
1825 3
        return $this->associationMappings[$assocName]['targetDocument'];
1826
    }
1827
1828
    /**
1829
     * {@inheritDoc}
1830
     */
1831
    public function isAssociationInverseSide($fieldName)
1832
    {
1833
        throw new \BadMethodCallException(__METHOD__ . '() is not implemented yet.');
1834
    }
1835
1836
    /**
1837
     * {@inheritDoc}
1838
     */
1839
    public function getAssociationMappedByTargetField($fieldName)
1840
    {
1841
        throw new \BadMethodCallException(__METHOD__ . '() is not implemented yet.');
1842
    }
1843
}
1844