Completed
Pull Request — master (#1385)
by Andreas
18:26
created

ClassMetadataInfo::setShardKey()   C

Complexity

Conditions 13
Paths 7

Size

Total Lines 42
Code Lines 25

Duplication

Lines 14
Ratio 33.33 %

Code Coverage

Tests 26
CRAP Score 13.0085

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 14
loc 42
ccs 26
cts 27
cp 0.963
rs 5.1234
cc 13
eloc 25
nc 7
nop 2
crap 13.0085

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