convertAnnotationToMapping()   C
last analyzed

Complexity

Conditions 13
Paths 11

Size

Total Lines 171
Code Lines 101

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 63
CRAP Score 13.0006

Importance

Changes 0
Metric Value
cc 13
eloc 101
c 0
b 0
f 0
nc 11
nop 4
dl 0
loc 171
ccs 63
cts 64
cp 0.9844
crap 13.0006
rs 5.2933

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Drivers;
12
13
use Doctrine\Common\Annotations\Reader;
14
use ReflectionClass;
15
use ReflectionProperty;
16
use Addiks\RDMBundle\Mapping\Drivers\MappingDriverInterface;
17
use Addiks\RDMBundle\Mapping\MappingInterface;
18
use Addiks\RDMBundle\Mapping\EntityMapping;
19
use Addiks\RDMBundle\Mapping\Annotation\Service;
20
use Addiks\RDMBundle\Mapping\ServiceMapping;
21
use Addiks\RDMBundle\Mapping\EntityMappingInterface;
22
use Addiks\RDMBundle\Mapping\Annotation\Choice;
23
use Addiks\RDMBundle\Mapping\ChoiceMapping;
24
use Addiks\RDMBundle\Exception\InvalidMappingException;
25
use Doctrine\ORM\Mapping\Column as ColumnAnnotation;
26
use Doctrine\DBAL\Schema\Column as DBALColumn;
27
use Doctrine\DBAL\Types\Type;
28
use Addiks\RDMBundle\Mapping\ObjectMapping;
29
use Addiks\RDMBundle\Mapping\CallDefinitionInterface;
30
use Addiks\RDMBundle\Mapping\FieldMapping;
31
use Addiks\RDMBundle\Mapping\ArrayMapping;
32
use Addiks\RDMBundle\Mapping\Annotation\RDMObject;
33
use Addiks\RDMBundle\Mapping\Annotation\RDMArray;
34
use Symfony\Component\DependencyInjection\ContainerInterface;
35
use Webmozart\Assert\Assert;
36
37
final class MappingAnnotationDriver implements MappingDriverInterface
38
{
39
40
    /**
41
     * @var ContainerInterface
42
     */
43
    private $container;
44
45
    /**
46
     * @var Reader
47
     */
48
    private $annotationReader;
49
50 8
    public function __construct(
51
        ContainerInterface $container,
52
        Reader $annotationReader
53
    ) {
54 8
        $this->container = $container;
55 8
        $this->annotationReader = $annotationReader;
56
    }
57
58 7
    public function loadRDMMetadataForClass(string $className): ?EntityMappingInterface
59
    {
60
        /** @var ?EntityMappingInterface $mapping */
61 7
        $mapping = null;
62
63
        /** @var array<MappingInterface> $fieldMappings */
64 7
        $fieldMappings = array();
65
66 7
        $classReflection = new ReflectionClass($className);
67
68 7
        foreach ($classReflection->getProperties() as $propertyReflection) {
69
            /** @var ReflectionProperty $propertyReflection */
70
71
            /** @var string $fieldName */
72 7
            $fieldName = $propertyReflection->getName();
73
74
            /** @var array<object> $annotations */
75 7
            $annotations = $this->annotationReader->getPropertyAnnotations($propertyReflection);
76
77 7
            foreach ($annotations as $annotation) {
78
                /** @var object $annotation */
79
80 7
                $fieldMapping = $this->convertAnnotationToMapping($annotation, $fieldName, $className);
81
82 7
                if ($fieldMapping instanceof MappingInterface) {
83 7
                    $fieldMappings[$fieldName] = $fieldMapping;
84
                }
85
            }
86
        }
87
88 7
        if (!empty($fieldMappings)) {
89 7
            $mapping = new EntityMapping($className, $fieldMappings);
90
        }
91
92 7
        return $mapping;
93
    }
94
95
    /**
96
     * @param object $annotation
97
     */
98 7
    private function convertAnnotationToMapping(
99
        $annotation,
100
        string $fieldName,
101
        string $className,
102
        bool $convertFieldsOnRootLevel = false
103
    ): ?MappingInterface {
104
        /** @var ?MappingInterface $fieldMapping */
105 7
        $fieldMapping = null;
106
107 7
        if ($annotation instanceof Service) {
108 6
            $fieldMapping = new ServiceMapping(
109 6
                $this->container,
110 6
                $annotation->id,
111 6
                $annotation->lax,
112 6
                sprintf(
113
                    "in entity '%s' on field '%s'",
114
                    $className,
115
                    $fieldName
116
                )
117
            );
118
119 7
        } elseif ($annotation instanceof Choice) {
120
            /** @var string|null|ColumnAnnotation $column */
121 5
            $column = $annotation->column;
122
123 5
            if (!$column instanceof ColumnAnnotation) {
124
                /** @var string $columnName */
125 5
                $columnName = $fieldName;
126
127 5
                if (is_string($column)) {
128 5
                    $columnName = $column;
129
                }
130
131 5
                $column = new ColumnAnnotation();
132 5
                $column->name = $columnName;
133 5
                $column->type = 'string';
134 5
                $column->length = 255;
135 5
                $column->precision = 10;
136 5
                $column->nullable = $annotation->nullable;
137
            }
138
139 5
            $dbalColumn = new DBALColumn(
140 5
                (string) $column->name,
141 5
                Type::getType($column->type),
142
                [
143 5
                    'notnull'   => !$column->nullable,
144 5
                    'length'    => $column->length,
145 5
                    'precision' => $column->precision,
146 5
                    'scale'     => $column->scale,
147
                ]
148
            );
149
150
            /** @var array<MappingInterface>*/
151 5
            $choiceMappings = array();
152
153 5
            foreach ($annotation->choices as $determinator => $choiceAnnotation) {
154
                /** @var ?MappingInterface $choiceMapping */
155 4
                $choiceMapping = $this->convertAnnotationToMapping(
156
                    $choiceAnnotation,
157
                    $fieldName,
158
                    $className
159
                );
160
161 4
                if ($choiceMapping instanceof MappingInterface) {
162 4
                    $choiceMappings[$determinator] = $choiceMapping;
163
164
                } else {
165
                    throw new InvalidMappingException(sprintf(
166
                        "Invalid mapping on entity '%s' in field '%s' of choice-option '%s'!",
167
                        $className,
168
                        $fieldName,
169
                        $determinator
170
                    ));
171
                }
172
            }
173
174 5
            $fieldMapping = new ChoiceMapping(
175
                $dbalColumn,
176
                $choiceMappings,
177 5
                sprintf(
178
                    "in entity '%s' on field '%s'",
179
                    $className,
180
                    $fieldName
181
                )
182
            );
183
184 7
        } elseif ($annotation instanceof RDMObject) {
185
            /** @var array<MappingInterface> $subFieldMappings */
186 2
            $subFieldMappings = array();
187
188
            /** @var null|CallDefinitionInterface $factory */
189 2
            $factory = null;
190
191
            /** @var null|CallDefinitionInterface $serializer */
192 2
            $serializer = null;
193
194 2
            foreach ($annotation->fields as $subFieldName => $subFieldAnnotation) {
195
                /** @var object $fieldAnnotation */
196
197 2
                $subFieldMappings[$subFieldName] = $this->convertAnnotationToMapping(
198
                    $subFieldAnnotation,
199 2
                    $fieldName . "->" . $subFieldName,
200
                    $className,
201
                    true
202
                );
203
            }
204
205
            /** @var class-string|null $objectMappingClassName */
206 2
            $objectMappingClassName = $annotation->{"class"};
207
208 2
            Assert::classExists($objectMappingClassName);
209
210 2
            $fieldMapping = new ObjectMapping(
211
                $objectMappingClassName,
212
                $subFieldMappings,
213
                null, # TODO: column
214 2
                sprintf(
215
                    "in entity '%s' on field '%s'",
216
                    $className,
217
                    $fieldName
218
                ),
219
                $factory,
220
                $serializer
221
            );
222
223 7
        } elseif ($annotation instanceof RDMArray) {
224
            /** @var array<MappingInterface> $entryMappings */
225 2
            $entryMappings = array();
226
227 2
            foreach ($annotation->entries as $key => $entryAnnotaton) {
228 2
                $entryMappings[$key] = $this->convertAnnotationToMapping(
229
                    $entryAnnotaton,
230 2
                    $fieldName . "->" . $key,
231
                    $className,
232
                    true
233
                );
234
            }
235
236 2
            $fieldMapping = new ArrayMapping(
237
                $entryMappings,
238 2
                sprintf(
239
                    "in entity '%s' on field '%s'",
240
                    $className,
241
                    $fieldName
242
                )
243
            );
244
245 7
        } elseif ($annotation instanceof ColumnAnnotation && $convertFieldsOnRootLevel) {
246
            /** @var DBALColumn $dbalColumn */
247 2
            $dbalColumn = new DBALColumn(
248 2
                (string) $annotation->name,
249 2
                Type::getType($annotation->type ?? 'string'),
250
                [
251 2
                    'notnull'   => !$annotation->nullable,
252 2
                    'length'    => $annotation->length,
253 2
                    'precision' => $annotation->precision ?? 0,
254 2
                    'scale'     => $annotation->scale,
255
                ]
256
            );
257
258 2
            $fieldMapping = new FieldMapping(
259
                $dbalColumn,
260 2
                sprintf(
261
                    "in entity '%s' on field '%s'",
262
                    $className,
263
                    $fieldName
264
                )
265
            );
266
        }
267
268 7
        return $fieldMapping;
269
    }
270
271
}
272