Completed
Push — master ( 707688...6da863 )
by Mike
04:47 queued 02:08
created

lib/Doctrine/ODM/CouchDB/Mapping/ClassMetadata.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Doctrine\ODM\CouchDB\Mapping;
4
5
use Doctrine\Common\Persistence\Mapping\ClassMetadata AS IClassMetadata,
6
    Doctrine\Instantiator\Instantiator,
7
    ReflectionClass,
8
    ReflectionProperty;
9
10
/**
11
 * Metadata class
12
 *
13
 * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
14
 * @link        www.doctrine-project.com
15
 * @since       1.0
16
 * @author      Benjamin Eberlei <[email protected]>
17
 * @author      Lukas Kahwe Smith <[email protected]>
18
 */
19
class ClassMetadata implements IClassMetadata
20
{
21
    const IDGENERATOR_UUID = 1;
22
    const IDGENERATOR_ASSIGNED = 2;
23
24
    const TO_ONE = 5;
25
    const TO_MANY = 10;
26
    const ONE_TO_ONE = 1;
27
    const ONE_TO_MANY = 2;
28
    const MANY_TO_ONE = 4;
29
    const MANY_TO_MANY = 8;
30
31
    const CASCADE_PERSIST = 1;
32
    const CASCADE_REMOVE  = 2;
33
    const CASCADE_MERGE   = 4;
34
    const CASCADE_DETACH  = 8;
35
    const CASCADE_REFRESH = 16;
36
    const CASCADE_ALL     = 31;
37
38
    public $idGenerator = self::IDGENERATOR_UUID;
39
40
    /**
41
     * READ-ONLY: The field name of the document identifier.
42
     */
43
    public $identifier;
44
45
    /**
46
     * READ-ONLY: The name of the document class.
47
     */
48
    public $name;
49
50
    /**
51
     * READ-ONLY: The root document class name.
52
     */
53
    public $rootDocumentName;
54
55
    /**
56
     * READ-ONLY: Is this entity in an inheritance hierachy?
57
     */
58
    public $inInheritanceHierachy = false;
59
60
    /**
61
     * READ-ONLY: a list of all parent classes.
62
     */
63
    public $parentClasses = array();
64
65
    /**
66
     * READ-ONLY: The namespace the document class is contained in.
67
     *
68
     * @var string
69
     * @todo Not really needed. Usage could be localized.
70
     */
71
    public $namespace;
72
73
    /**
74
     * The name of the custom repository class used for the document class.
75
     * (Optional).
76
     *
77
     * @var string
78
     */
79
    public $customRepositoryClassName;
80
81
    /**
82
     * READ-ONLY: The field mappings of the class.
83
     * Keys are field names and values are mapping definitions.
84
     *
85
     * The mapping definition array has the following values:
86
     *
87
     * - <b>fieldName</b> (string)
88
     * The name of the field in the Document.
89
     *
90
     * - <b>id</b> (boolean, optional)
91
     * Marks the field as the primary key of the document. Multiple fields of an
92
     * document can have the id attribute, forming a composite key.
93
     *
94
     * @var array
95
     */
96
    public $fieldMappings = array();
97
98
    /**
99
     * An array of indexed fields, accessible through a generic view shipped with Doctrine.
100
     *
101
     * @var array
102
     */
103
    public $indexes = array();
104
105
    /**
106
     * Is this class indexed? If yes, then a findAll() query can be executed for this type.
107
     *
108
     * @var bool
109
     */
110
    public $indexed = false;
111
112
    /**
113
     * An array of json result-key-names to field-names
114
     *
115
     * @var array
116
     */
117
    public $jsonNames = array();
118
119
    /**
120
     * READ-ONLY: Array of fields to also load with a given method.
121
     *
122
     * @var array
123
     */
124
    public $alsoLoadMethods = array();
125
126
    /**
127
     * READ-ONLY: Whether this class describes the mapping of a mapped superclass.
128
     *
129
     * @var boolean
130
     */
131
    public $isMappedSuperclass = false;
132
133
    /**
134
     * READ-ONLY: Whether this class describes the mapping of a embedded document.
135
     *
136
     * @var boolean
137
     */
138
    public $isEmbeddedDocument = false;
139
140
    /**
141
     * READ-ONLY: Wheather the document or embedded document is read-only and will be skipped in change-tracking.
142
     *
143
     * This should be set to true for value objects, for example attachments. Replacing the reference with a new
144
     * value object will trigger an update.
145
     *
146
     * @var bool
147
     */
148
    public $isReadOnly = false;
149
150
    /**
151
     * READ-ONLY
152
     *
153
     * @var array
154
     */
155
    public $associationsMappings = array();
156
157
    /**
158
     * CouchDB documents are always versioned, this flag determines if this version is exposed to the userland.
159
     *
160
     * @var bool
161
     */
162
    public $isVersioned = false;
163
164
    /**
165
     * Version Field stores the CouchDB Revision
166
     *
167
     * @var string
168
     */
169
    public $versionField = null;
170
171
    /**
172
     * @var bool
173
     */
174
    public $hasAttachments = false;
175
176
    /**
177
     * Field that stores the attachments as a key->value array of file-names to attachment objects.
178
     *
179
     * @var string
180
     */
181
    public $attachmentField = null;
182
183
    /**
184
     * If in an inheritance scenario the attachment field is on a super class, this is its name.
185
     *
186
     * @var string|null
187
     */
188
    public $attachmentDeclaredClass = null;
189
190
    /**
191
     * The ReflectionClass instance of the mapped class.
192
     *
193
     * @var ReflectionClass
194
     */
195
    public $reflClass;
196
197
    /**
198
     * The ReflectionProperty instances of the mapped class.
199
     *
200
     * @var array
201
     */
202
    public $reflFields = array();
203
204
    /**
205
     * @var \Doctrine\Instantiator\InstantiatorInterface
206
     */
207
    private $instantiator;
208
209
    /**
210
     * Initializes a new ClassMetadata instance that will hold the object-document mapping
211
     * metadata of the class with the given name.
212
     *
213
     * @param string $documentName The name of the document class the new instance is used for.
214
     */
215
    public function __construct($documentName)
216
    {
217
        $this->name = $documentName;
218
        $this->rootDocumentName = $documentName;
219
        $this->instantiator = new Instantiator();
220
    }
221
222
    /**
223
     * Used to derive a class metadata of the current instance for a mapped child class.
224
     *
225
     * @param  ClassMetadata $child
226
     * @throws \InvalidArgumentException
227
     */
228
    public function deriveChildMetadata($child)
229
    {
230
        if (!is_subclass_of($child->name, $this->name)) {
231
            throw new \InvalidArgumentException("Only child class names of '".$this->name."' are valid values.");
232
        }
233
234
        $child->isMappedSuperclass = false;
235
        $child->isEmbeddedDocument = false;
236
237
        foreach ($this->fieldMappings AS $fieldName => $fieldMapping) {
238
            $child->fieldMappings[$fieldName] = $fieldMapping;
239
240
            if (!isset($fieldMapping['declared'])) {
241
                $child->fieldMappings[$fieldName]['declared'] = $this->name;
242
            }
243
        }
244
245
        foreach ($this->associationsMappings AS $assocName => $assocMapping) {
246
            $child->associationsMappings[$assocName] = $assocMapping;
247
248
            if (!isset($assocMapping['declared'])) {
249
                $child->associationsMappings[$assocName]['declared'] = $this->name;
250
            }
251
        }
252
253
        if ($this->attachmentField) {
254
            $child->attachmentField = $this->attachmentField;
255
256
            if (!$child->attachmentDeclaredClass) {
257
                $child->attachmentDeclaredClass = $this->name;
258
            }
259
        }
260
    }
261
262
    /**
263
     * Determines which fields get serialized.
264
     *
265
     * It is only serialized what is necessary for best unserialization performance.
266
     * That means any metadata properties that are not set or empty or simply have
267
     * their default value are NOT serialized.
268
     *
269
     * Parts that are also NOT serialized because they can not be properly unserialized:
270
     *      - reflClass (ReflectionClass)
271
     *      - reflFields (ReflectionProperty array)
272
     *
273
     * @return array The names of all the fields that should be serialized.
274
     */
275
    public function __sleep()
276
    {
277
        // This metadata is always serialized/cached.
278
        $serialized = array(
279
            'name',
280
            'associationsMappings',
281
            'fieldMappings',
282
            'jsonNames',
283
            'idGenerator',
284
            'identifier',
285
            'rootDocumentName',
286
        );
287
288
        if ($this->inInheritanceHierachy) {
289
            $serialized[] = 'inInheritanceHierachy';
290
        }
291
292
        if ($this->parentClasses) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->parentClasses of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
293
            $serialized[] = 'parentClasses';
294
        }
295
296
        if ($this->isVersioned) {
297
            $serialized[] = 'isVersioned';
298
            $serialized[] = 'versionField';
299
        }
300
301
        if ($this->customRepositoryClassName) {
302
            $serialized[] = 'customRepositoryClassName';
303
        }
304
305
        if ($this->hasAttachments) {
306
            $serialized[] = 'hasAttachments';
307
            $serialized[] = 'attachmentField';
308
            if ($this->attachmentDeclaredClass) {
309
                $serialized[] = 'attachmentDeclaredClass';
310
            }
311
        }
312
313
        if ($this->isReadOnly) {
314
            $serialized[] = 'isReadOnly';
315
        }
316
317
        if ($this->isMappedSuperclass) {
318
            $serialized[] = 'isMappedSuperclass';
319
        }
320
321
        if ($this->indexed) {
322
            $serialized[] = 'indexed';
323
        }
324
        if ($this->indexes) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->indexes of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
325
            $serialized[] = 'indexes';
326
        }
