Completed
Pull Request — master (#1424)
by Andreas
11:09
created

ClassMetadataInfo::mapField()   F

Complexity

Conditions 83
Paths > 20000

Size

Total Lines 189
Code Lines 116

Duplication

Lines 43
Ratio 22.75 %

Code Coverage

Tests 114
CRAP Score 83.0044

Importance

Changes 11
Bugs 1 Features 3
Metric Value
c 11
b 1
f 3
dl 43
loc 189
ccs 114
cts 115
cp 0.9913
rs 2
cc 83
eloc 116
nc 4294967295
nop 1
crap 83.0044

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\ODM\MongoDB\Mapping;
21
22
use Doctrine\ODM\MongoDB\Utility\CollectionHelper;
23
use Doctrine\ODM\MongoDB\LockException;
24
use Doctrine\ODM\MongoDB\Proxy\Proxy;
25
use Doctrine\ODM\MongoDB\Types\Type;
26
use InvalidArgumentException;
27
28
/**
29
 * A <tt>ClassMetadata</tt> instance holds all the object-document mapping metadata
30
 * of a document and it's references.
31
 *
32
 * Once populated, ClassMetadata instances are usually cached in a serialized form.
33
 *
34
 * <b>IMPORTANT NOTE:</b>
35
 *
36
 * The fields of this class are only public for 2 reasons:
37
 * 1) To allow fast READ access.
38
 * 2) To drastically reduce the size of a serialized instance (private/protected members
39
 *    get the whole class name, namespace inclusive, prepended to every property in
40
 *    the serialized representation).
41
 *
42
 * @since       1.0
43
 */
44
class ClassMetadataInfo implements \Doctrine\Common\Persistence\Mapping\ClassMetadata
45
{
46
    /* The Id generator types. */
47
    /**
48
     * AUTO means Doctrine will automatically create a new \MongoId instance for us.
49
     */
50
    const GENERATOR_TYPE_AUTO = 1;
51
52
    /**
53
     * INCREMENT means a separate collection is used for maintaining and incrementing id generation.
54
     * Offers full portability.
55
     */
56
    const GENERATOR_TYPE_INCREMENT = 2;
57
58
    /**
59
     * UUID means Doctrine will generate a uuid for us.
60
     */
61
    const GENERATOR_TYPE_UUID = 3;
62
63
    /**
64
     * ALNUM means Doctrine will generate Alpha-numeric string identifiers, using the INCREMENT
65
     * generator to ensure identifier uniqueness
66
     */
67
    const GENERATOR_TYPE_ALNUM = 4;
68
69
    /**
70
     * CUSTOM means Doctrine expect a class parameter. It will then try to initiate that class
71
     * and pass other options to the generator. It will throw an Exception if the class
72
     * does not exist or if an option was passed for that there is not setter in the new
73
     * generator class.
74
     *
75
     * The class  will have to be a subtype of AbstractIdGenerator.
76
     */
77
    const GENERATOR_TYPE_CUSTOM = 5;
78
79
    /**
80
     * NONE means Doctrine will not generate any id for us and you are responsible for manually
81
     * assigning an id.
82
     */
83
    const GENERATOR_TYPE_NONE = 6;
84
85
    /**
86
     * Default discriminator field name.
87
     *
88
     * This is used for associations value for associations where a that do not define a "targetDocument" or
89
     * "discriminatorField" option in their mapping.
90
     */
91
    const DEFAULT_DISCRIMINATOR_FIELD = '_doctrine_class_name';
92
93
    const REFERENCE_ONE = 1;
94
    const REFERENCE_MANY = 2;
95
    const EMBED_ONE = 3;
96
    const EMBED_MANY = 4;
97
    const MANY = 'many';
98
    const ONE = 'one';
99
100
    /**
101
     * The types of storeAs references
102
     */
103
    const REFERENCE_STORE_AS_ID = 'id';
104
    const REFERENCE_STORE_AS_DB_REF = 'dbRef';
105
    const REFERENCE_STORE_AS_DB_REF_WITH_DB = 'dbRefWithDb';
106
107
    /* The inheritance mapping types */
108
    /**
109
     * NONE means the class does not participate in an inheritance hierarchy
110
     * and therefore does not need an inheritance mapping type.
111
     */
112
    const INHERITANCE_TYPE_NONE = 1;
113
114
    /**
115
     * SINGLE_COLLECTION means the class will be persisted according to the rules of
116
     * <tt>Single Collection Inheritance</tt>.
117
     */
118
    const INHERITANCE_TYPE_SINGLE_COLLECTION = 2;
119
120
    /**
121
     * COLLECTION_PER_CLASS means the class will be persisted according to the rules
122
     * of <tt>Concrete Collection Inheritance</tt>.
123
     */
124
    const INHERITANCE_TYPE_COLLECTION_PER_CLASS = 3;
125
126
    /**
127
     * DEFERRED_IMPLICIT means that changes of entities are calculated at commit-time
128
     * by doing a property-by-property comparison with the original data. This will
129
     * be done for all entities that are in MANAGED state at commit-time.
130
     *
131
     * This is the default change tracking policy.
132
     */
133
    const CHANGETRACKING_DEFERRED_IMPLICIT = 1;
134
135
    /**
136
     * DEFERRED_EXPLICIT means that changes of entities are calculated at commit-time
137
     * by doing a property-by-property comparison with the original data. This will
138
     * be done only for entities that were explicitly saved (through persist() or a cascade).
139
     */
140
    const CHANGETRACKING_DEFERRED_EXPLICIT = 2;
141
142
    /**
143
     * NOTIFY means that Doctrine relies on the entities sending out notifications
144
     * when their properties change. Such entity classes must implement
145
     * the <tt>NotifyPropertyChanged</tt> interface.
146
     */
147
    const CHANGETRACKING_NOTIFY = 3;
148
149
    /**
150
     * SET means that fields will be written to the database using a $set operator
151
     */
152
    const STORAGE_STRATEGY_SET = 'set';
153
154
    /**
155
     * INCREMENT means that fields will be written to the database by calculating
156
     * the difference and using the $inc operator
157
     */
158
    const STORAGE_STRATEGY_INCREMENT = 'increment';
159
160
    const STORAGE_STRATEGY_PUSH_ALL = 'pushAll';
161
    const STORAGE_STRATEGY_ADD_TO_SET = 'addToSet';
162
    const STORAGE_STRATEGY_ATOMIC_SET = 'atomicSet';
163
    const STORAGE_STRATEGY_ATOMIC_SET_ARRAY = 'atomicSetArray';
164
    const STORAGE_STRATEGY_SET_ARRAY = 'setArray';
165
166
    /**
167
     * READ-ONLY: The name of the mongo database the document is mapped to.
168
     */
169
    public $db;
170
171
    /**
172
     * READ-ONLY: The name of the mongo collection the document is mapped to.
173
     */
174
    public $collection;
175
176
    /**
177
     * READ-ONLY: If the collection should be a fixed size.
178
     */
179
    public $collectionCapped;
180
181
    /**
182
     * READ-ONLY: If the collection is fixed size, its size in bytes.
183
     */
184
    public $collectionSize;
185
186
    /**
187
     * READ-ONLY: If the collection is fixed size, the maximum number of elements to store in the collection.
188
     */
189
    public $collectionMax;
190
191
    /**
192
     * READ-ONLY: The field name of the document identifier.
193
     */
194
    public $identifier;
195
196
    /**
197
     * READ-ONLY: The field that stores a file reference and indicates the
198
     * document is a file and should be stored on the MongoGridFS.
199
     */
200
    public $file;
201
202
    /**
203
     * READ-ONLY: The field that stores the calculated distance when performing geo spatial
204
     * queries.
205
     */
206
    public $distance;
207
208
    /**
209
     * READ-ONLY: Whether or not reads for this class are okay to read from a slave.
210
     */
211
    public $slaveOkay;
212
213
    /**
214
     * READ-ONLY: The array of indexes for the document collection.
215
     */
216
    public $indexes = array();
217
218
    /**
219
     * READ-ONLY: Keys and options describing shard key. Only for sharded collections.
220
     */
221
    public $shardKey;
222
223
    /**
224
     * READ-ONLY: Whether or not queries on this document should require indexes.
225
     */
226
    public $requireIndexes = false;
227
228
    /**
229
     * READ-ONLY: The name of the document class.
230
     */
231
    public $name;
232
233
    /**
234
     * READ-ONLY: The namespace the document class is contained in.
235
     *
236
     * @var string
237
     * @todo Not really needed. Usage could be localized.
238
     */
239
    public $namespace;
240
241
    /**
242
     * READ-ONLY: The name of the document class that is at the root of the mapped document inheritance
243
     * hierarchy. If the document is not part of a mapped inheritance hierarchy this is the same
244
     * as {@link $documentName}.
245
     *
246
     * @var string
247
     */
248
    public $rootDocumentName;
249
250
    /**
251
     * The name of the custom repository class used for the document class.
252
     * (Optional).
253
     *
254
     * @var string
255
     */
256
    public $customRepositoryClassName;
257
258
    /**
259
     * READ-ONLY: The names of the parent classes (ancestors).
260
     *
261
     * @var array
262
     */
263
    public $parentClasses = array();
264
265
    /**
266
     * READ-ONLY: The names of all subclasses (descendants).
267
     *
268
     * @var array
269
     */
270
    public $subClasses = array();
271
272
    /**
273
     * The ReflectionProperty instances of the mapped class.
274
     *
275
     * @var \ReflectionProperty[]
276
     */
277
    public $reflFields = array();
278
279
    /**
280
     * READ-ONLY: The inheritance mapping type used by the class.
281
     *
282
     * @var integer
283
     */
284
    public $inheritanceType = self::INHERITANCE_TYPE_NONE;
285
286
    /**
287
     * READ-ONLY: The Id generator type used by the class.
288
     *
289
     * @var string
290
     */
291
    public $generatorType = self::GENERATOR_TYPE_AUTO;
292
293
    /**
294
     * READ-ONLY: The Id generator options.
295
     *
296
     * @var array
297
     */
298
    public $generatorOptions = array();
299
300
    /**
301
     * READ-ONLY: The ID generator used for generating IDs for this class.
302
     *
303
     * @var \Doctrine\ODM\MongoDB\Id\AbstractIdGenerator
304
     */
305
    public $idGenerator;
306
307
    /**
308
     * READ-ONLY: The field mappings of the class.
309
     * Keys are field names and values are mapping definitions.
310
     *
311
     * The mapping definition array has the following values:
312
     *
313
     * - <b>fieldName</b> (string)
314
     * The name of the field in the Document.
315
     *
316
     * - <b>id</b> (boolean, optional)
317
     * Marks the field as the primary key of the document. Multiple fields of an
318
     * document can have the id attribute, forming a composite key.
319
     *
320
     * @var array
321
     */
322
    public $fieldMappings = array();
323
324
    /**
325
     * READ-ONLY: The association mappings of the class.
326
     * Keys are field names and values are mapping definitions.
327
     *
328
     * @var array
329
     */
330
    public $associationMappings = array();
331
332
    /**
333
     * READ-ONLY: Array of fields to also load with a given method.
334
     *
335
     * @var array
336
     */
337
    public $alsoLoadMethods = array();
338
339
    /**
340
     * READ-ONLY: The registered lifecycle callbacks for documents of this class.
341
     *
342
     * @var array
343
     */
344
    public $lifecycleCallbacks = array();
345
346
    /**
347
     * READ-ONLY: The discriminator value of this class.
348
     *
349
     * <b>This does only apply to the JOINED and SINGLE_COLLECTION inheritance mapping strategies
350
     * where a discriminator field is used.</b>
351
     *
352
     * @var mixed
353
     * @see discriminatorField
354
     */
355
    public $discriminatorValue;
356
357
    /**
358
     * READ-ONLY: The discriminator map of all mapped classes in the hierarchy.
359
     *
360
     * <b>This does only apply to the SINGLE_COLLECTION inheritance mapping strategy
361
     * where a discriminator field is used.</b>
362
     *
363
     * @var mixed
364
     * @see discriminatorField
365
     */
366
    public $discriminatorMap = array();
367
368
    /**
369
     * READ-ONLY: The definition of the discriminator field used in SINGLE_COLLECTION
370
     * inheritance mapping.
371
     *
372
     * @var string
373
     */
374
    public $discriminatorField;
375
376
    /**
377
     * READ-ONLY: The default value for discriminatorField in case it's not set in the document
378
     *
379
     * @var string
380
     * @see discriminatorField
381
     */
382
    public $defaultDiscriminatorValue;
383
384
    /**
385
     * READ-ONLY: Whether this class describes the mapping of a mapped superclass.
386
     *
387
     * @var boolean
388
     */
389
    public $isMappedSuperclass = false;
390
391
    /**
392
     * READ-ONLY: Whether this class describes the mapping of a embedded document.
393
     *
394
     * @var boolean
395
     */
396
    public $isEmbeddedDocument = false;
397
398
    /**
399
     * READ-ONLY: The policy used for change-tracking on entities of this class.
400
     *
401
     * @var integer
402
     */
403
    public $changeTrackingPolicy = self::CHANGETRACKING_DEFERRED_IMPLICIT;
404
405
    /**
406
     * READ-ONLY: A flag for whether or not instances of this class are to be versioned
407
     * with optimistic locking.
408
     *
409
     * @var boolean $isVersioned
410
     */
411
    public $isVersioned;
412
413
    /**
414
     * READ-ONLY: The name of the field which is used for versioning in optimistic locking (if any).
415
     *
416
     * @var mixed $versionField
417
     */
418
    public $versionField;
419
420
    /**
421
     * READ-ONLY: A flag for whether or not instances of this class are to allow pessimistic
422
     * locking.
423
     *
424
     * @var boolean $isLockable
425
     */
426
    public $isLockable;
427
428
    /**
429
     * READ-ONLY: The name of the field which is used for locking a document.
430
     *
431
     * @var mixed $lockField
432
     */
433
    public $lockField;
434
435
    /**
436
     * The ReflectionClass instance of the mapped class.
437
     *
438
     * @var \ReflectionClass
439
     */
440
    public $reflClass;
441
442
    /**
443
     * Initializes a new ClassMetadata instance that will hold the object-document mapping
444
     * metadata of the class with the given name.
445
     *
446
     * @param string $documentName The name of the document class the new instance is used for.
447
     */
448 920
    public function __construct($documentName)
449
    {
450 920
        $this->name = $documentName;
451 920
        $this->rootDocumentName = $documentName;
452 920
    }
453
454
    /**
455
     * {@inheritDoc}
456
     */
457 855
    public function getReflectionClass()
458
    {
459 855
        if ( ! $this->reflClass) {
460 2
            $this->reflClass = new \ReflectionClass($this->name);
461
        }
462
463 855
        return $this->reflClass;
464
    }
465
466
    /**
467
     * {@inheritDoc}
468
     */
469 308
    public function isIdentifier($fieldName)
470
    {
471 308
        return $this->identifier === $fieldName;
472
    }
473
474
    /**
475
     * INTERNAL:
476
     * Sets the mapped identifier field of this class.
477
     *
478
     * @param string $identifier
479
     */
480 346
    public function setIdentifier($identifier)
481
    {
482 346
        $this->identifier = $identifier;
483 346
    }
484
485
    /**
486
     * {@inheritDoc}
487
     *
488
     * Since MongoDB only allows exactly one identifier field
489
     * this will always return an array with only one value
490
     */
491 26
    public function getIdentifier()
492
    {
493 26
        return array($this->identifier);
494
    }
495
496
    /**
497
     * {@inheritDoc}
498
     *
499
     * Since MongoDB only allows exactly one identifier field
500
     * this will always return an array with only one value
501
     */
502 94
    public function getIdentifierFieldNames()
503
    {
504 94
        return array($this->identifier);
505
    }
506
507
    /**
508
     * {@inheritDoc}
509
     */
510 533
    public function hasField($fieldName)
511
    {
512 533
        return isset($this->fieldMappings[$fieldName]);
513
    }
514
515
    /**
516
     * Sets the inheritance type used by the class and it's subclasses.
517
     *
518
     * @param integer $type
519
     */
520 362
    public function setInheritanceType($type)
521
    {
522 362
        $this->inheritanceType = $type;
523 362
    }
524
525
    /**
526
     * Checks whether a mapped field is inherited from an entity superclass.
527
     *
528
     * @param  string $fieldName
529
     *
530
     * @return boolean TRUE if the field is inherited, FALSE otherwise.
531
     */
532 855
    public function isInheritedField($fieldName)
533
    {
534 855
        return isset($this->fieldMappings[$fieldName]['inherited']);
535
    }
536
537
    /**
538
     * Registers a custom repository class for the document class.
539
     *
540
     * @param string $repositoryClassName The class name of the custom repository.
541
     */
542 302 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...
543
    {
544 302
        if ($this->isEmbeddedDocument) {
545
            return;
546
        }
547
548 302
        if ($repositoryClassName && strpos($repositoryClassName, '\\') === false && strlen($this->namespace)) {
549 3
            $repositoryClassName = $this->namespace . '\\' . $repositoryClassName;
550
        }
551
552 302
        $this->customRepositoryClassName = $repositoryClassName;
553 302
    }
554
555
    /**
556
     * Dispatches the lifecycle event of the given document by invoking all
557
     * registered callbacks.
558
     *
559
     * @param string $event     Lifecycle event
560
     * @param object $document  Document on which the event occurred
561
     * @param array  $arguments Arguments to pass to all callbacks
562
     * @throws \InvalidArgumentException if document class is not this class or
563
     *                                   a Proxy of this class
564
     */
565 618
    public function invokeLifecycleCallbacks($event, $document, array $arguments = null)
566
    {
567 618
        if ( ! $document instanceof $this->name) {
568 1
            throw new \InvalidArgumentException(sprintf('Expected document class "%s"; found: "%s"', $this->name, get_class($document)));
569
        }
570
571 617
        if (empty($this->lifecycleCallbacks[$event])) {
572 603
            return;
573
        }
574
575 185
        foreach ($this->lifecycleCallbacks[$event] as $callback) {
576 185
            if ($arguments !== null) {
577 184
                call_user_func_array(array($document, $callback), $arguments);
578
            } else {
579 185
                $document->$callback();
580
            }
581
        }
582 185
    }
583
584
    /**
585
     * Checks whether the class has callbacks registered for a lifecycle event.
586
     *
587
     * @param string $event Lifecycle event
588
     *
589
     * @return boolean
590
     */
591
    public function hasLifecycleCallbacks($event)
592
    {
593
        return ! empty($this->lifecycleCallbacks[$event]);
594
    }
595
596
    /**
597
     * Gets the registered lifecycle callbacks for an event.
598
     *
599
     * @param string $event
600
     * @return array
601
     */
602
    public function getLifecycleCallbacks($event)
603
    {
604
        return isset($this->lifecycleCallbacks[$event]) ? $this->lifecycleCallbacks[$event] : array();
605
    }
606
607
    /**
608
     * Adds a lifecycle callback for documents of this class.
609
     *
610
     * If the callback is already registered, this is a NOOP.
611
     *
612
     * @param string $callback
613
     * @param string $event
614
     */
615 281
    public function addLifecycleCallback($callback, $event)
616
    {
617 281
        if (isset($this->lifecycleCallbacks[$event]) && in_array($callback, $this->lifecycleCallbacks[$event])) {
618 1
            return;
619
        }
620
621 281
        $this->lifecycleCallbacks[$event][] = $callback;
622 281
    }
623
624
    /**
625
     * Sets the lifecycle callbacks for documents of this class.
626
     *
627
     * Any previously registered callbacks are overwritten.
628
     *
629
     * @param array $callbacks
630
     */
631 345
    public function setLifecycleCallbacks(array $callbacks)
632
    {
633 345
        $this->lifecycleCallbacks = $callbacks;
634 345
    }
635
636
    /**
637
     * Registers a method for loading document data before field hydration.
638
     *
639
     * Note: A method may be registered multiple times for different fields.
640
     * it will be invoked only once for the first field found.
641
     *
642
     * @param string       $method Method name
643
     * @param array|string $fields Database field name(s)
644
     */
645 15
    public function registerAlsoLoadMethod($method, $fields)
646
    {
647 15
        $this->alsoLoadMethods[$method] = is_array($fields) ? $fields : array($fields);
648 15
    }
649
650
    /**
651
     * Sets the AlsoLoad methods for documents of this class.
652
     *
653
     * Any previously registered methods are overwritten.
654
     *
655
     * @param array $methods
656
     */
657 345
    public function setAlsoLoadMethods(array $methods)
658
    {
659 345
        $this->alsoLoadMethods = $methods;
660 345
    }
661
662
    /**
663
     * Sets the discriminator field.
664
     *
665
     * The field name is the the unmapped database field. Discriminator values
666
     * are only used to discern the hydration class and are not mapped to class
667
     * properties.
668
     *
669
     * @param string $discriminatorField
670
     *
671
     * @throws MappingException If the discriminator field conflicts with the
672
     *                          "name" attribute of a mapped field.
673
     */
674 371
    public function setDiscriminatorField($discriminatorField)
675
    {
676 371
        if ($discriminatorField === null) {
677 311
            $this->discriminatorField = null;
678
679 311
            return;
680
        }
681
682
        // Handle array argument with name/fieldName keys for BC
683 117
        if (is_array($discriminatorField)) {
684
            if (isset($discriminatorField['name'])) {
685
                $discriminatorField = $discriminatorField['name'];
686
            } elseif (isset($discriminatorField['fieldName'])) {
687
                $discriminatorField = $discriminatorField['fieldName'];
688
            }
689
        }
690
691 117
        foreach ($this->fieldMappings as $fieldMapping) {
692 4
            if ($discriminatorField == $fieldMapping['name']) {
693 4
                throw MappingException::discriminatorFieldConflict($this->name, $discriminatorField);
694
            }
695
        }
696
697 116
        $this->discriminatorField = $discriminatorField;
698 116
    }
699
700
    /**
701
     * Sets the discriminator values used by this class.
702
     * Used for JOINED and SINGLE_TABLE inheritance mapping strategies.
703
     *
704
     * @param array $map
705
     *
706
     * @throws MappingException
707
     */
708 367
    public function setDiscriminatorMap(array $map)
709
    {
710 367
        foreach ($map as $value => $className) {
711 115
            if (strpos($className, '\\') === false && strlen($this->namespace)) {
712 83
                $className = $this->namespace . '\\' . $className;
713
            }
714 115
            $this->discriminatorMap[$value] = $className;
715 115
            if ($this->name == $className) {
716 107
                $this->discriminatorValue = $value;
717
            } else {
718 111
                if ( ! class_exists($className)) {
719
                    throw MappingException::invalidClassInDiscriminatorMap($className, $this->name);
720
                }
721 111
                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...
722 115
                    $this->subClasses[] = $className;
723
                }
724
            }
725
        }
726 367
    }
727
728
    /**
729
     * Sets the default discriminator value to be used for this class
730
     * Used for JOINED and SINGLE_TABLE inheritance mapping strategies if the document has no discriminator value
731
     *
732
     * @param string $defaultDiscriminatorValue
733
     *
734
     * @throws MappingException
735
     */
736 351
    public function setDefaultDiscriminatorValue($defaultDiscriminatorValue)
737
    {
738 351
        if ($defaultDiscriminatorValue === null) {
739 345
            $this->defaultDiscriminatorValue = null;
740
741 345
            return;
742
        }
743
744 59
        if (!array_key_exists($defaultDiscriminatorValue, $this->discriminatorMap)) {
745
            throw MappingException::invalidDiscriminatorValue($defaultDiscriminatorValue, $this->name);
746
        }
747
748 59
        $this->defaultDiscriminatorValue = $defaultDiscriminatorValue;
749 59
    }
750
751
    /**
752
     * Sets the discriminator value for this class.
753
     * Used for JOINED/SINGLE_TABLE inheritance and multiple document types in a single
754
     * collection.
755
     *
756
     * @param string $value
757
     */
758
    public function setDiscriminatorValue($value)
759
    {
760
        $this->discriminatorMap[$value] = $this->name;
761
        $this->discriminatorValue = $value;
762
    }
763
764
    /**
765
     * Sets the slaveOkay option applied to collections for this class.
766
     *
767
     * @param boolean|null $slaveOkay
768
     */
769 3
    public function setSlaveOkay($slaveOkay)
770
    {
771 3
        $this->slaveOkay = $slaveOkay === null ? null : (boolean) $slaveOkay;
772 3
    }
773
774
    /**
775
     * Add a index for this Document.
776
     *
777
     * @param array $keys Array of keys for the index.
778
     * @param array $options Array of options for the index.
779
     */
780 216
    public function addIndex($keys, array $options = array())
781
    {
782 216
        $this->indexes[] = array(
783 View Code Duplication
            'keys' => array_map(function($value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
784 216
                if ($value == 1 || $value == -1) {
785 60
                    return (int) $value;
786
                }
787 209
                if (is_string($value)) {
788 209
                    $lower = strtolower($value);
789 209
                    if ($lower === 'asc') {
790 202
                        return 1;
791 10
                    } elseif ($lower === 'desc') {
792 3
                        return -1;
793
                    }
794
                }
795 7
                return $value;
796 216
            }, $keys),
797 216
            'options' => $options
798
        );
799 216
    }
800
801
    /**
802
     * Set whether or not queries on this document should require indexes.
803
     *
804
     * @param bool $requireIndexes
805
     */
806 846
    public function setRequireIndexes($requireIndexes)
807
    {
808 846
        $this->requireIndexes = $requireIndexes;
809 846
    }
810
811
    /**
812
     * Returns the array of indexes for this Document.
813
     *
814
     * @return array $indexes The array of indexes.
815
     */
816 53
    public function getIndexes()
817
    {
818 53
        return $this->indexes;
819
    }
820
821
    /**
822
     * Checks whether this document has indexes or not.
823
     *
824
     * @return boolean
825
     */
826
    public function hasIndexes()
827
    {
828
        return $this->indexes ? true : false;
829
    }
830
831
    /**
832
     * Set shard key for this Document.
833
     *
834
     * @param array $keys Array of document keys.
835
     * @param array $options Array of sharding options.
836
     *
837
     * @throws MappingException
838
     */
839 85
    public function setShardKey(array $keys, array $options = array())
840
    {
841 85
        if ($this->inheritanceType === self::INHERITANCE_TYPE_SINGLE_COLLECTION && !is_null($this->shardKey)) {
842 2
            throw MappingException::shardKeyInSingleCollInheritanceSubclass($this->getName());
843
        }
844
845 85
        if ($this->isEmbeddedDocument) {
846 2
            throw MappingException::embeddedDocumentCantHaveShardKey($this->getName());
847
        }
848
849 83
        foreach (array_keys($keys) as $field) {
850 83
            if (! isset($this->fieldMappings[$field])) {
851 76
                continue;
852
            }
853
854 7
            if (in_array($this->fieldMappings[$field]['type'], ['many', 'collection'])) {
855 3
                throw MappingException::noMultiKeyShardKeys($this->getName(), $field);
856
            }
857
858 4
            if ($this->fieldMappings[$field]['strategy'] !== static::STORAGE_STRATEGY_SET) {
859 4
                throw MappingException::onlySetStrategyAllowedInShardKey($this->getName(), $field);
860
            }
861
        }
862
863 79
        $this->shardKey = array(
864 View Code Duplication
            'keys' => array_map(function($value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
865 79
                if ($value == 1 || $value == -1) {
866 6
                    return (int) $value;
867
                }
868 78
                if (is_string($value)) {
869 78
                    $lower = strtolower($value);
870 78
                    if ($lower === 'asc') {
871 78
                        return 1;
872 52
                    } elseif ($lower === 'desc') {
873
                        return -1;
874
                    }
875
                }
876 52
                return $value;
877 79
            }, $keys),
878 79
            'options' => $options
879
        );
880 79
    }
881
882
    /**
883
     * @return array
884
     */
885 28
    public function getShardKey()
886
    {
887 28
        return $this->shardKey;
888
    }
889
890
    /**
891
     * Checks whether this document has shard key or not.
892
     *
893
     * @return bool
894
     */
895 567
    public function isSharded()
896
    {
897 567
        return $this->shardKey ? true : false;
898
    }
899
900
    /**
901
     * Sets the change tracking policy used by this class.
902
     *
903
     * @param integer $policy
904
     */
905 350
    public function setChangeTrackingPolicy($policy)
906
    {
907 350
        $this->changeTrackingPolicy = $policy;
908 350
    }
909
910
    /**
911
     * Whether the change tracking policy of this class is "deferred explicit".
912
     *
913
     * @return boolean
914
     */
915 65
    public function isChangeTrackingDeferredExplicit()
916
    {
917 65
        return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_EXPLICIT;
918
    }
919
920
    /**
921
     * Whether the change tracking policy of this class is "deferred implicit".
922
     *
923
     * @return boolean
924
     */
925 592
    public function isChangeTrackingDeferredImplicit()
926
    {
927 592
        return $this->changeTrackingPolicy == self::CHANGETRACKING_DEFERRED_IMPLICIT;
928
    }
929
930
    /**
931
     * Whether the change tracking policy of this class is "notify".
932
     *
933
     * @return boolean
934
     */
935 345
    public function isChangeTrackingNotify()
936
    {
937 345
        return $this->changeTrackingPolicy == self::CHANGETRACKING_NOTIFY;
938
    }
939
940
    /**
941
     * Gets the ReflectionProperties of the mapped class.
942
     *
943
     * @return array An array of ReflectionProperty instances.
944
     */
945 94
    public function getReflectionProperties()
946
    {
947 94
        return $this->reflFields;
948
    }
949
950
    /**
951
     * Gets a ReflectionProperty for a specific field of the mapped class.
952
     *
953
     * @param string $name
954
     *
955
     * @return \ReflectionProperty
956
     */
957
    public function getReflectionProperty($name)
958
    {
959
        return $this->reflFields[$name];
960
    }
961
962
    /**
963
     * {@inheritDoc}
964
     */
965 858
    public function getName()
966
    {
967 858
        return $this->name;
968
    }
969
970
    /**
971
     * The namespace this Document class belongs to.
972
     *
973
     * @return string $namespace The namespace name.
974
     */
975
    public function getNamespace()
976
    {
977
        return $this->namespace;
978
    }
979
980
    /**
981
     * Returns the database this Document is mapped to.
982
     *
983
     * @return string $db The database name.
984
     */
985 785
    public function getDatabase()
986
    {
987 785
        return $this->db;
988
    }
989
990
    /**
991
     * Set the database this Document is mapped to.
992
     *
993
     * @param string $db The database name
994
     */
995 94
    public function setDatabase($db)
996
    {
997 94
        $this->db = $db;
998 94
    }
999
1000
    /**
1001
     * Get the collection this Document is mapped to.
1002
     *
1003
     * @return string $collection The collection name.
1004
     */
1005 789
    public function getCollection()
1006
    {
1007 789
        return $this->collection;
1008
    }
1009
1010
    /**
1011
     * Sets the collection this Document is mapped to.
1012
     *
1013
     * @param array|string $name
1014
     *
1015
     * @throws \InvalidArgumentException
1016
     */
1017 885
    public function setCollection($name)
1018
    {
1019 885
        if (is_array($name)) {
1020
            if ( ! isset($name['name'])) {
1021
                throw new \InvalidArgumentException('A name key is required when passing an array to setCollection()');
1022
            }
1023
            $this->collectionCapped = isset($name['capped']) ? $name['capped'] : false;
1024
            $this->collectionSize = isset($name['size']) ? $name['size'] : 0;
1025
            $this->collectionMax = isset($name['max']) ? $name['max'] : 0;
1026
            $this->collection = $name['name'];
1027
        } else {
1028 885
            $this->collection = $name;
1029
        }
1030 885
    }
1031
1032
    /**
1033
     * Get whether or not the documents collection is capped.
1034
     *
1035
     * @return boolean
1036
     */
1037 4
    public function getCollectionCapped()
1038
    {
1039 4
        return $this->collectionCapped;
1040
    }
1041
1042
    /**
1043
     * Set whether or not the documents collection is capped.
1044
     *
1045
     * @param boolean $bool
1046
     */
1047 1
    public function setCollectionCapped($bool)
1048
    {
1049 1
        $this->collectionCapped = $bool;
1050 1
    }
1051
1052
    /**
1053
     * Get the collection size
1054
     *
1055
     * @return integer
1056
     */
1057 4
    public function getCollectionSize()
1058
    {
1059 4
        return $this->collectionSize;
1060
    }
1061
1062
    /**
1063
     * Set the collection size.
1064
     *
1065
     * @param integer $size
1066
     */
1067 1
    public function setCollectionSize($size)
1068
    {
1069 1
        $this->collectionSize = $size;
1070 1
    }
1071
1072
    /**
1073
     * Get the collection max.
1074
     *
1075
     * @return integer
1076
     */
1077 4
    public function getCollectionMax()
1078
    {
1079 4
        return $this->collectionMax;
1080
    }
1081
1082
    /**
1083
     * Set the collection max.
1084
     *
1085
     * @param integer $max
1086
     */
1087 1
    public function setCollectionMax($max)
1088
    {
1089 1
        $this->collectionMax = $max;
1090 1
    }
1091
1092
    /**
1093
     * Returns TRUE if this Document is mapped to a collection FALSE otherwise.
1094
     *
1095
     * @return boolean
1096
     */
1097
    public function isMappedToCollection()
1098
    {
1099
        return $this->collection ? true : false;
1100
    }
1101
1102
    /**
1103
     * Returns TRUE if this Document is a file to be stored on the MongoGridFS FALSE otherwise.
1104
     *
1105
     * @return boolean
1106
     */
1107 730
    public function isFile()
1108
    {
1109 730
        return $this->file ? true : false;
1110
    }
1111
1112
    /**
1113
     * Returns the file field name.
1114
     *
1115
     * @return string $file The file field name.
1116
     */
1117 345
    public function getFile()
1118
    {
1119 345
        return $this->file;
1120
    }
1121
1122
    /**
1123
     * Set the field name that stores the grid file.
1124
     *
1125
     * @param string $file
1126
     */
1127 346
    public function setFile($file)
1128
    {
1129 346
        $this->file = $file;
1130 346
    }
1131
1132
    /**
1133
     * Returns the distance field name.
1134
     *
1135
     * @return string $distance The distance field name.
1136
     */
1137
    public function getDistance()
1138
    {
1139
        return $this->distance;
1140
    }
1141
1142
    /**
1143
     * Set the field name that stores the distance.
1144
     *
1145
     * @param string $distance
1146
     */
1147 1
    public function setDistance($distance)
1148
    {
1149 1
        $this->distance = $distance;
1150 1
    }
1151
1152
    /**
1153
     * Map a field.
1154
     *
1155
     * @param array $mapping The mapping information.
1156
     *
1157
     * @return array
1158
     *
1159
     * @throws MappingException
1160
     */
1161 898
    public function mapField(array $mapping)
1162
    {
1163 898
        if ( ! isset($mapping['fieldName']) && isset($mapping['name'])) {
1164 8
            $mapping['fieldName'] = $mapping['name'];
1165
        }
1166 898
        if ( ! isset($mapping['fieldName'])) {
1167
            throw MappingException::missingFieldName($this->name);
1168
        }
1169 898
        if ( ! isset($mapping['name'])) {
1170 890
            $mapping['name'] = $mapping['fieldName'];
1171
        }
1172 898
        if ($this->identifier === $mapping['name'] && empty($mapping['id'])) {
1173 1
            throw MappingException::mustNotChangeIdentifierFieldsType($this->name, $mapping['name']);
1174
        }
1175 897
        if (isset($this->fieldMappings[$mapping['fieldName']])) {
1176
            //throw MappingException::duplicateFieldMapping($this->name, $mapping['fieldName']);
1177
        }
1178 897
        if ($this->discriminatorField !== null && $this->discriminatorField == $mapping['name']) {
1179 1
            throw MappingException::discriminatorFieldConflict($this->name, $this->discriminatorField);
1180
        }
1181 896 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...
1182 570
            $mapping['targetDocument'] = $this->namespace . '\\' . $mapping['targetDocument'];
1183
        }
1184 896
        if (isset($mapping['collectionClass'])) {
1185 60 View Code Duplication
            if (strpos($mapping['collectionClass'], '\\') === false && strlen($this->namespace)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1186 59
                $mapping['collectionClass'] = $this->namespace . '\\' . $mapping['collectionClass'];
1187
            }
1188 60
            $mapping['collectionClass'] = ltrim($mapping['collectionClass'], '\\');
1189
        }
1190 896
        if ( ! empty($mapping['collectionClass'])) {
1191 60
            $rColl = new \ReflectionClass($mapping['collectionClass']);
1192 60
            if ( ! $rColl->implementsInterface('Doctrine\\Common\\Collections\\Collection')) {
1193 1
                throw MappingException::collectionClassDoesNotImplementCommonInterface($this->name, $mapping['fieldName'], $mapping['collectionClass']);
1194
            }
1195
        }
1196
1197 895
        if (isset($mapping['discriminatorMap'])) {
1198 109
            foreach ($mapping['discriminatorMap'] as $key => $class) {
1199 109 View Code Duplication
                if (strpos($class, '\\') === false && strlen($this->namespace)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1200 109
                    $mapping['discriminatorMap'][$key] = $this->namespace . '\\' . $class;
1201
                }
1202
            }
1203
        }
1204
1205 895
        if (isset($mapping['cascade']) && isset($mapping['embedded'])) {
1206 1
            throw MappingException::cascadeOnEmbeddedNotAllowed($this->name, $mapping['fieldName']);
1207
        }
1208
1209 894
        $cascades = isset($mapping['cascade']) ? array_map('strtolower', (array) $mapping['cascade']) : array();
1210
1211 894
        if (in_array('all', $cascades) || isset($mapping['embedded'])) {
1212 596
            $cascades = array('remove', 'persist', 'refresh', 'merge', 'detach');
1213
        }
1214
1215 894
        if (isset($mapping['embedded'])) {
1216 562
            unset($mapping['cascade']);
1217 889
        } elseif (isset($mapping['cascade'])) {
1218 376
            $mapping['cascade'] = $cascades;
1219
        }
1220
1221 894
        $mapping['isCascadeRemove'] = in_array('remove', $cascades);
1222 894
        $mapping['isCascadePersist'] = in_array('persist', $cascades);
1223 894
        $mapping['isCascadeRefresh'] = in_array('refresh', $cascades);
1224 894
        $mapping['isCascadeMerge'] = in_array('merge', $cascades);
1225 894
        $mapping['isCascadeDetach'] = in_array('detach', $cascades);
1226
1227 894
        if (isset($mapping['type']) && $mapping['type'] === 'file') {
1228 63
            $mapping['file'] = true;
1229
        }
1230 894
        if (isset($mapping['type']) && $mapping['type'] === 'increment') {
1231 1
            $mapping['strategy'] = self::STORAGE_STRATEGY_INCREMENT;
1232
        }
1233 894 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...
1234 63
            $this->file = $mapping['fieldName'];
1235 63
            $mapping['name'] = 'file';
1236
        }
