Completed
Push — master ( f563c7...7369e3 )
by Kamil
20:40
created

ODMMappedSuperClassSubscriber   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 119
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 20
lcom 1
cbo 3
dl 0
loc 119
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getSubscribedEvents() 0 6 1
A loadClassMetadata() 0 12 2
A convertToDocumentIfNeeded() 0 16 4
A unsetAssociationMappings() 0 12 4
C setAssociationMappings() 0 31 8
A isRelation() 0 13 1
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sylius\Bundle\ResourceBundle\EventListener;
13
14
use Doctrine\ODM\MongoDB\Event\LoadClassMetadataEventArgs;
15
use Doctrine\ODM\MongoDB\Events;
16
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
17
use Doctrine\ODM\MongoDB\Mapping\ClassMetadataInfo;
18
19
/**
20
 * Doctrine listener used to manipulate mappings.
21
 *
22
 * @author Ivannis Suárez Jérez <[email protected]>
23
 */
24
final class ODMMappedSuperClassSubscriber extends AbstractDoctrineSubscriber
25
{
26
    /**
27
     * @return array
28
     */
29
    public function getSubscribedEvents()
30
    {
31
        return [
32
            Events::loadClassMetadata,
33
        ];
34
    }
35
36
    /**
37
     * @param LoadClassMetadataEventArgs $eventArgs
38
     */
39
    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
40
    {
41
        $metadata = $eventArgs->getClassMetadata();
42
43
        $this->convertToDocumentIfNeeded($metadata);
44
45
        if (!$metadata->isMappedSuperclass) {
46
            $this->setAssociationMappings($metadata, $eventArgs->getDocumentManager()->getConfiguration());
47
        } else {
48
            $this->unsetAssociationMappings($metadata);
49
        }
50
    }
51
52
    /**
53
     * @param ClassMetadataInfo $metadata
54
     */
55
    private function convertToDocumentIfNeeded(ClassMetadataInfo $metadata)
56
    {
57
        if (false === $metadata->isMappedSuperclass) {
58
            return;
59
        }
60
61
        try {
62
            $resourceMetadata = $this->resourceRegistry->getByClass($metadata->getName());
63
        } catch (\InvalidArgumentException $exception) {
64
            return;
65
        }
66
67
        if ($metadata->getName() === $resourceMetadata->getClass('model')) {
68
            $metadata->isMappedSuperclass = false;
69
        }
70
    }
71
72
    /**
73
     * @param ClassMetadataInfo $metadata
74
     * @param $configuration
75
     */
76
    private function setAssociationMappings(ClassMetadataInfo $metadata, $configuration)
77
    {
78
        foreach (class_parents($metadata->getName()) as $parent) {
79
            if (false === in_array($parent, $configuration->getMetadataDriverImpl()->getAllClassNames())) {
80
                continue;
81
            }
82
83
            $parentMetadata = new ClassMetadata(
84
                $parent,
85
                $configuration->getNamingStrategy()
86
            );
87
88
            // Wakeup Reflection
89
            $parentMetadata->wakeupReflection($this->getReflectionService());
90
91
            // Load Metadata
92
            $configuration->getMetadataDriverImpl()->loadMetadataForClass($parent, $parentMetadata);
93
94
            if (false === $this->isResource($parentMetadata)) {
95
                continue;
96
            }
97
98
            if ($parentMetadata->isMappedSuperclass) {
99
                foreach ($parentMetadata->associationMappings as $key => $value) {
100
                    if ($this->isRelation($value['association']) && !isset($metadata->associationMappings[$key])) {
101
                        $metadata->associationMappings[$key] = $value;
102
                    }
103
                }
104
            }
105
        }
106
    }
107
108
    /**
109
     * @param ClassMetadataInfo $metadata
110
     */
111
    private function unsetAssociationMappings(ClassMetadataInfo $metadata)
112
    {
113
        if (false === $this->isResource($metadata)) {
114
            return;
115
        }
116
117
        foreach ($metadata->associationMappings as $key => $value) {
118
            if ($this->isRelation($value['association'])) {
119
                unset($metadata->associationMappings[$key]);
120
            }
121
        }
122
    }
123
124
    /**
125
     * @param string $type
126
     *
127
     * @return bool
128
     */
129
    private function isRelation($type)
130
    {
131
        return in_array(
132
            $type,
133
            [
134
                ClassMetadataInfo::REFERENCE_ONE,
135
                ClassMetadataInfo::REFERENCE_MANY,
136
                ClassMetadataInfo::EMBED_ONE,
137
                ClassMetadataInfo::EMBED_MANY,
138
            ],
139
            true
140
        );
141
    }
142
}
143