327
328
        return $serialized;
329
    }
330
331
    /**
332
     * Restores some state that can not be serialized/unserialized.
333
     */
334
    public function wakeupReflection($reflService)
335
    {
336
        // Restore ReflectionClass and properties
337
        $this->reflClass    = $reflService->getClass($this->name);
338
        $this->namespace    = $reflService->getClassNamespace($this->name);
339
        $this->instantiator = $this->instantiator ?: new Instantiator();
340
341 View Code Duplication
        foreach ($this->fieldMappings as $field => $mapping) {
342
            if (isset($mapping['declared'])) {
343
                $reflField = new \ReflectionProperty($mapping['declared'], $field);
344
            } else {
345
                $reflField = $this->reflClass->getProperty($field);
346
            }
347
            $reflField->setAccessible(true);
348
            $this->reflFields[$field] = $reflField;
349
        }
350
351 View Code Duplication
        foreach ($this->associationsMappings as $field => $mapping) {
352
            if (isset($mapping['declared'])) {
353
                $reflField = new \ReflectionProperty($mapping['declared'], $field);
354
            } else {
355
                $reflField = $this->reflClass->getProperty($field);
356
            }
357
358
            $reflField->setAccessible(true);
359
            $this->reflFields[$field] = $reflField;
360
        }
361
362
        if ($this->hasAttachments) {
363
            if ($this->attachmentDeclaredClass) {
364
                $reflField = new \ReflectionProperty($this->attachmentDeclaredClass, $this->attachmentField);
365
            } else {
366
                $reflField = $this->reflClass->getProperty($this->attachmentField);
367
            }
368
            $reflField->setAccessible(true);
369
            $this->reflFields[$this->attachmentField] = $reflField;
370
        }
371
    }