1237 894 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...
1238 7
            $this->distance = $mapping['fieldName'];
1239
        }
1240 894
        if (isset($mapping['id']) && $mapping['id'] === true) {
1241 867
            $mapping['name'] = '_id';
1242 867
            $this->identifier = $mapping['fieldName'];
1243 867 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...
1244 852
                $this->generatorType = constant(ClassMetadata::class . '::GENERATOR_TYPE_' . strtoupper($mapping['strategy']));
1245
            }
1246 867
            $this->generatorOptions = isset($mapping['options']) ? $mapping['options'] : array();
1247 867
            switch ($this->generatorType) {
1248 867
                case self::GENERATOR_TYPE_AUTO:
1249 798
                    $mapping['type'] = 'id';
1250 798
                    break;
1251
                default:
1252 148
                    if ( ! empty($this->generatorOptions['type'])) {
1253 52
                        $mapping['type'] = $this->generatorOptions['type'];
1254 96
                    } elseif (empty($mapping['type'])) {
1255 82
                        $mapping['type'] = $this->generatorType === self::GENERATOR_TYPE_INCREMENT ? 'int_id' : 'custom_id';
1256
                    }
1257
            }
1258 867
            unset($this->generatorOptions['type']);
1259
        }
1260
1261 894
        if ( ! isset($mapping['nullable'])) {
1262 46
            $mapping['nullable'] = false;
1263
        }
