AssociationOverride   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 233
Duplicated Lines 9.87 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 21
c 1
b 0
f 0
lcom 1
cbo 4
dl 23
loc 233
ccs 85
cts 85
cp 1
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A mapJoinColumns() 0 15 4
A hasJoinColumns() 0 4 1
A hasInverseJoinColumns() 0 4 1
A hasJoinTable() 0 4 1
A __construct() 11 11 1
B build() 6 60 7
A convertToMappingArray() 0 6 1
A newClassMetadataBuilder() 0 6 1
A getAssociationBuilder() 0 9 1
A mapJoinTable() 6 20 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace LaravelDoctrine\Fluent\Builders\Overrides;
4
5
use Doctrine\ORM\Mapping\Builder\ClassMetadataBuilder;
6
use Doctrine\ORM\Mapping\ClassMetadataInfo;
7
use Doctrine\ORM\Mapping\NamingStrategy;
8
use InvalidArgumentException;
9
use LaravelDoctrine\Fluent\Buildable;
10
use LaravelDoctrine\Fluent\Relations\ManyToMany;
11
use LaravelDoctrine\Fluent\Relations\ManyToOne;
12
use LaravelDoctrine\Fluent\Relations\Relation;
13
14
class AssociationOverride implements Buildable
15
{
16
    /**
17
     * @var string
18
     */
19
    protected $name;
20
21
    /**
22
     * @var callable
23
     */
24
    protected $callback;
25
26
    /**
27
     * @var ClassMetadataBuilder
28
     */
29
    protected $builder;
30
31
    /**
32
     * @var NamingStrategy
33
     */
34
    protected $namingStrategy;
35
36
    /**
37
     * @var array
38
     */
39
    protected $relations = [
40
        ClassMetadataInfo::MANY_TO_ONE  => ManyToOne::class,
41
        ClassMetadataInfo::MANY_TO_MANY => ManyToMany::class
42
    ];
43
44
    /**
45
     * @param ClassMetadataBuilder $builder
46
     * @param NamingStrategy       $namingStrategy
47
     * @param string               $name
48
     * @param callable             $callback
49
     */
50 13 View Code Duplication
    public function __construct(
51
        ClassMetadataBuilder $builder,
52
        NamingStrategy $namingStrategy,
53
        $name,
54
        callable $callback
55
    ) {
56 13
        $this->builder        = $builder;
57 13
        $this->callback       = $callback;
58 13
        $this->name           = $name;
59 13
        $this->namingStrategy = $namingStrategy;
60 13
    }
61
62
    /**
63
     * Execute the build process
64
     */
65 12
    public function build()
66
    {
67 12
        $callback = $this->callback;
68
69
        // We will create a new class metadata builder instance,
70
        // so we can use it to easily generated a new mapping
71
        // array, without re-declaring the existing association
72 12
        $builder = $this->newClassMetadataBuilder();
73 12
        $source  = $this->convertToMappingArray($this->builder);
74
75 11
        if (!isset($this->relations[$source['type']])) {
76 1
            throw new InvalidArgumentException('Only ManyToMany and ManyToOne relations can be overridden');
77
        }
78
79
        // Create a new association builder, based on the given type
80 10
        $associationBuilder = $this->getAssociationBuilder($builder, $source);
81
82
        // Give the original join table name, so we won't
83
        // accidentally remove custom join table names
84 10
        if ($this->hasJoinTable($source)) {
85 7
            $associationBuilder->setJoinTable($source['joinTable']['name']);
86 7
        }
87
88 10
        $association = $callback($associationBuilder);
89
90
        // When the user forget to return, use the $associationBuilder instance
91
        // which contains the same information
92 10
        $association = $association ?: $associationBuilder;
93
94 10
        if (!$association instanceof Relation) {
95 1
            throw new InvalidArgumentException("The callback should return an instance of " . Relation::class);
96
        }
97
98 9
        $association->build();
99
100 9
        $target = $this->convertToMappingArray($builder);
101
102 9
        $overrideMapping = [];
103
104
        // ManyToMany mappings
105 9
        if ($this->hasJoinTable($target)) {
106 6
            $overrideMapping['joinTable'] = $this->mapJoinTable(
107 6
                $target['joinTable'],
108 6
                $source['joinTable']
109 6
            );
110 6
        }
111
112
        // ManyToOne mappings
113 9 View Code Duplication
        if ($this->hasJoinColumns($target)) {
114 3
            $overrideMapping['joinColumns'] = $this->mapJoinColumns(
115 3
                $target['joinColumns'],
116 3
                $source['joinColumns']
117 3
            );
118 3
        }
119
120 9
        $this->builder->getClassMetadata()->setAssociationOverride(
121 9
            $this->name,
122
            $overrideMapping
123 9
        );
124 9
    }
125
126
    /**
127
     * @param ClassMetadataBuilder $builder
128
     *
129
     * @throws \Doctrine\ORM\Mapping\MappingException
130
     * @return array
131
     */
132 12
    protected function convertToMappingArray(ClassMetadataBuilder $builder)
133
    {
134 12
        $metadata = $builder->getClassMetadata();
135
136 12
        return $metadata->getAssociationMapping($this->name);
137
    }
138
139
    /**
140
     * @return ClassMetadataBuilder
141
     */
142 12
    protected function newClassMetadataBuilder()
143
    {
144 12
        return new ClassMetadataBuilder(
145 12
            new ClassMetadataInfo($this->builder->getClassMetadata()->name)
146 12
        );
147
    }
148
149
    /**
150
     * @param $builder
151
     * @param $source
152
     *
153
     * @return mixed
154
     */
155 10
    protected function getAssociationBuilder(ClassMetadataBuilder $builder, array $source)
156
    {
157 10
        return new $this->relations[$source['type']](
158 10
            $builder,
159 10
            $this->namingStrategy,
160 10
            $this->name,
161 10
            $source['targetEntity']
162 10
        );
163
    }
164
165
    /**
166
     * @param array $target
167
     * @param array $source
168
     *
169
     * @return array
170
     */
171 6
    protected function mapJoinTable(array $target = [], array $source = [])
172
    {
173 6
        $joinTable['name'] = $target['name'];
174
175 6 View Code Duplication
        if ($this->hasJoinColumns($target)) {
176 6
            $joinTable['joinColumns'] = $this->mapJoinColumns(
177 6
                $target['joinColumns'],
178 6
                $source['joinColumns']
179 6
            );
180 6
        }
181
182 6
        if ($this->hasInverseJoinColumns($target)) {
183 6
            $joinTable['inverseJoinColumns'] = $this->mapJoinColumns(
184 6
                $target['inverseJoinColumns'],
185 6
                $source['inverseJoinColumns']
186 6
            );
187 6
        }
188
189 6
        return $joinTable;
190
    }
191
192
    /**
193
     * @param array $target
194
     * @param array $source
195
     *
196
     * @return mixed
197
     * @internal param $target
198
     * @internal param $source
199
     * @internal param $overrideMapping
200
     */
201 9
    protected function mapJoinColumns(array $target = [], array $source = [])
202
    {
203 9
        $joinColumns = [];
204 9
        foreach ($target as $index => $joinColumn) {
205 9
            if (isset($source[$index])) {
206 9
                $diff = array_diff($joinColumn, $source[$index]);
207
208 9
                if (!empty($diff)) {
209 6
                    $joinColumns[] = $diff;
210 6
                }
211 9
            }
212 9
        }
213
214 9
        return $joinColumns;
215
    }
216
217
    /**
218
     * @param array $target
219
     *
220
     * @return bool
221
     */
222 9
    protected function hasJoinColumns(array $target = [])
223
    {
224 9
        return isset($target['joinColumns']);
225
    }
226
227
    /**
228
     * @param array $target
229
     *
230
     * @return bool
231
     */
232 6
    protected function hasInverseJoinColumns(array $target = [])
233
    {
234 6
        return isset($target['inverseJoinColumns']);
235
    }
236
237
    /**
238
     * @param array $target
239
     *
240
     * @return bool
241
     */
242 10
    protected function hasJoinTable(array $target = [])
243
    {
244 10
        return isset($target['joinTable']);
245
    }
246
}
247