372
373
    /**
374
     * Creates a new instance of the mapped class, without invoking the constructor.
375
     *
376
     * @return object
377
     */
378
    public function newInstance()
379
    {
380
        return $this->instantiator->instantiate($this->name);
381
    }
382
383
    /**
384
     * Gets the ReflectionClass instance of the mapped class.
385
     *
386
     * @return ReflectionClass
387
     */
388
    public function getReflectionClass()
389
    {
390
        if ( ! $this->reflClass) {
391
            $this->reflClass = new ReflectionClass($this->name);
392
        }
393
        return $this->reflClass;
394
    }
395
396
    /**
397
     * Gets the ReflectionPropertys of the mapped class.
398
     *
399
     * @return array An array of ReflectionProperty instances.
400
     */
401
    public function getReflectionProperties()
402
    {
403
        return $this->reflFields;
404
    }
405
406
    /**
407
     * Gets a ReflectionProperty for a specific field of the mapped class.
408
     *
409
     * @param string $name
410
     * @return ReflectionProperty
411
     */
412
    public function getReflectionProperty($name)
413
    {
414
        return $this->reflFields[$name];
415
    }
416
417
418
    /**
419
     * Sets the document identifier of a document.
420
     *
421
     * @param object $document
422
     * @param mixed $id
423
     */