1264
1265
        // Synchronize the "simple" and "storeAs" mapping information for backwards compatibility
1266 894
        if (isset($mapping['simple']) && ($mapping['simple'] === true || $mapping['simple'] === 'true')) {
1267 274
            $mapping['storeAs'] = ClassMetadataInfo::REFERENCE_STORE_AS_ID;
1268
        }
1269
        // Remove the "simple" mapping and use "storeAs" in all further logic
1270 894
        if (isset($mapping['simple'])) {
1271 534
            unset($mapping['simple']);
1272
        }
1273
1274 894
        if (isset($mapping['reference'])
1275 894
            && isset($mapping['storeAs'])
1276 894
            && $mapping['storeAs'] === ClassMetadataInfo::REFERENCE_STORE_AS_ID
1277 894
            && ! isset($mapping['targetDocument'])
1278
        ) {
1279 3
            throw MappingException::simpleReferenceRequiresTargetDocument($this->name, $mapping['fieldName']);
1280
        }
1281
1282 891
        if (isset($mapping['reference']) && empty($mapping['targetDocument']) && empty($mapping['discriminatorMap']) &&
1283 891
                (isset($mapping['mappedBy']) || isset($mapping['inversedBy']))) {
1284 4
            throw MappingException::owningAndInverseReferencesRequireTargetDocument($this->name, $mapping['fieldName']);
1285
        }
