Passed
Push — master ( 356755...14835f )
by Gerrit
04:25
created

convertAnnotationToMapping()   D

Complexity

Conditions 13
Paths 11

Size

Total Lines 166
Code Lines 104

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 94
CRAP Score 13.0114

Importance

Changes 0
Metric Value
dl 0
loc 166
ccs 94
cts 98
cp 0.9592
rs 4.9922
c 0
b 0
f 0
cc 13
eloc 104
nc 11
nop 4
crap 13.0114

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