Passed
Push — master ( 7b5f02...eec92d )
by Gerrit
02:49
created

ChoiceMapping::addChoice()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

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