1286
1287 887
        if ($this->isEmbeddedDocument && $mapping['type'] === 'many' && CollectionHelper::isAtomic($mapping['strategy'])) {
1288 1
            throw MappingException::atomicCollectionStrategyNotAllowed($mapping['strategy'], $this->name, $mapping['fieldName']);
1289
        }
1290
1291 886 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...
1292 472
            $mapping['association'] = self::REFERENCE_ONE;
1293
        }
1294 886 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...
1295 427
            $mapping['association'] = self::REFERENCE_MANY;
1296
        }
1297 886 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...
1298 423
            $mapping['association'] = self::EMBED_ONE;
1299
        }
1300 886 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...
1301 481
            $mapping['association'] = self::EMBED_MANY;
1302
        }
1303
1304 886
        if (isset($mapping['association']) && ! isset($mapping['targetDocument']) && ! isset($mapping['discriminatorField'])) {
1305 124
            $mapping['discriminatorField'] = self::DEFAULT_DISCRIMINATOR_FIELD;
1306
        }
1307
1308
        /*
1309
        if (isset($mapping['type']) && ($mapping['type'] === 'one' || $mapping['type'] === 'many')) {
1310
            $mapping['type'] = $mapping['type'] === 'one' ? self::ONE : self::MANY;
1311
        }
1312
        */
