Completed
Push — master ( 481496...88a09b )
by Gerrit
04:44
created

ChoiceMapping   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 211
Duplicated Lines 26.07 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 87.95%

Importance

Changes 0
Metric Value
wmc 26
lcom 1
cbo 4
dl 55
loc 211
ccs 73
cts 83
cp 0.8795
rs 10
c 0
b 0
f 0

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 10 25 3
A getChoices() 0 4 1
A describeOrigin() 0 4 1
A collectDBALColumns() 0 18 2
A getDeterminatorColumn() 0 4 1
A getDeterminatorColumnName() 0 4 1
A addChoice() 0 4 1
A resolveValue() 22 35 5
A revertValue() 0 40 4
A assertValue() 23 32 5
A wakeUpMapping() 0 8 2

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
 * Copyright (C) 2018 Gerrit Addiks.
4
 * This package (including this file) was released under the terms of the GPL-3.0.
5
 * You should have received a copy of the GNU General Public License along with this program.
6
 * If not, see <http://www.gnu.org/licenses/> or send me a mail so i can send you a copy.
7
 * @license GPL-3.0
8
 * @author Gerrit Addiks <[email protected]>
9
 */
10
11
namespace Addiks\RDMBundle\Mapping;
12
13
use Addiks\RDMBundle\Mapping\MappingInterface;
14
use Doctrine\DBAL\Schema\Column;
15
use Doctrine\DBAL\Types\Type;
16
use Addiks\RDMBundle\Exception\InvalidMappingException;
17
use Addiks\RDMBundle\Hydration\HydrationContextInterface;
18
use Symfony\Component\DependencyInjection\ContainerInterface;
19
use Exception;
20
21
final class ChoiceMapping implements MappingInterface
22
{
23
24
    /**
25
     * @var Column
26
     */
27
    private $determinatorColumn;
28
29
    /**
30
     * @var array<MappingInterface>
31
     */
32
    private $choiceMappings = array();
33
34
    /**
35
     * @var string
36
     */
37
    private $originDescription;
38
39
    /**
40
     * @param string|Column $determinatorColumn
41
     */
42 15
    public function __construct(
43
        $determinatorColumn,
44
        array $choiceMappings,
45
        string $originDescription = ""
46
    ) {
47 15 View Code Duplication
        if (!$determinatorColumn instanceof Column) {
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...
48 6
            $determinatorColumn = new Column(
49 6
                (string)$determinatorColumn,
50 6
                Type::getType('string'),
51
                [
52 6
                    'notnull' => false,
53
                    'length'  => 255,
54
                ]
55
            );
56
        }
57
58 15
        $this->determinatorColumn = clone $determinatorColumn;
59 15
        $this->originDescription = $originDescription;
60
61 15
        foreach ($choiceMappings as $determinator => $choiceMapping) {
62
            /** @var MappingInterface $choiceMapping */
63
64 14
            $this->addChoice($determinator, $choiceMapping);
65
        }
66 15
    }
67
68 1
    public function getChoices(): array
69
    {
70 1
        return $this->choiceMappings;
71
    }
72
73 1
    public function describeOrigin(): string
74
    {
75 1
        return $this->originDescription;
76
    }
77
78 3
    public function collectDBALColumns(): array
79
    {
80
        /** @var array<Column> $additionalMappings */
81
        $additionalMappings = array(
82 3
            clone $this->determinatorColumn
83
        );
84
85 3
        foreach ($this->choiceMappings as $choiceMapping) {
86
            /** @var MappingInterface $choiceMapping */
87
88 2
            $additionalMappings = array_merge(
89 2
                $additionalMappings,
90 2
                $choiceMapping->collectDBALColumns()
91
            );
92
        }
93
94 3
        return $additionalMappings;
95
    }
96
97 1
    public function getDeterminatorColumn(): Column
98
    {
99 1
        return clone $this->determinatorColumn;
100
    }
101
102 1
    public function getDeterminatorColumnName(): string
103
    {
104 1
        return $this->determinatorColumn->getName();
105
    }
106
107 14
    private function addChoice(string $determinator, MappingInterface $choiceMapping): void
108
    {
109 14
        $this->choiceMappings[$determinator] = $choiceMapping;
110 14
    }
111
112 2
    public function resolveValue(
113
        HydrationContextInterface $context,
114
        array $dataFromAdditionalColumns
115
    ) {
116
        /** @var mixed $value */
117 2
        $value = null;
118
119
        /** @var string $determinatorColumn */
120 2
        $determinatorColumn = $this->determinatorColumn->getName();
121
122 2 View Code Duplication
        if (array_key_exists($determinatorColumn, $dataFromAdditionalColumns)) {
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...
123
            /** @var string|int $determinatorValue */
124 2
            $determinatorValue = $dataFromAdditionalColumns[$determinatorColumn];
125
126 2
            if (!empty($determinatorValue) && !array_key_exists($determinatorValue, $this->choiceMappings)) {
127
                throw new InvalidMappingException(sprintf(
128
                    "Invalid option-value '%s' for choice-column '%s' on entity %s!",
129
                    $determinatorValue,
130
                    $determinatorColumn,
131
                    $context->getEntityClass()
132
                ));
133
            }
134
135 2
            if (isset($this->choiceMappings[$determinatorValue])) {
136 2
                $choiceMapping = $this->choiceMappings[$determinatorValue];
137
138 2
                $value = $choiceMapping->resolveValue(
139 2
                    $context,
140 2
                    $dataFromAdditionalColumns
141
                );
142
            }
143
        }
144
145 2
        return $value;
146
    }
147
148 3
    public function revertValue(
149
        HydrationContextInterface $context,
150
        $valueFromEntityField
151
    ): array {
152
        /** @var array<scalar> $data */
153 3
        $data = array();
154
155
        /** @var string $determinatorColumn */
156 3
        $determinatorColumn = $this->determinatorColumn->getName();
157
158
        /** @var ?scalar $determinatorValue */
0 ignored issues
show
Documentation introduced by
The doc-type ?scalar could not be parsed: Unknown type name "?scalar" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
159 3
        $determinatorValue = null;
160
161 3
        foreach ($this->choiceMappings as $choiceDeterminatorValue => $choiceMapping) {
162
            /** @var MappingInterface $choiceMapping */
163
164
            try {
165
                /** @var array<scalar> $choiceData */
166 3
                $choiceData = $choiceMapping->revertValue($context, $valueFromEntityField);
167
168 3
                $choiceValue = $choiceMapping->resolveValue(
169 3
                    $context,
170 3
                    $choiceData
171
                );
172
173 3
                if ($choiceValue === $valueFromEntityField) {
174 3
                    $determinatorValue = $choiceDeterminatorValue;
175 3
                    $data = $choiceData;
176 3
                    break;
177
                }
178
179 2
            } catch (Exception $exception) {
180
                # This mapping did not match, continue with the next
181
            }
182
        }
183
184 3
        $data[$determinatorColumn] = $determinatorValue;
185
186 3
        return $data;
187
    }
188
189 2
    public function assertValue(
190
        HydrationContextInterface $context,
191
        array $dataFromAdditionalColumns,
192
        $actualValue
193
    ): void {
194
        /** @var string $determinatorColumn */
195 2
        $determinatorColumn = $this->determinatorColumn->getName();
196
197 2 View Code Duplication
        if (array_key_exists($determinatorColumn, $dataFromAdditionalColumns)) {
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...
198
            /** @var string|int $determinatorValue */
199 2
            $determinatorValue = $dataFromAdditionalColumns[$determinatorColumn];
200
201 2
            if (!empty($determinatorValue) && !array_key_exists($determinatorValue, $this->choiceMappings)) {
202
                throw new InvalidMappingException(sprintf(
203
                    "Invalid option-value '%s' for choice-column '%s' on entity %s!",
204
                    $determinatorValue,
205
                    $determinatorColumn,
206
                    $context->getEntityClass()
207
                ));
208
            }
209
210 2
            if (isset($this->choiceMappings[$determinatorValue])) {
211 2
                $choiceMapping = $this->choiceMappings[$determinatorValue];
212
213 2
                $choiceMapping->assertValue(
214 2
                    $context,
215 2
                    $dataFromAdditionalColumns,
216 2
                    $actualValue
217
                );
218
            }
219
        }
220 2
    }
221
222 1
    public function wakeUpMapping(ContainerInterface $container): void
223
    {
224 1
        foreach ($this->choiceMappings as $choiceMapping) {
225
            /** @var MappingInterface $choiceMapping */
226
227 1
            $choiceMapping->wakeUpMapping($container);
228
        }
229 1
    }
230
231
}
232