Completed
Push — develop ( 391d43...2463ed )
by Bastian
10s
created

DocumentMap::processDocument()   F

Complexity

Conditions 26
Paths 900

Size

Total Lines 94
Code Lines 70

Duplication

Lines 32
Ratio 34.04 %

Code Coverage

Tests 65
CRAP Score 26
Metric Value
dl 32
loc 94
ccs 65
cts 65
cp 1
rs 2.2136
cc 26
eloc 70
nc 900
nop 4
crap 26

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
 * DocumentMap class file
4
 */
5
6
namespace Graviton\DocumentBundle\DependencyInjection\Compiler\Utils;
7
8
use Symfony\Component\Finder\Finder;
9
10
/**
11
 * Document map
12
 *
13
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
14
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
15
 * @link     http://swisscom.ch
16
 */
17
class DocumentMap
18
{
19
    /**
20
     * @var array
21
     */
22
    private $mappings = [];
23
    /**
24
     * @var Document[]
25
     */
26
    private $documents = [];
27
28
    /**
29
     * Constructor
30
     *
31
     * @param Finder $doctrineFinder   Doctrine mapping finder
32
     * @param Finder $serializerFinder Serializer mapping finder
33
     * @param Finder $validationFinder Validation mapping finder
34
     */
35 8
    public function __construct(Finder $doctrineFinder, Finder $serializerFinder, Finder $validationFinder)
36
    {
37 8
        $doctrineMap = $this->loadDoctrineClassMap($doctrineFinder);
38 8
        $serializerMap = $this->loadSerializerClassMap($serializerFinder);
39 8
        $validationMap = $this->loadValidationClassMap($validationFinder);
40
41 8
        foreach ($doctrineMap as $className => $doctrineMapping) {
42 8
            $this->mappings[$className] = [
43 8
                'doctrine'   => $doctrineMap[$className],
44 8
                'serializer' => isset($serializerMap[$className]) ? $serializerMap[$className] : null,
45 8
                'validation' => isset($validationMap[$className]) ? $validationMap[$className] : null,
46
            ];
47
        }
48 8
    }
49
50
    /**
51
     * Get document
52
     *
53
     * @param string $className Document class
54
     * @return Document
55
     */
56 8
    public function getDocument($className)
57
    {
58 8
        if (isset($this->documents[$className])) {
59 8
            return $this->documents[$className];
60
        }
61 8
        if (!isset($this->mappings[$className])) {
62
            throw new \InvalidArgumentException(sprintf('No XML mapping found for document "%s"', $className));
63
        }
64
65 8
        return $this->documents[$className] = $this->processDocument(
66
            $className,
67 8
            $this->mappings[$className]['doctrine'],
68 8
            $this->mappings[$className]['serializer'],
69 8
            $this->mappings[$className]['validation']
70
        );
71
    }
72
73
    /**
74
     * Get all documents
75
     *
76
     * @return Document[]
77
     */
78 6
    public function getDocuments()
79
    {
80 6
        return array_map([$this, 'getDocument'], array_keys($this->mappings));
81
    }
82
83
    /**
84
     * Process document
85
     *
86
     * @param string      $className         Class name
87
     * @param \DOMElement $doctrineMapping   Doctrine XML mapping
88
     * @param \DOMElement $serializerMapping Serializer XML mapping
89
     * @param \DOMElement $validationMapping Validation XML mapping
90
     * @return Document
91
     */
92 8
    private function processDocument(
93
        $className,
94
        \DOMElement $doctrineMapping,
95
        \DOMElement $serializerMapping = null,
96
        \DOMElement $validationMapping = null
97
    ) {
98 8
        if ($serializerMapping === null) {
99 2
            $serializerFields = [];
100
        } else {
101 8
            $serializerFields = array_reduce(
102 8
                $this->getSerializerFields($serializerMapping),
103
                function (array $fields, array $field) {
104 8
                    $fields[$field['fieldName']] = $field;
105 8
                    return $fields;
106 8
                },
107 8
                []
108
            );
109
        }
110
111 8
        if ($validationMapping === null) {
112 2
            $validationFields = [];
113
        } else {
114 8
            $validationFields = array_reduce(
115 8
                $this->getValidationFields($validationMapping),
116
                function (array $fields, array $field) {
117 5
                    $fields[$field['fieldName']] = $field;
118 5
                    return $fields;
119 8
                },
120 8
                []
121
            );
122
        }
123
124 8
        $fields = [];
125 8
        foreach ($this->getDoctrineFields($doctrineMapping) as $doctrineField) {
126 8
            $serializerField = isset($serializerFields[$doctrineField['name']]) ?
127 8
                $serializerFields[$doctrineField['name']] :
128 8
                null;
129 8
            $validationField = isset($validationFields[$doctrineField['name']]) ?
130 5
                $validationFields[$doctrineField['name']] :
131 8
                null;
132
133 8
            if ($doctrineField['type'] === 'collection') {
134 2
                $fields[] = new ArrayField(
135 2
                    $serializerField === null ? 'array<string>' : $serializerField['fieldType'],
136 2
                    $doctrineField['name'],
137 2
                    $serializerField === null ? $doctrineField['name'] : $serializerField['exposedName'],
138 2
                    $serializerField === null ? false : $serializerField['readOnly'],
139 2
                    $validationField === null ? false : $validationField['required']
140
                );
141
            } else {
142 8
                $fields[] = new Field(
143 8
                    $doctrineField['type'],
144 8
                    $doctrineField['name'],
145 8
                    $serializerField === null ? $doctrineField['name'] : $serializerField['exposedName'],
146 8
                    $serializerField === null ? false : $serializerField['readOnly'],
147 8
                    $validationField === null ? false : $validationField['required']
148
                );
149
            }
150
        }
151 8 View Code Duplication
        foreach ($this->getDoctrineEmbedOneFields($doctrineMapping) as $doctrineField) {
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...
152 8
            $serializerField = isset($serializerFields[$doctrineField['name']]) ?
153 8
                $serializerFields[$doctrineField['name']] :
154 8
                null;
155 8
            $validationField = isset($validationFields[$doctrineField['name']]) ?
156 5
                $validationFields[$doctrineField['name']] :
157 8
                null;
158
159 8
            $fields[] = new EmbedOne(
160 8
                $this->getDocument($doctrineField['type']),
161 8
                $doctrineField['name'],
162 8
                $serializerField === null ? $doctrineField['name'] : $serializerField['exposedName'],
163 8
                $serializerField === null ? false : $serializerField['readOnly'],
164 8
                $validationField === null ? false : $validationField['required']
165
            );
166
        }
167 8 View Code Duplication
        foreach ($this->getDoctrineEmbedManyFields($doctrineMapping) as $doctrineField) {
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...
168 8
            $serializerField = isset($serializerFields[$doctrineField['name']]) ?
169 8
                $serializerFields[$doctrineField['name']] :
170 8
                null;
171 8
            $validationField = isset($validationFields[$doctrineField['name']]) ?
172 2
                $validationFields[$doctrineField['name']] :
173 8
                null;
174
175 8
            $fields[] = new EmbedMany(
176 8
                $this->getDocument($doctrineField['type']),
177 8
                $doctrineField['name'],
178 8
                $serializerField === null ? $doctrineField['name'] : $serializerField['exposedName'],
179 8
                $serializerField === null ? false : $serializerField['readOnly'],
180 8
                $validationField === null ? false : $validationField['required']
181
            );
182
        }
183
184 8
        return new Document($className, $fields);
185
    }
186
187
    /**
188
     * Load doctrine class map
189
     *
190
     * @param Finder $finder Mapping finder
191
     * @return array
192
     */
193 8 View Code Duplication
    private function loadDoctrineClassMap(Finder $finder)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
194
    {
195 8
        $classMap = [];
196 8
        foreach ($finder as $file) {
197 8
            $document = new \DOMDocument();
198 8
            $document->load($file);
199
200 8
            $xpath = new \DOMXPath($document);
201 8
            $xpath->registerNamespace('doctrine', 'http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping');
202
203 8
            $classMap = array_reduce(
204 8
                iterator_to_array($xpath->query('//*[self::doctrine:document or self::doctrine:embedded-document]')),
205
                function (array $classMap, \DOMElement $element) {
206 8
                    $classMap[$element->getAttribute('name')] = $element;
207 8
                    return $classMap;
208 8
                },
209
                $classMap
210
            );
211
        }
212
213 8
        return $classMap;
214
    }
215
216
    /**
217
     * Load serializer class map
218
     *
219
     * @param Finder $finder Mapping finder
220
     * @return array
221
     */
222 8 View Code Duplication
    private function loadSerializerClassMap(Finder $finder)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
223
    {
224 8
        $classMap = [];
225 8
        foreach ($finder as $file) {
226 8
            $document = new \DOMDocument();
227 8
            $document->load($file);
228
229 8
            $xpath = new \DOMXPath($document);
230
231 8
            $classMap = array_reduce(
232 8
                iterator_to_array($xpath->query('//class')),
233
                function (array $classMap, \DOMElement $element) {
234 8
                    $classMap[$element->getAttribute('name')] = $element;
235 8
                    return $classMap;
236 8
                },
237
                $classMap
238
            );
239
        }
240
241 8
        return $classMap;
242
    }
243
244
    /**
245
     * Load validation class map
246
     *
247
     * @param Finder $finder Mapping finder
248
     * @return array
249
     */
250 8 View Code Duplication
    private function loadValidationClassMap(Finder $finder)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
251
    {
252 8
        $classMap = [];
253 8
        foreach ($finder as $file) {
254 8
            $document = new \DOMDocument();
255 8
            $document->load($file);
256
257 8
            $xpath = new \DOMXPath($document);
258 8
            $xpath->registerNamespace('constraint', 'http://symfony.com/schema/dic/constraint-mapping');
259
260 8
            $classMap = array_reduce(
261 8
                iterator_to_array($xpath->query('//constraint:class')),
262
                function (array $classMap, \DOMElement $element) {
263 8
                    $classMap[$element->getAttribute('name')] = $element;
264 8
                    return $classMap;
265 8
                },
266
                $classMap
267
            );
268
        }
269
270 8
        return $classMap;
271
    }
272
273
    /**
274
     * Get serializer fields
275
     *
276
     * @param \DOMElement $mapping Serializer XML mapping
277
     * @return array
278
     */
279 8
    private function getSerializerFields(\DOMElement $mapping)
280
    {
281 8
        $xpath = new \DOMXPath($mapping->ownerDocument);
282
283 8
        return array_map(
284
            function (\DOMElement $element) {
285
                return [
286 8
                    'fieldName'   => $element->getAttribute('name'),
287 8
                    'fieldType'   => $this->getSerializerFieldType($element),
288 8
                    'exposedName' => $element->getAttribute('serialized-name') ?: $element->getAttribute('name'),
289 8
                    'readOnly'    => $element->getAttribute('read-only') === 'true',
290
                ];
291 8
            },
292 8
            iterator_to_array($xpath->query('property', $mapping))
293
        );
294
    }
295
296
    /**
297
     * Get serializer field type
298
     *
299
     * @param \DOMElement $field Field node
300
     * @return string|null
301
     */
302 8
    private function getSerializerFieldType(\DOMElement $field)
303
    {
304 8
        if ($field->getAttribute('type')) {
305 8
            return $field->getAttribute('type');
306
        }
307
308 2
        $xpath = new \DOMXPath($field->ownerDocument);
309
310 2
        $type = $xpath->query('type', $field)->item(0);
311 2
        return $type === null ? null : $type->nodeValue;
312
    }
313
314
    /**
315
     * Get validation fields
316
     *
317
     * @param \DOMElement $mapping Validation XML mapping
318
     * @return array
319
     */
320 8
    private function getValidationFields(\DOMElement $mapping)
321
    {
322 8
        $xpath = new \DOMXPath($mapping->ownerDocument);
323 8
        $xpath->registerNamespace('constraint', 'http://symfony.com/schema/dic/constraint-mapping');
324
325 8
        return array_map(
326
            function (\DOMElement $element) use ($xpath) {
327 5
                $constraints = $xpath->query('constraint:constraint[@name="NotBlank" or @name="NotNull"]', $element);
328
                return [
329 5
                    'fieldName' => $element->getAttribute('name'),
330 5
                    'required'  => $constraints->length > 0,
331
                ];
332 8
            },
333 8
            iterator_to_array($xpath->query('constraint:property', $mapping))
334
        );
335
    }
336
337
    /**
338
     * Get doctrine document fields
339
     *
340
     * @param \DOMElement $mapping Doctrine XML mapping
341
     * @return array
342
     */
343 8 View Code Duplication
    private function getDoctrineFields(\DOMElement $mapping)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
344
    {
345 8
        $xpath = new \DOMXPath($mapping->ownerDocument);
346 8
        $xpath->registerNamespace('doctrine', 'http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping');
347
348 8
        return array_map(
349
            function (\DOMElement $element) {
350
                return [
351 8
                    'name' => $element->getAttribute('fieldName'),
352 8
                    'type' => $element->getAttribute('type'),
353
                ];
354 8
            },
355 8
            iterator_to_array($xpath->query('doctrine:field', $mapping))
356
        );
357
    }
358
359
    /**
360
     * Get doctrine document embed-one fields
361
     *
362
     * @param \DOMElement $mapping Doctrine XML mapping
363
     * @return array
364
     */
365 8 View Code Duplication
    private function getDoctrineEmbedOneFields(\DOMElement $mapping)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
366
    {
367 8
        $xpath = new \DOMXPath($mapping->ownerDocument);
368 8
        $xpath->registerNamespace('doctrine', 'http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping');
369
370 8
        return array_map(
371
            function (\DOMElement $element) {
372
                return [
373 8
                    'name' => $element->getAttribute('field'),
374 8
                    'type' => $element->getAttribute('target-document'),
375
                ];
376 8
            },
377 8
            iterator_to_array($xpath->query('*[self::doctrine:embed-one or self::doctrine:reference-one]', $mapping))
378
        );
379
    }
380
381
    /**
382
     * Get doctrine document embed-many fields
383
     *
384
     * @param \DOMElement $mapping Doctrine XML mapping
385
     * @return array
386
     */
387 8 View Code Duplication
    private function getDoctrineEmbedManyFields(\DOMElement $mapping)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
388
    {
389 8
        $xpath = new \DOMXPath($mapping->ownerDocument);
390 8
        $xpath->registerNamespace('doctrine', 'http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping');
391
392 8
        return array_map(
393 8
            function (\DOMElement $element) {
394
                return [
395 8
                    'name' => $element->getAttribute('field'),
396 8
                    'type' => $element->getAttribute('target-document'),
397
                ];
398 8
            },
399 8
            iterator_to_array($xpath->query('*[self::doctrine:embed-many or self::doctrine:reference-many]', $mapping))
400
        );
401
    }
402
}
403