1313 886
        if (isset($mapping['version'])) {
1314 99
            $mapping['notSaved'] = true;
1315 99
            $this->setVersionMapping($mapping);
1316
        }
1317 886
        if (isset($mapping['lock'])) {
1318 26
            $mapping['notSaved'] = true;
1319 26
            $this->setLockMapping($mapping);
1320
        }
1321 886
        $mapping['isOwningSide'] = true;
1322 886
        $mapping['isInverseSide'] = false;
1323 886
        if (isset($mapping['reference'])) {
1324 540 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...
1325 80
                $mapping['isOwningSide'] = true;
1326 80
                $mapping['isInverseSide'] = false;
1327
            }
1328 540 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...
1329 274
                $mapping['isInverseSide'] = true;
1330 274
                $mapping['isOwningSide'] = false;
1331
            }
1332 540 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...
1333 60
                $mapping['isInverseSide'] = true;
1334 60
                $mapping['isOwningSide'] = false;
1335
            }
1336 540
            if (!isset($mapping['orphanRemoval'])) {
1337 520
                $mapping['orphanRemoval'] = false;
1338
            }
1339
        }
1340
1341 886
        $this->applyStorageStrategy($mapping);
1342
1343 885
        $this->fieldMappings[$mapping['fieldName']] = $mapping;
