Passed
Push — master ( 50749f...7b5f02 )
by Gerrit
12:36
created

ChoiceMapping::getDeterminatorColumn()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
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
use Webmozart\Assert\Assert;
21
22
final class ChoiceMapping implements MappingInterface
23
{
24
25
    /**
26
     * @var Column
27
     */
28
    private $determinatorColumn;
29
30
    /**
31
     * @var array<MappingInterface>
32
     */
33
    private $choiceMappings = array();
34
35
    /**
36
     * @var string
37
     */
38
    private $originDescription;
39
40
    /**
41
     * @param string|Column $determinatorColumn
42
     */
43 16
    public function __construct(
44
        $determinatorColumn,
45
        array $choiceMappings,
46
        string $originDescription = ""
47
    ) {
48 16
        if (!$determinatorColumn instanceof Column) {
49 6
            Assert::string($determinatorColumn);
50 6
            $determinatorColumn = new Column(
51 6
                $determinatorColumn,
52 6
                Type::getType('string'),
53
                [
54 6
                    'notnull' => false,
55
                    'length'  => 255,
56
                ]
57
            );
58
        }
59
60 16
        $this->determinatorColumn = clone $determinatorColumn;
61 16
        $this->originDescription = $originDescription;
62
63 16
        foreach ($choiceMappings as $determinator => $choiceMapping) {
64
            /** @var MappingInterface $choiceMapping */
65
66 15
            $this->addChoice($determinator, $choiceMapping);
67
        }
68 16
    }
69
70 1
    public function getChoices(): array
71
    {
72 1
        return $this->choiceMappings;
73
    }
74
75 1
    public function describeOrigin(): string
76
    {
77 1
        return $this->originDescription;
78
    }
79
80 4
    public function collectDBALColumns(): array
81
    {
82
        /** @var array<Column> $additionalMappings */
83
        $additionalMappings = array(
84 4
            clone $this->determinatorColumn
85
        );
86
87 4
        foreach ($this->choiceMappings as $choiceMapping) {
88
            /** @var MappingInterface $choiceMapping */
89
90 3
            $additionalMappings = array_merge(
91 3
                $additionalMappings,
92 3
                $choiceMapping->collectDBALColumns()
93
            );
94
        }
95
96 4
        return $additionalMappings;
97
    }
98
99 1
    public function getDeterminatorColumn(): Column
100
    {
101 1
        return clone $this->determinatorColumn;
102
    }
103
104 1
    public function getDeterminatorColumnName(): string
105
    {
106 1
        return $this->determinatorColumn->getName();
107
    }
108
109 15
    private function addChoice(string $determinator, MappingInterface $choiceMapping): void
110
    {
111 15
        $this->choiceMappings[$determinator] = $choiceMapping;
112 15
    }
113
114 2
    public function resolveValue(
115
        HydrationContextInterface $context,
116
        array $dataFromAdditionalColumns
117
    ) {
118
        /** @var mixed $value */
119 2
        $value = null;
120
121
        /** @var string $determinatorColumn */
122 2
        $determinatorColumn = $this->determinatorColumn->getName();
123
124 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...
125
            /** @var string|int $determinatorValue */
126 2
            $determinatorValue = $dataFromAdditionalColumns[$determinatorColumn];
127
128 2
            if (!empty($determinatorValue) && !array_key_exists($determinatorValue, $this->choiceMappings)) {
129
                throw new InvalidMappingException(sprintf(
130
                    "Invalid option-value '%s' for choice-column '%s' on entity %s!",
131
                    $determinatorValue,
132
                    $determinatorColumn,
133
                    $context->getEntityClass()
134
                ));
135
            }
136
137 2
            if (isset($this->choiceMappings[$determinatorValue])) {
138 2
                $choiceMapping = $this->choiceMappings[$determinatorValue];
139
140 2
                $value = $choiceMapping->resolveValue(
141 2
                    $context,
142
                    $dataFromAdditionalColumns
143
                );
144
            }
145
        }
146
147 2
        return $value;
148
    }
149
150 3
    public function revertValue(
151
        HydrationContextInterface $context,
152
        $valueFromEntityField
153
    ): array {
154
        /** @var array<string, scalar|null> $data */
155 3
        $data = array();
156
157
        /** @var string $determinatorColumn */
158 3
        $determinatorColumn = $this->determinatorColumn->getName();
159
160
        /** @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...
161 3
        $determinatorValue = null;
162
163 3
        foreach ($this->choiceMappings as $choiceDeterminatorValue => $choiceMapping) {
164
            /** @var MappingInterface $choiceMapping */
165
166
            try {
167
                /** @var array<scalar> $choiceData */
168 3
                $choiceData = $choiceMapping->revertValue($context, $valueFromEntityField);
169
170 3
                $choiceValue = $choiceMapping->resolveValue(
171 3
                    $context,
172
                    $choiceData
173
                );
174
175 3
                if ($choiceValue === $valueFromEntityField) {
176 3
                    $determinatorValue = $choiceDeterminatorValue;
177 3
                    $data = $choiceData;
178 3
                    break;
179
                }
180
181
            } catch (Exception $exception) {
182
                # This mapping did not match, continue with the next
183
            }
184
        }
185
186 3
        $data[$determinatorColumn] = $determinatorValue;
187
188 3
        return $data;
189
    }
190
191 2
    public function assertValue(
192
        HydrationContextInterface $context,
193
        array $dataFromAdditionalColumns,
194
        $actualValue
195
    ): void {
196
        /** @var string $determinatorColumn */
197 2
        $determinatorColumn = $this->determinatorColumn->getName();
198
199 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...
200
            /** @var string|int $determinatorValue */
201 2
            $determinatorValue = $dataFromAdditionalColumns[$determinatorColumn];
202
203 2
            if (!empty($determinatorValue) && !array_key_exists($determinatorValue, $this->choiceMappings)) {
204
                throw new InvalidMappingException(sprintf(
205
                    "Invalid option-value '%s' for choice-column '%s' on entity %s!",
206
                    $determinatorValue,
207
                    $determinatorColumn,
208
                    $context->getEntityClass()
209
                ));
210
            }
211
212 2
            if (isset($this->choiceMappings[$determinatorValue])) {
213 2
                $choiceMapping = $this->choiceMappings[$determinatorValue];
214
215 2
                $choiceMapping->assertValue(
216 2
                    $context,
217
                    $dataFromAdditionalColumns,
218
                    $actualValue
219
                );
220
            }
221
        }
222 2
    }
223
224 1
    public function wakeUpMapping(ContainerInterface $container): void
225
    {
226 1
        foreach ($this->choiceMappings as $choiceMapping) {
227
            /** @var MappingInterface $choiceMapping */
228
229 1
            $choiceMapping->wakeUpMapping($container);
230
        }
231 1
    }
232
233
}
234