Completed
Push — master ( 09b86b...ba0798 )
by Andreas
20:05 queued 12s
created

ResolveTargetDocumentListener::loadClassMetadata()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 7
cts 7
cp 1
rs 9.8666
c 0
b 0
f 0
cc 3
nc 3
nop 1
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ODM\MongoDB\Tools;
6
7
use Doctrine\Common\EventSubscriber;
8
use Doctrine\ODM\MongoDB\Event\LoadClassMetadataEventArgs;
9
use Doctrine\ODM\MongoDB\Event\OnClassMetadataNotFoundEventArgs;
10
use Doctrine\ODM\MongoDB\Events;
11
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
12
use function array_key_exists;
13
use function array_replace_recursive;
14
use function ltrim;
15
16
/**
17
 * ResolveTargetDocumentListener
18
 *
19
 * Mechanism to overwrite document interfaces or classes specified as association targets.
20
 */
21
class ResolveTargetDocumentListener implements EventSubscriber
22
{
23
    /** @var array */
24
    private $resolveTargetDocuments = [];
25
26
    /**
27
     * {@inheritDoc}
28
     */
29 2
    public function getSubscribedEvents()
30
    {
31
        return [
32 2
            Events::loadClassMetadata,
33
            Events::onClassMetadataNotFound,
34
        ];
35
    }
36
37
    /**
38
     * Add a target-document class name to resolve to a new class name.
39
     */
40 3
    public function addResolveTargetDocument(string $originalDocument, string $newDocument, array $mapping) : void
41
    {
42 3
        $mapping['targetDocument']                                    = ltrim($newDocument, '\\');
43 3
        $this->resolveTargetDocuments[ltrim($originalDocument, '\\')] = $mapping;
44 3
    }
45
46
    /**
47
     * @internal this is an event callback, and should not be called directly
48
     *
49
     * @return void
50
     */
51 2
    public function onClassMetadataNotFound(OnClassMetadataNotFoundEventArgs $args)
52
    {
53 2
        if (! array_key_exists($args->getClassName(), $this->resolveTargetDocuments)) {
54
            return;
55
        }
56
57 2
        $args->setFoundMetadata(
58
            $args
59 2
                ->getDocumentManager()
60 2
                ->getClassMetadata($this->resolveTargetDocuments[$args->getClassName()]['targetDocument'])
61
        );
62 2
    }
63
64
    /**
65
     * Process event and resolve new target document names.
66
     */
67 3
    public function loadClassMetadata(LoadClassMetadataEventArgs $args) : void
68
    {
69
        /** @var ClassMetadata $cm */
70 3
        $cm = $args->getClassMetadata();
71 3
        foreach ($cm->associationMappings as $mapping) {
72 3
            if (! isset($this->resolveTargetDocuments[$mapping['targetDocument']])) {
73 2
                continue;
74
            }
75
76 2
            $this->remapAssociation($cm, $mapping);
77
        }
78 3
    }
79
80 2
    private function remapAssociation(ClassMetadata $classMetadata, array $mapping) : void
81
    {
82 2
        $newMapping              = $this->resolveTargetDocuments[$mapping['targetDocument']];
83 2
        $newMapping              = array_replace_recursive($mapping, $newMapping);
84 2
        $newMapping['fieldName'] = $mapping['fieldName'];
85
86
        // clear reference case of duplicate exception
87 2
        unset($classMetadata->fieldMappings[$mapping['fieldName']]);
88 2
        unset($classMetadata->associationMappings[$mapping['fieldName']]);
89
90 2
        switch ($mapping['association']) {
91
            case ClassMetadata::REFERENCE_ONE:
92 2
                $classMetadata->mapOneReference($newMapping);
93 2
                break;
94
            case ClassMetadata::REFERENCE_MANY:
95 1
                $classMetadata->mapManyReference($newMapping);
96 1
                break;
97
            case ClassMetadata::EMBED_ONE:
98 2
                $classMetadata->mapOneEmbedded($newMapping);
99 2
                break;
100
            case ClassMetadata::EMBED_MANY:
101 1
                $classMetadata->mapManyEmbedded($newMapping);
102 1
                break;
103
        }
104 2
    }
105
}
106