1344 885
        if (isset($mapping['association'])) {
1345 684
            $this->associationMappings[$mapping['fieldName']] = $mapping;
1346
        }
1347
1348 885
        return $mapping;
1349
    }
1350
1351
    /**
1352
     * Validates the storage strategy of a mapping for consistency
1353
     * @param array $mapping
1354
     * @throws \Doctrine\ODM\MongoDB\Mapping\MappingException
1355
     */
1356 886
    private function applyStorageStrategy(array &$mapping)
1357
    {
1358 886
        if (! isset($mapping['type']) || isset($mapping['id'])) {
1359 869
            return;
1360
        }
1361
1362
        switch (true) {
1363 849
            case $mapping['type'] == 'int':
1364 848
            case $mapping['type'] == 'float':
1365 848
            case $mapping['type'] == 'increment':
1366 317
                $defaultStrategy = self::STORAGE_STRATEGY_SET;
1367 317
                $allowedStrategies = [self::STORAGE_STRATEGY_SET, self::STORAGE_STRATEGY_INCREMENT];
1368 317
                break;
1369
1370 847
            case $mapping['type'] == 'many':
1371 578
                $defaultStrategy = CollectionHelper::DEFAULT_STRATEGY;
1372
                $allowedStrategies = [
1373 578
                    self::STORAGE_STRATEGY_PUSH_ALL,
1374 578
                    self::STORAGE_STRATEGY_ADD_TO_SET,
1375 578
                    self::STORAGE_STRATEGY_SET,
1376 578
                    self::STORAGE_STRATEGY_SET_ARRAY,
1377 578
                    self::STORAGE_STRATEGY_ATOMIC_SET,
1378 578
                    self::STORAGE_STRATEGY_ATOMIC_SET_ARRAY,
1379
                ];
1380 578
                break;
1381
1382
            default:
1383 838
                $defaultStrategy = self::STORAGE_STRATEGY_SET;
1384 838
                $allowedStrategies = [self::STORAGE_STRATEGY_SET];
1385
        }
1386
1387 849
        if (! isset($mapping['strategy'])) {
1388 841
            $mapping['strategy'] = $defaultStrategy;
1389
        }
1390
1391 849
        if (! in_array($mapping['strategy'], $allowedStrategies)) {
1392
            throw MappingException::invalidStorageStrategy($this->name, $mapping['fieldName'], $mapping['type'], $mapping['strategy']);
1393
        }
1394
1395 849
        if (isset($mapping['reference']) && $mapping['type'] === 'many' && $mapping['isOwningSide']
1396 849
            && ! empty($mapping['sort']) && ! CollectionHelper::usesSet($mapping['strategy'])) {
1397 1
            throw MappingException::referenceManySortMustNotBeUsedWithNonSetCollectionStrategy($this->name, $mapping['fieldName'], $mapping['strategy']);
1398
        }
1399 848
    }
1400
1401
    /**
1402
     * Map a MongoGridFSFile.
1403
     *
1404
     * @param array $mapping The mapping information.
1405
     */
1406
    public function mapFile(array $mapping)
1407
    {
1408
        $mapping['file'] = true;
1409
        $mapping['type'] = 'file';
1410
        $this->mapField($mapping);
1411
    }
1412
1413
    /**
1414
     * Map a single embedded document.
1415
     *
1416
     * @param array $mapping The mapping information.
1417
     */
1418 6
    public function mapOneEmbedded(array $mapping)
1419
    {
1420 6
        $mapping['embedded'] = true;
1421 6
        $mapping['type'] = 'one';
1422 6
        $this->mapField($mapping);
1423 5
    }
1424
1425
    /**
1426
     * Map a collection of embedded documents.
1427
     *
1428
     * @param array $mapping The mapping information.
1429
     */
1430 5
    public function mapManyEmbedded(array $mapping)
1431
    {
1432 5
        $mapping['embedded'] = true;
1433 5
        $mapping['type'] = 'many';
1434 5
        $this->mapField($mapping);
1435 5
    }
1436
1437
    /**
1438
     * Map a single document reference.
1439
     *
1440
     * @param array $mapping The mapping information.
1441
     */
1442 8
    public function mapOneReference(array $mapping)
1443
    {
1444 8
        $mapping['reference'] = true;
1445 8
        $mapping['type'] = 'one';
1446 8
        $this->mapField($mapping);
1447 8
    }
1448
1449
    /**
1450
     * Map a collection of document references.
1451
     *
1452
     * @param array $mapping The mapping information.
1453
     */
1454 8
    public function mapManyReference(array $mapping)
1455
    {
1456 8
        $mapping['reference'] = true;
1457 8
        $mapping['type'] = 'many';
1458 8
        $this->mapField($mapping);
1459 8
    }
1460
1461
    /**
1462
     * INTERNAL:
1463
     * Adds a field mapping without completing/validating it.
1464
     * This is mainly used to add inherited field mappings to derived classes.
1465
     *
1466
     * @param array $fieldMapping
1467
     */
1468 120
    public function addInheritedFieldMapping(array $fieldMapping)
1469
    {
1470 120
        $this->fieldMappings[$fieldMapping['fieldName']] = $fieldMapping;
1471
1472 120
        if (isset($fieldMapping['association'])) {
1473 76
            $this->associationMappings[$fieldMapping['fieldName']] = $fieldMapping;
1474
        }
1475 120
    }
1476
1477
    /**
1478
     * INTERNAL:
1479
     * Adds an association mapping without completing/validating it.
1480
     * This is mainly used to add inherited association mappings to derived classes.
1481
     *
1482
     * @param array $mapping
1483
     *
1484
     * @return void
1485
     *
1486
     * @throws MappingException
1487
     */
1488 77
    public function addInheritedAssociationMapping(array $mapping/*, $owningClassName = null*/)
1489
    {
1490 77
        $this->associationMappings[$mapping['fieldName']] = $mapping;
1491 77
    }
1492
1493
    /**
1494
     * Checks whether the class has a mapped association with the given field name.
1495
     *
1496
     * @param string $fieldName
1497
     * @return boolean
1498
     */
1499 7
    public function hasReference($fieldName)
1500
    {
1501 7
        return isset($this->fieldMappings[$fieldName]['reference']);
1502
    }
1503
1504
    /**
1505
     * Checks whether the class has a mapped embed with the given field name.
1506
     *
1507
     * @param string $fieldName
1508
     * @return boolean
1509
     */
1510 5
    public function hasEmbed($fieldName)
1511
    {
1512 5
        return isset($this->fieldMappings[$fieldName]['embedded']);
1513
    }
1514
1515
    /**
1516
     * {@inheritDoc}
1517
     *
1518
     * Checks whether the class has a mapped association (embed or reference) with the given field name.
1519
     */
1520 7
    public function hasAssociation($fieldName)
1521
    {
1522 7
        return $this->hasReference($fieldName) || $this->hasEmbed($fieldName);
1523
    }
1524
1525
    /**
1526
     * {@inheritDoc}
1527
     *
1528
     * Checks whether the class has a mapped reference or embed for the specified field and
1529
     * is a single valued association.
1530
     */
1531
    public function isSingleValuedAssociation($fieldName)
1532
    {
1533
        return $this->isSingleValuedReference($fieldName) || $this->isSingleValuedEmbed($fieldName);
1534
    }