424
    public function setIdentifierValue($document, $id)
425
    {
426
        $this->reflFields[$this->identifier]->setValue($document, $id);
427
    }
428
429
    /**
430
     * Gets the document identifier.
431
     *
432
     * @param object $document
433
     * @return string $id
434
     */
435
    public function getIdentifierValue($document)
436
    {
437
        return (string) $this->reflFields[$this->identifier]->getValue($document);
438
    }
439
440
    /**
441
     * Get identifier values of this document.
442
     *
443
     * Since CouchDB only allows exactly one identifier field this is a proxy
444
     * to {@see getIdentifierValue()} and returns an array with the identifier
445
     * field as a key.
446
     *
447
     * @param object $document
448
     * @return array
449
     */
450
    public function getIdentifierValues($document)
451
    {
452
        return array($this->identifier => $this->getIdentifierValue($document));
453
    }
454
455
    /**
456
     * Sets the specified field to the specified value on the given document.
457
     *
458
     * @param object $document
459
     * @param string $field
460
     * @param mixed $value
461
     */
462
    public function setFieldValue($document, $field, $value)
463
    {
464
        $this->reflFields[$field]->setValue($document, $value);
465
    }
466
467
    /**
468
     * Gets the specified field's value off the given document.
469
     *
470
     * @param object $document
471
     * @param string $field
472
     */
473
    public function getFieldValue($document, $field)
474
    {
475
        return $this->reflFields[$field]->getValue($document);
476
    }
477
478
    /**
479
     * Checks whether a field is part of the identifier/primary key field(s).
480
     *
481
     * @param string $fieldName  The field name
482
     * @return boolean  TRUE if the field is part of the table identifier/primary key field(s),
483
     *                  FALSE otherwise.
484
     */
485
    public function isIdentifier($fieldName)
486
    {
487
        return $this->identifier === $fieldName ? true : false;
488
    }
489
490
    /**
491
     * INTERNAL:
492
     * Sets the mapped identifier field of this class.
493
     *
494
     * @param string $identifier
495
     * @throws MappingException
496
     */
497
    public function setIdentifier($identifier)
498
    {
499
        if ($this->isEmbeddedDocument) {
500
            throw new MappingException('EmbeddedDocument should not have id field');
501
        }
502
        $this->identifier = $identifier;
503
    }
504
505
    /**
506
     * Gets the mapped identifier field of this class.
507
     *
508
     * @return string $identifier
509
     */
510
    public function getIdentifier()
511
    {
512
        return $this->identifier;
513
    }
514
515
    /**
516
     * Get identifier field names of this class.;
517
     *
518
     * Since CouchDB only allows exactly one identifier field this is a proxy
519
     * to {@see getIdentifier()} and returns an array.
520
     *
521
     * @return array
522
     */