1535
1536
    /**
1537
     * {@inheritDoc}
1538
     *
1539
     * Checks whether the class has a mapped reference or embed for the specified field and
1540
     * is a collection valued association.
1541
     */
1542
    public function isCollectionValuedAssociation($fieldName)
1543
    {
1544
        return $this->isCollectionValuedReference($fieldName) || $this->isCollectionValuedEmbed($fieldName);
1545
    }
1546
1547
    /**
1548
     * Checks whether the class has a mapped association for the specified field
1549
     * and if yes, checks whether it is a single-valued association (to-one).
1550
     *
1551
     * @param string $fieldName
1552
     * @return boolean TRUE if the association exists and is single-valued, FALSE otherwise.
1553
     */
1554
    public function isSingleValuedReference($fieldName)
1555
    {
1556
        return isset($this->fieldMappings[$fieldName]['association']) &&
1557
            $this->fieldMappings[$fieldName]['association'] === self::REFERENCE_ONE;
1558
    }
1559
1560
    /**
1561
     * Checks whether the class has a mapped association for the specified field
1562
     * and if yes, checks whether it is a collection-valued association (to-many).
1563
     *
1564
     * @param string $fieldName
1565
     * @return boolean TRUE if the association exists and is collection-valued, FALSE otherwise.
1566
     */
1567
    public function isCollectionValuedReference($fieldName)
1568
    {
1569
        return isset($this->fieldMappings[$fieldName]['association']) &&
1570
            $this->fieldMappings[$fieldName]['association'] === self::REFERENCE_MANY;
1571
    }
1572
1573
    /**
1574
     * Checks whether the class has a mapped embedded document for the specified field
1575
     * and if yes, checks whether it is a single-valued association (to-one).
1576
     *
1577
     * @param string $fieldName
1578
     * @return boolean TRUE if the association exists and is single-valued, FALSE otherwise.
1579
     */
1580
    public function isSingleValuedEmbed($fieldName)
1581
    {
1582
        return isset($this->fieldMappings[$fieldName]['association']) &&
1583
            $this->fieldMappings[$fieldName]['association'] === self::EMBED_ONE;
1584
    }
1585
1586
    /**
1587
     * Checks whether the class has a mapped embedded document for the specified field
1588
     * and if yes, checks whether it is a collection-valued association (to-many).
1589
     *
1590
     * @param string $fieldName
1591
     * @return boolean TRUE if the association exists and is collection-valued, FALSE otherwise.
1592
     */
1593
    public function isCollectionValuedEmbed($fieldName)
1594
    {
1595
        return isset($this->fieldMappings[$fieldName]['association']) &&
1596
            $this->fieldMappings[$fieldName]['association'] === self::EMBED_MANY;
1597
    }
1598
1599
    /**
1600
     * Sets the ID generator used to generate IDs for instances of this class.
1601
     *
1602
     * @param \Doctrine\ODM\MongoDB\Id\AbstractIdGenerator $generator
1603
     */
1604 794
    public function setIdGenerator($generator)
1605
    {
1606 794
        $this->idGenerator = $generator;
1607 794
    }
1608
1609
    /**
1610
     * Casts the identifier to its portable PHP type.
1611
     *
1612
     * @param mixed $id
1613
     * @return mixed $id
1614
     */
1615 609
    public function getPHPIdentifierValue($id)
1616
    {
1617 609
        $idType = $this->fieldMappings[$this->identifier]['type'];
1618 609
        return Type::getType($idType)->convertToPHPValue($id);
1619
    }
1620
1621
    /**
1622
     * Casts the identifier to its database type.
1623
     *
1624
     * @param mixed $id
1625
     * @return mixed $id
1626
     */
1627 672
    public function getDatabaseIdentifierValue($id)
1628
    {
1629 672
        $idType = $this->fieldMappings[$this->identifier]['type'];
1630 672
        return Type::getType($idType)->convertToDatabaseValue($id);
1631
    }
1632
1633
    /**
1634
     * Sets the document identifier of a document.
1635
     *
1636
     * The value will be converted to a PHP type before being set.
1637
     *
1638
     * @param object $document
1639
     * @param mixed $id
1640
     */
1641 541
    public function setIdentifierValue($document, $id)
1642
    {
1643 541
        $id = $this->getPHPIdentifierValue($id);
1644 541
        $this->reflFields[$this->identifier]->setValue($document, $id);
1645 541
    }
1646
1647
    /**
1648
     * Gets the document identifier as a PHP type.
1649
     *
1650
     * @param object $document
1651
     * @return mixed $id
1652
     */
1653 623
    public function getIdentifierValue($document)
1654
    {
1655 623
        return $this->reflFields[$this->identifier]->getValue($document);
1656
    }
1657
1658
    /**
1659
     * {@inheritDoc}
1660
     *
1661
     * Since MongoDB only allows exactly one identifier field this is a proxy
1662
     * to {@see getIdentifierValue()} and returns an array with the identifier
1663
     * field as a key.
1664
     */
1665
    public function getIdentifierValues($object)
1666
    {
1667
        return array($this->identifier => $this->getIdentifierValue($object));
1668
    }
1669
1670
    /**
1671
     * Get the document identifier object as a database type.
1672
     *
1673
     * @param object $document
1674
     *
1675
     * @return \MongoId $id The MongoID object.
1676
     */
1677 34
    public function getIdentifierObject($document)
1678
    {
1679 34
        return $this->getDatabaseIdentifierValue($this->getIdentifierValue($document));
1680
    }
1681
1682
    /**
1683
     * Sets the specified field to the specified value on the given document.
1684
     *
1685
     * @param object $document
1686
     * @param string $field
1687
     * @param mixed $value
1688
     */
1689 7
    public function setFieldValue($document, $field, $value)
1690
    {
1691 7
        if ($document instanceof Proxy && ! $document->__isInitialized()) {
1692
            //property changes to an uninitialized proxy will not be tracked or persisted,
1693
            //so the proxy needs to be loaded first.
1694 1
            $document->__load();
1695
        }
1696
1697 7
        $this->reflFields[$field]->setValue($document, $value);
1698 7
    }
1699
1700
    /**
1701
     * Gets the specified field's value off the given document.
1702
     *
1703
     * @param object $document
1704
     * @param string $field
1705
     *
1706
     * @return mixed
1707
     */
1708 27
    public function getFieldValue($document, $field)
1709
    {
1710 27
        if ($document instanceof Proxy && $field !== $this->identifier && ! $document->__isInitialized()) {
1711 1
            $document->__load();
1712
        }
1713
1714 27
        return $this->reflFields[$field]->getValue($document);
1715
    }
1716
1717
    /**
1718
     * Gets the mapping of a field.
1719
     *
1720
     * @param string $fieldName  The field name.
1721
     *
1722
     * @return array  The field mapping.
1723
     *
1724
     * @throws MappingException if the $fieldName is not found in the fieldMappings array
1725
     */
1726 95
    public function getFieldMapping($fieldName)
1727
    {
1728 95
        if ( ! isset($this->fieldMappings[$fieldName])) {
1729 6
            throw MappingException::mappingNotFound($this->name, $fieldName);
1730
        }
1731 93
        return $this->fieldMappings[$fieldName];
1732
    }
1733
1734
    /**
1735
     * Gets mappings of fields holding embedded document(s).
1736
     *
1737
     * @return array of field mappings
1738
     */
1739 584
    public function getEmbeddedFieldsMappings()
1740
    {
1741 584
        return array_filter(
1742 584
            $this->associationMappings,
1743
            function($assoc) { return ! empty($assoc['embedded']); }
1744
        );
1745
    }
1746
1747
    /**
1748
     * Gets the field mapping by its DB name.
1749
     * E.g. it returns identifier's mapping when called with _id.
1750
     *
1751
     * @param string $dbFieldName
1752
     *
1753
     * @return array
1754
     * @throws MappingException
1755
     */
1756 9
    public function getFieldMappingByDbFieldName($dbFieldName)
1757
    {
1758 9
        foreach ($this->fieldMappings as $mapping) {
1759 9
            if ($mapping['name'] == $dbFieldName) {
1760 9
                return $mapping;
1761
            }
1762
        }
1763
1764
        throw MappingException::mappingNotFoundByDbName($this->name, $dbFieldName);
1765
    }
1766
1767
    /**
1768
     * Check if the field is not null.
1769
     *
1770
     * @param string $fieldName  The field name
1771
     *
1772
     * @return boolean  TRUE if the field is not null, FALSE otherwise.
1773
     */
1774 1
    public function isNullable($fieldName)
1775
    {
1776 1
        $mapping = $this->getFieldMapping($fieldName);
1777 1
        if ($mapping !== false) {
1778 1
            return isset($mapping['nullable']) && $mapping['nullable'] == true;
1779
        }
1780
        return false;
1781
    }