523
    public function getIdentifierFieldNames()
524
    {
525
        return array($this->identifier);
526
    }
527
528
    /**
529
     * Checks whether the class has a (mapped) field with a certain name.
530
     *
531
     * @param $fieldName
532
     * @return boolean
533
     */
534
    public function hasField($fieldName)
535
    {
536
        return isset($this->fieldMappings[$fieldName]);
537
    }
538
539
    /**
540
     * Registers a custom repository class for the document class.
541
     *
542
     * @param string $repositoryClassName  The class name of the custom mapper.
543
     */
544
    public function setCustomRepositoryClass($repositoryClassName)
545
    {
546
        $this->customRepositoryClassName = $repositoryClassName;
547
    }
548
549
    /**
550
     * The name of this Document class.
551
     *
552
     * @return string $name The Document class name.
553
     */
554
    public function getName()
555
    {
556
        return $this->name;
557
    }
558
559
    /**
560
     * The namespace this Document class belongs to.
561
     *
562
     * @return string $namespace The namespace name.
563
     */
564
    public function getNamespace()
565
    {
566
        return $this->namespace;
567
    }
568
569
    /**
570
     * Set the field that will contain attachments of this document.
571
     *
572
     * @param string $fieldName
573
     * @throws MappingException
574
     */
575
    public function mapAttachments($fieldName)
576
    {
577
        if (isset($this->fieldMappings[$fieldName]) || isset($this->associationsMappings[$fieldName])) {
578
            throw MappingException::duplicateFieldMapping($this->name, $fieldName);
579
        }
580
581
        $this->hasAttachments = true;
582
        $this->attachmentField = $fieldName;
583
    }
584
585
    /**
586
     * Map an embedded object
587
     *
588
     * - fieldName - The name of the property/field on the mapped php class
589
     * - jsonName - JSON key name of this field in CouchDB.
590
     * - targetDocument - Name of the target document
591
     * - embedded - one or many embedded objects?
592
     *
593
     * @param array $mapping
594
     */
595
    public function mapEmbedded(array $mapping)
596
    {
597
        $mapping = $this->validateAndCompleteReferenceMapping($mapping);
598
599
        $this->mapField($mapping);
600
    }
601
602
    /**
603
     * Map a field.
604
     *
605
     * - type - The Doctrine Type of this field.
606
     * - fieldName - The name of the property/field on the mapped php class
607
     * - jsonName - JSON key name of this field in CouchDB.
608
     * - name - The JSON key of this field in the CouchDB document
609
     * - id - True for an ID field.
610
     * - strategy - ID Generator strategy when the field is an id-field.
611
     * - indexed - Is this field indexed for the Doctrine CouchDB repository view
612
     * - isVersionField - Is this field containing the revision number of this document?
613
     *
614
     * @param array $mapping The mapping information.
615
     */
616
    public function mapField(array $mapping)
617
    {
618
        $mapping = $this->validateAndCompleteFieldMapping($mapping);
619
620
        if (!isset($mapping['type'])) {
621
            $mapping['type'] = "mixed";
622
        }
623
624
        if (isset($mapping['id']) && $mapping['id'] === true) {
625
            $mapping['type'] = 'string';
626
            $mapping['jsonName'] = '_id';
627
            $this->setIdentifier($mapping['fieldName']);
628
            if (isset($mapping['strategy'])) {
629
                $this->idGenerator = constant('Doctrine\ODM\CouchDB\Mapping\ClassMetadata::IDGENERATOR_' . strtoupper($mapping['strategy']));
630
                unset($mapping['strategy']);
631
            }
632
        } else if (isset($mapping['isVersionField'])) {
633
            $this->isVersioned = true;
634
            $this->versionField = $mapping['fieldName'];
635
        }
636
637
        $mapping = $this->checkAndStoreIndexMapping($mapping);
638
639
        $this->fieldMappings[$mapping['fieldName']] = $mapping;
640
        $this->jsonNames[$mapping['jsonName']] = $mapping['fieldName'];
641
    }