1782
1783
    /**
1784
     * Checks whether the document has a discriminator field and value configured.
1785
     *
1786
     * @return boolean
1787
     */
1788 496
    public function hasDiscriminator()
1789
    {
1790 496
        return isset($this->discriminatorField, $this->discriminatorValue);
1791
    }
1792
1793
    /**
1794
     * Sets the type of Id generator to use for the mapped class.
1795
     *
1796
     * @param string $generatorType Generator type.
1797
     */
1798 351
    public function setIdGeneratorType($generatorType)
1799
    {
1800 351
        $this->generatorType = $generatorType;
1801 351
    }
1802
1803
    /**
1804
     * Sets the Id generator options.
1805
     *
1806
     * @param array $generatorOptions Generator options.
1807
     */
1808
    public function setIdGeneratorOptions($generatorOptions)
1809
    {
1810
        $this->generatorOptions = $generatorOptions;
1811
    }
1812
1813
    /**
1814
     * @return boolean
1815
     */
1816 590
    public function isInheritanceTypeNone()
1817
    {
1818 590
        return $this->inheritanceType == self::INHERITANCE_TYPE_NONE;
1819
    }
1820
1821
    /**
1822
     * Checks whether the mapped class uses the SINGLE_COLLECTION inheritance mapping strategy.
1823
     *
1824
     * @return boolean
1825
     */
1826 344
    public function isInheritanceTypeSingleCollection()
1827
    {
1828 344
        return $this->inheritanceType == self::INHERITANCE_TYPE_SINGLE_COLLECTION;
1829
    }
1830
1831
    /**
1832
     * Checks whether the mapped class uses the COLLECTION_PER_CLASS inheritance mapping strategy.
1833
     *
1834
     * @return boolean
1835
     */
1836
    public function isInheritanceTypeCollectionPerClass()
1837
    {
1838
        return $this->inheritanceType == self::INHERITANCE_TYPE_COLLECTION_PER_CLASS;
1839
    }
1840
1841
    /**
1842
     * Sets the mapped subclasses of this class.
1843
     *
1844
     * @param string[] $subclasses The names of all mapped subclasses.
1845
     */
1846 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...
1847
    {
1848 2
        foreach ($subclasses as $subclass) {
1849 2
            if (strpos($subclass, '\\') === false && strlen($this->namespace)) {
1850 1
                $this->subClasses[] = $this->namespace . '\\' . $subclass;
1851
            } else {
1852 2
                $this->subClasses[] = $subclass;
1853
            }
1854
        }
1855 2
    }
1856
1857
    /**
1858
     * Sets the parent class names.
1859
     * Assumes that the class names in the passed array are in the order:
1860
     * directParent -> directParentParent -> directParentParentParent ... -> root.
1861
     *
1862
     * @param string[] $classNames
1863
     */
1864 849
    public function setParentClasses(array $classNames)
1865
    {
1866 849
        $this->parentClasses = $classNames;
1867
1868 849
        if (count($classNames) > 0) {
1869 104
            $this->rootDocumentName = array_pop($classNames);
1870
        }
1871 849
    }
1872
1873
    /**
1874
     * Checks whether the class will generate a new \MongoId instance for us.
1875
     *
1876
     * @return boolean TRUE if the class uses the AUTO generator, FALSE otherwise.
1877
     */
1878
    public function isIdGeneratorAuto()
1879
    {
1880
        return $this->generatorType == self::GENERATOR_TYPE_AUTO;
1881
    }
1882
1883
    /**
1884
     * Checks whether the class will use a collection to generate incremented identifiers.
1885
     *
1886
     * @return boolean TRUE if the class uses the INCREMENT generator, FALSE otherwise.
1887
     */
1888
    public function isIdGeneratorIncrement()
1889
    {
1890
        return $this->generatorType == self::GENERATOR_TYPE_INCREMENT;
1891
    }
1892
1893
    /**
1894
     * Checks whether the class will generate a uuid id.
1895
     *
1896
     * @return boolean TRUE if the class uses the UUID generator, FALSE otherwise.
1897
     */
1898
    public function isIdGeneratorUuid()
1899
    {
1900
        return $this->generatorType == self::GENERATOR_TYPE_UUID;
1901
    }
1902
1903
    /**
1904
     * Checks whether the class uses no id generator.
1905
     *
1906
     * @return boolean TRUE if the class does not use any id generator, FALSE otherwise.
1907
     */
1908
    public function isIdGeneratorNone()
1909
    {
1910
        return $this->generatorType == self::GENERATOR_TYPE_NONE;
1911
    }
1912
1913
    /**
1914
     * Sets the version field mapping used for versioning. Sets the default
1915
     * value to use depending on the column type.
1916
     *
1917
     * @param array $mapping   The version field mapping array
1918
     *
1919
     * @throws LockException
1920
     */
1921 99
    public function setVersionMapping(array &$mapping)
1922
    {
1923 99
        if ($mapping['type'] !== 'int' && $mapping['type'] !== 'date') {
1924 1
            throw LockException::invalidVersionFieldType($mapping['type']);
1925
        }
1926
1927 98
        $this->isVersioned  = true;
1928 98
        $this->versionField = $mapping['fieldName'];
1929 98
    }
1930
1931
    /**
1932
     * Sets whether this class is to be versioned for optimistic locking.
1933
     *
1934
     * @param boolean $bool
1935
     */
1936 345
    public function setVersioned($bool)
1937
    {
1938 345
        $this->isVersioned = $bool;
1939 345
    }
1940
1941
    /**
1942
     * Sets the name of the field that is to be used for versioning if this class is
1943
     * versioned for optimistic locking.
1944
     *
1945
     * @param string $versionField
1946
     */
1947 345
    public function setVersionField($versionField)
1948
    {
1949 345
        $this->versionField = $versionField;
1950 345
    }
1951
1952
    /**
1953
     * Sets the version field mapping used for versioning. Sets the default
1954
     * value to use depending on the column type.
1955
     *
1956
     * @param array $mapping   The version field mapping array
1957
     *
1958
     * @throws \Doctrine\ODM\MongoDB\LockException
1959
     */
1960 26
    public function setLockMapping(array &$mapping)
1961
    {
1962 26
        if ($mapping['type'] !== 'int') {
1963 1
            throw LockException::invalidLockFieldType($mapping['type']);
1964
        }
1965
1966 25
        $this->isLockable = true;
1967 25
        $this->lockField = $mapping['fieldName'];
1968 25
    }
1969
1970
    /**
1971
     * Sets whether this class is to allow pessimistic locking.
1972
     *
1973
     * @param boolean $bool
1974
     */
1975
    public function setLockable($bool)
1976
    {
1977
        $this->isLockable = $bool;
1978
    }
1979
1980
    /**
1981
     * Sets the name of the field that is to be used for storing whether a document
1982
     * is currently locked or not.
1983
     *
1984
     * @param string $lockField
1985
     */
1986
    public function setLockField($lockField)
1987
    {
1988
        $this->lockField = $lockField;
1989
    }
1990
1991
    /**
1992
     * {@inheritDoc}
1993
     */
1994
    public function getFieldNames()
1995
    {
1996
        return array_keys($this->fieldMappings);
1997
    }
1998
1999
    /**
2000
     * {@inheritDoc}
2001
     */
2002
    public function getAssociationNames()
2003
    {
2004
        return array_keys($this->associationMappings);
2005
    }
2006
2007
    /**
2008
     * {@inheritDoc}
2009
     */
2010 22
    public function getTypeOfField($fieldName)
2011
    {
2012 22
        return isset($this->fieldMappings[$fieldName]) ?
2013 22
            $this->fieldMappings[$fieldName]['type'] : null;
2014
    }
2015
2016
    /**
2017
     * {@inheritDoc}
2018
     */
2019 6
    public function getAssociationTargetClass($assocName)
2020
    {
2021 6
        if ( ! isset($this->associationMappings[$assocName])) {
2022 3
            throw new InvalidArgumentException("Association name expected, '" . $assocName . "' is not an association.");
2023
        }
2024
2025 3
        return $this->associationMappings[$assocName]['targetDocument'];
2026
    }
2027
2028
    /**
2029
     * {@inheritDoc}
2030
     */
2031
    public function isAssociationInverseSide($fieldName)
2032
    {
2033
        throw new \BadMethodCallException(__METHOD__ . '() is not implemented yet.');
2034
    }
2035
2036
    /**
2037
     * {@inheritDoc}
2038
     */
2039
    public function getAssociationMappedByTargetField($fieldName)
2040
    {
2041
        throw new \BadMethodCallException(__METHOD__ . '() is not implemented yet.');
2042
    }
2043
}
2044