642
643
    protected function validateAndCompleteFieldMapping($mapping)
644
    {
645
        if ( ! isset($mapping['fieldName']) || !$mapping['fieldName']) {
646
            throw new MappingException("Mapping a property requires to specify the name.");
647
        }
648
        if ( ! isset($mapping['jsonName'])) {
649
            $mapping['jsonName'] = $mapping['fieldName'];
650
        }
651
        if (isset($this->fieldMappings[$mapping['fieldName']]) || isset($this->associationsMappings[$mapping['fieldName']])) {
652
            throw MappingException::duplicateFieldMapping($this->name, $mapping['fieldName']);
653
        }
654
655
        return $mapping;
656
    }
657
658
    protected function validateAndCompleteReferenceMapping($mapping)
659
    {
660
        if (isset($mapping['targetDocument']) && $mapping['targetDocument'] && strpos($mapping['targetDocument'], '\\') === false && strlen($this->namespace)) {
661
            $mapping['targetDocument'] = $this->namespace . '\\' . $mapping['targetDocument'];
662
        }
663
        return $mapping;
664
    }
665
666
    protected function validateAndCompleteAssociationMapping($mapping)
667
    {
668
        $mapping = $this->validateAndCompleteFieldMapping($mapping);
669
670
        $mapping['sourceDocument'] = $this->name;
671
        $mapping = $this->validateAndCompleteReferenceMapping($mapping);
672
        return $mapping;
673
    }
674
675 View Code Duplication
    public function mapManyToOne($mapping)
676
    {
677
        $mapping = $this->validateAndCompleteAssociationMapping($mapping);
678
679
        $mapping['isOwning'] = true;
680
        $mapping['type'] = self::MANY_TO_ONE;
681
682
        $mapping = $this->checkAndStoreIndexMapping($mapping);
683
684
        $this->storeAssociationMapping($mapping);
685
    }
686
687 View Code Duplication
    public function mapManyToMany($mapping)
688
    {
689
        $mapping = $this->validateAndCompleteAssociationMapping($mapping);
690
691
        $mapping['isOwning'] = empty($mapping['mappedBy']);
692
        $mapping['type'] = self::MANY_TO_MANY;
693
694
        $this->storeAssociationMapping($mapping);
695
    }
696
697
    private function checkAndStoreIndexMapping($mapping)
698
    {
699
        if (isset($mapping['indexed']) && $mapping['indexed']) {
700
            $this->indexes[] = $mapping['fieldName'];
701
        }
702
        unset($mapping['indexed']);
703
704
        return $mapping;
705
    }
706
707
    private function storeAssociationMapping($mapping)
708
    {
709
        $this->associationsMappings[$mapping['fieldName']] = $mapping;
710
        $this->jsonNames[$mapping['jsonName']] = $mapping['fieldName'];
711
    }
712
713
    /**
714
     * A numerically indexed list of field names of this persistent class.
715
     *
716
     * This array includes identifier fields if present on this class.
717
     *
718
     * @return array
719
     */
720
    public function getFieldNames()
721
    {
722
        return array_keys($this->fieldMappings);
723
    }
724
725
    /**
726
     * Gets the mapping of a field.
727
     *
728
     * @param string $fieldName  The field name.
729
     * @return array  The field mapping.
730
     * @throws MappingException
731
     */
732
    public function getFieldMapping($fieldName)
733
    {
734
        if ( ! isset($this->fieldMappings[$fieldName])) {
735
            throw MappingException::mappingNotFound($this->name, $fieldName);
736
        }
737
        return $this->fieldMappings[$fieldName];
738
    }
739
740
    /**
741
     * Gets the type of a field.
742
     *
743
     * @param string $fieldName
744
     * @return Type
745
     */
746
    public function getTypeOfField($fieldName)
747
    {
748
        return isset($this->fieldMappings[$fieldName]) ?
749
                $this->fieldMappings[$fieldName]['type'] : null;
750
    }
751
752
    /**
753
     * Checks if the given field is a mapped association for this class.
754
     *
755
     * @param string $fieldName
756
     * @return boolean
757
     */
758
    public function hasAssociation($fieldName)
759
    {
760
        return isset($this->associationsMappings[$fieldName]);
761
    }
762
763
    public function isCollectionValuedAssociation($name)
764
    {
765
        // TODO: included @EmbedMany here also?
766
        return isset($this->associationsMappings[$name]) && ($this->associationsMappings[$name]['type'] & self::TO_MANY);
767
    }
768
769
    /**
770
     * Checks if the given field is a mapped single valued association for this class.
771
     *
772
     * @param string $fieldName
773
     * @return boolean
774
     */
775
    public function isSingleValuedAssociation($fieldName)
776
    {
777
        return isset($this->associationsMappings[$fieldName]) &&
778
                ($this->associationsMappings[$fieldName]['type'] & self::TO_ONE);
779
    }
780
781
    /**
782
     * A numerically indexed list of association names of this persistent class.
783
     *
784
     * This array includes identifier associations if present on this class.
785
     *
786
     * @return array
787
     */
788
    public function getAssociationNames()
789
    {
790
        return array_keys($this->associationsMappings);
791
    }
792
793
    /**
794
     * Returns the target class name of the given association.
795
     *
796
     * @param string $assocName
797
     * @return string
798
     * @throws \InvalidArgumentException
799
     */
800
    public function getAssociationTargetClass($assocName)
801
    {
802
        if (!isset($this->associationsMappings[$assocName])) {
803
            throw new \InvalidArgumentException("Association name expected, '" . $assocName ."' is not an association.");
804
        }
805
        return $this->associationsMappings[$assocName]['targetDocument'];
806
    }
807
808
    /**
809
     * {@inheritDoc}
810
     */
811
    public function getAssociationMappedByTargetField($assocName)
812
    {
813
        return $this->associationsMappings[$assocName]['mappedBy'];
814
    }
815
816
    /**
817
     * {@inheritDoc}
818
     */
819
    public function isAssociationInverseSide($assocName)
820
    {
821
        return isset($this->associationsMappings[$assocName]) && ! $this->associationsMappings[$assocName];
822
    }
823
824
    public function isInheritedField($field)
825
    {
826
        return isset($this->fieldMappings[$field]['declared']);
827
    }
828
829
    public function isInheritedAssociation($field)
830
    {
831
        return isset($this->associationsMappings[$field]['declared']);
832
    }
833
834
    public function setParentClasses($classes)
835
    {
836
        $this->parentClasses         = $classes;
837
        $this->inInheritanceHierachy = true;
838
        if (count($classes) > 0) {
839
            $this->rootDocumentName = array_pop($classes);
840
        }
841
    }
842
843
    public function markInheritanceRoot()
844
    {
845
        if ($this->parentClasses) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->parentClasses of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
846
            throw MappingException::invalidInheritanceRoot($this->name, $this->parentClasses);
847
        }
848
        $this->inInheritanceHierachy = true;
849
    }
850
851
    /**
852
     * Initializes a new ClassMetadata instance that will hold the object-relational mapping
853
     * metadata of the class with the given name.
854
     *
855
     * @param \Doctrine\Common\Persistence\Mapping\ReflectionService $reflService The reflection service.
856
     *
857
     * @return void
858
     */
859
    public function initializeReflection($reflService)
860
    {
861
        $this->reflClass = $reflService->getClass($this->name);
862
        $this->namespace = $reflService->getClassNamespace($this->name);
863
864
        if ($this->reflClass) {
865
            $this->name = $this->rootDocumentName = $this->reflClass->getName();
866
        }
867
    }
868
}
869
870