Completed
Push — feature/other-validation ( 582c96...3c7e86 )
by Narcotic
109:38 queued 43:32
created

DocumentMap   C

Complexity

Total Complexity 71

Size/Duplication

Total Lines 518
Duplicated Lines 25.1 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 99.52%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 71
c 1
b 0
f 0
lcom 1
cbo 6
dl 130
loc 518
rs 5.5904
ccs 207
cts 208
cp 0.9952

16 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 20 5
A getDocument() 0 17 3
A getDocuments() 0 4 1
F processDocument() 0 107 31
A loadDoctrineClassMap() 22 22 2
A loadSerializerClassMap() 21 21 2
B loadSchemaClassMap() 9 23 6
A loadValidationClassMap() 22 22 2
A getSerializerFields() 0 17 2
A getSerializerFieldType() 0 11 3
A getValidationFields() 0 16 1
A getDoctrineFields() 15 15 1
A getDoctrineEmbedOneFields() 15 15 1
A getDoctrineEmbedManyFields() 15 15 1
C getFieldNamesFlat() 11 46 8
A getFlatFieldCheckCallback() 0 8 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like DocumentMap often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use DocumentMap, and based on these observations, apply Extract Interface, too.

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
     * @param Finder $schemaFinder     Schema finder
35 14
     */
36
    public function __construct(
37 14
        Finder $doctrineFinder,
38 14
        Finder $serializerFinder,
39 14
        Finder $validationFinder,
40
        Finder $schemaFinder
41 14
    ) {
42 14
        $doctrineMap = $this->loadDoctrineClassMap($doctrineFinder);
43 14
        $serializerMap = $this->loadSerializerClassMap($serializerFinder);
44 14
        $validationMap = $this->loadValidationClassMap($validationFinder);
45 14
        $schemaMap = $this->loadSchemaClassMap($schemaFinder);
46
47 7
        foreach ($doctrineMap as $className => $doctrineMapping) {
48 14
            $this->mappings[$className] = [
49
                'doctrine'   => $doctrineMap[$className],
50
                'serializer' => isset($serializerMap[$className]) ? $serializerMap[$className] : null,
51
                'validation' => isset($validationMap[$className]) ? $validationMap[$className] : null,
52
                'schema' => isset($schemaMap[$className]) ? $schemaMap[$className] : null,
53
            ];
54
        }
55
    }
56 14
57
    /**
58 14
     * Get document
59 14
     *
60
     * @param string $className Document class
61 14
     * @return Document
62
     */
63
    public function getDocument($className)
64
    {
65 14
        if (isset($this->documents[$className])) {
66 7
            return $this->documents[$className];
67 14
        }
68 14
        if (!isset($this->mappings[$className])) {
69 14
            throw new \InvalidArgumentException(sprintf('No XML mapping found for document "%s"', $className));
70 7
        }
71
72
        return $this->documents[$className] = $this->processDocument(
73
            $className,
74
            $this->mappings[$className]['doctrine'],
75
            $this->mappings[$className]['serializer'],
76
            $this->mappings[$className]['validation'],
77
            $this->mappings[$className]['schema']
78 10
        );
79
    }
80 10
81
    /**
82
     * Get all documents
83
     *
84
     * @return Document[]
85
     */
86
    public function getDocuments()
87
    {
88
        return array_map([$this, 'getDocument'], array_keys($this->mappings));
89
    }
90
91
    /**
92 14
     * Process document
93
     *
94
     * @param string      $className         Class name
95
     * @param \DOMElement $doctrineMapping   Doctrine XML mapping
96
     * @param \DOMElement $serializerMapping Serializer XML mapping
0 ignored issues
show
Documentation introduced by
Should the type for parameter $serializerMapping not be null|\DOMElement?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
97
     * @param \DOMElement $validationMapping Validation XML mapping
0 ignored issues
show
Documentation introduced by
Should the type for parameter $validationMapping not be null|\DOMElement?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
98 14
     * @param array       $schemaMapping     Schema mapping
0 ignored issues
show
Documentation introduced by
Should the type for parameter $schemaMapping not be null|array? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
99 2
     *
100 1
     * @return Document
101 14
     */
102 14
    private function processDocument(
103
        $className,
104 14
        \DOMElement $doctrineMapping,
105 14
        \DOMElement $serializerMapping = null,
106 14
        \DOMElement $validationMapping = null,
107 14
        array $schemaMapping = null
108 7
    ) {
109
        if ($serializerMapping === null) {
110
            $serializerFields = [];
111 14
        } else {
112 2
            $serializerFields = array_reduce(
113 1
                $this->getSerializerFields($serializerMapping),
114 14
                function (array $fields, array $field) {
115 14
                    $fields[$field['fieldName']] = $field;
116
                    return $fields;
117 8
                },
118 8
                []
119 14
            );
120 14
        }
121 7
122
        if ($validationMapping === null) {
123
            $validationFields = [];
124 14
        } else {
125 14
            $validationFields = array_reduce(
126 14
                $this->getValidationFields($validationMapping),
127 14
                function (array $fields, array $field) {
128 14
                    $fields[$field['fieldName']] = $field;
129 14
                    return $fields;
130 11
                },
131 14
                []
132
            );
133 14
        }
134 2
135 2
        if ($schemaMapping === null) {
136 2
            $schemaFields = [];
137 2
        } else {
138 2
            $schemaFields = $schemaMapping;
139 2
        }
140 2
141 1
        $fields = [];
142 1
        foreach ($this->getDoctrineFields($doctrineMapping) as $doctrineField) {
143 14
            $serializerField = isset($serializerFields[$doctrineField['name']]) ?
144 14
                $serializerFields[$doctrineField['name']] :
145 14
                null;
146 14
            $validationField = isset($validationFields[$doctrineField['name']]) ?
147 14
                $validationFields[$doctrineField['name']] :
148 14
                null;
149 14
            $schemaField = isset($schemaFields[$doctrineField['name']]) ?
150 7
                $schemaFields[$doctrineField['name']] :
151
                null;
152 7
153 14
            if ($doctrineField['type'] === 'collection') {
154 14
                $fields[] = new ArrayField(
155 14
                    $serializerField === null ? 'array<string>' : $serializerField['fieldType'],
156 14
                    $doctrineField['name'],
157 14
                    $serializerField === null ? $doctrineField['name'] : $serializerField['exposedName'],
158 11
                    !isset($schemaField['readOnly']) ? false : $schemaField['readOnly'],
159 14
                    $validationField === null ? false : $validationField['required'],
160
                    $serializerField === null ? false : $serializerField['searchable']
0 ignored issues
show
Unused Code introduced by
The call to ArrayField::__construct() has too many arguments starting with $serializerField === nul...izerField['searchable'].

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
161 14
                );
162 14
            } else {
163 14
                $fields[] = new Field(
164 14
                    $doctrineField['type'],
165 14
                    $doctrineField['name'],
166 14
                    $serializerField === null ? $doctrineField['name'] : $serializerField['exposedName'],
167 14
                    !isset($schemaField['readOnly']) ? false : $schemaField['readOnly'],
168 7
                    $validationField === null ? false : $validationField['required'],
169 7
                    $serializerField === null ? false : $serializerField['searchable']
170 14
                );
171 14
            }
172 14
        }
173 14
        foreach ($this->getDoctrineEmbedOneFields($doctrineMapping) as $doctrineField) {
174 14
            $serializerField = isset($serializerFields[$doctrineField['name']]) ?
175 8
                $serializerFields[$doctrineField['name']] :
176 14
                null;
177
            $validationField = isset($validationFields[$doctrineField['name']]) ?
178 14
                $validationFields[$doctrineField['name']] :
179 14
                null;
180 14
181 14
            $fields[] = new EmbedOne(
182 14
                $this->getDocument($doctrineField['type']),
183 14
                $doctrineField['name'],
184 7
                $serializerField === null ? $doctrineField['name'] : $serializerField['exposedName'],
185 7
                !isset($schemaField['readOnly']) ? false : $schemaField['readOnly'],
186
                $validationField === null ? false : $validationField['required'],
187 14
                $serializerField === null ? false : $serializerField['searchable']
0 ignored issues
show
Unused Code introduced by
The call to EmbedOne::__construct() has too many arguments starting with $serializerField === nul...izerField['searchable'].

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
188
            );
189
        }
190
        foreach ($this->getDoctrineEmbedManyFields($doctrineMapping) as $doctrineField) {
191
            $serializerField = isset($serializerFields[$doctrineField['name']]) ?
192
                $serializerFields[$doctrineField['name']] :
193
                null;
194
            $validationField = isset($validationFields[$doctrineField['name']]) ?
195
                $validationFields[$doctrineField['name']] :
196 14
                null;
197
198 14
            $fields[] = new EmbedMany(
199 14
                $this->getDocument($doctrineField['type']),
200 14
                $doctrineField['name'],
201 14
                $serializerField === null ? $doctrineField['name'] : $serializerField['exposedName'],
202
                !isset($schemaField['readOnly']) ? false : $schemaField['readOnly'],
203 14
                $validationField === null ? false : $validationField['required']
204 14
            );
205
        }
206 14
207 14
        return new Document($className, $fields);
208
    }
209 14
210 14
    /**
211 14
     * Load doctrine class map
212
     *
213 7
     * @param Finder $finder Mapping finder
214 7
     * @return array
215
     */
216 14 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...
217
    {
218
        $classMap = [];
219
        foreach ($finder as $file) {
220
            $document = new \DOMDocument();
221
            $document->load($file);
222
223
            $xpath = new \DOMXPath($document);
224
            $xpath->registerNamespace('doctrine', 'http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping');
225 14
226
            $classMap = array_reduce(
227 14
                iterator_to_array($xpath->query('//*[self::doctrine:document or self::doctrine:embedded-document]')),
228 14
                function (array $classMap, \DOMElement $element) {
229 14
                    $classMap[$element->getAttribute('name')] = $element;
230 14
                    return $classMap;
231
                },
232 14
                $classMap
233
            );
234 14
        }
235 14
236
        return $classMap;
237 14
    }
238 14
239 14
    /**
240
     * Load serializer class map
241 7
     *
242 7
     * @param Finder $finder Mapping finder
243
     * @return array
244 14
     */
245 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...
246
    {
247
        $classMap = [];
248
        foreach ($finder as $file) {
249
            $document = new \DOMDocument();
250
            $document->load($file);
251
252
            $xpath = new \DOMXPath($document);
253 14
254
            $classMap = array_reduce(
255 14
                iterator_to_array($xpath->query('//class')),
256 14
                function (array $classMap, \DOMElement $element) {
257 14
                    $classMap[$element->getAttribute('name')] = $element;
258 14
                    return $classMap;
259
                },
260 14
                $classMap
261 14
            );
262
        }
263 14
264 14
        return $classMap;
265
    }
266 14
267 14
    /**
268 14
     * Load schema class map
269
     *
270 7
     * @param Finder $finder Mapping finder
271 7
     * @return array
272
     */
273 14
    private function loadSchemaClassMap(Finder $finder)
274
    {
275
        $classMap = [];
276
        foreach ($finder as $file) {
277
            $schema = json_decode(file_get_contents($file), true);
278
279
            if (!isset($schema['x-documentClass'])) {
280
                continue;
281
            }
282 14
283 View Code Duplication
            foreach ($schema['required'] as $field) {
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...
284 14
                $classMap[$schema['x-documentClass']][$field]['required'] = true;
285
            }
286 14 View Code Duplication
            foreach ($schema['searchable'] as $field) {
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...
287
                $classMap[$schema['x-documentClass']][$field]['searchable'] = true;
288
            }
289 14 View Code Duplication
            foreach ($schema['readOnlyFields'] as $field) {
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...
290 14
                $classMap[$schema['x-documentClass']][$field]['readOnly'] = true;
291 14
            }
292 14
        }
293 14
294 7
        return $classMap;
295 14
    }
296 14
297 7
    /**
298
     * Load validation class map
299
     *
300
     * @param Finder $finder Mapping finder
301
     * @return array
302
     */
303 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...
304
    {
305
        $classMap = [];
306 14
        foreach ($finder as $file) {
307
            $document = new \DOMDocument();
308 14
            $document->load($file);
309 14
310
            $xpath = new \DOMXPath($document);
311
            $xpath->registerNamespace('constraint', 'http://symfony.com/schema/dic/constraint-mapping');
312 2
313
            $classMap = array_reduce(
314 2
                iterator_to_array($xpath->query('//constraint:class')),
315 2
                function (array $classMap, \DOMElement $element) {
316
                    $classMap[$element->getAttribute('name')] = $element;
317
                    return $classMap;
318
                },
319
                $classMap
320
            );
321
        }
322
323
        return $classMap;
324 14
    }
325
326 14
    /**
327 14
     * Get serializer fields
328
     *
329 14
     * @param \DOMElement $mapping Serializer XML mapping
330
     * @return array
331 8
     */
332
    private function getSerializerFields(\DOMElement $mapping)
333 8
    {
334 8
        $xpath = new \DOMXPath($mapping->ownerDocument);
335 4
336 14
        return array_map(
337 14
            function (\DOMElement $element) {
338 7
                return [
339
                    'fieldName'   => $element->getAttribute('name'),
340
                    'fieldType'   => $this->getSerializerFieldType($element),
341
                    'exposedName' => $element->getAttribute('serialized-name') ?: $element->getAttribute('name'),
342
                    'readOnly'    => $element->getAttribute('read-only') === 'true',
343
                    'searchable'  => $element->getAttribute('searchable') === 'true',
344
                ];
345
            },
346
            iterator_to_array($xpath->query('property', $mapping))
347 14
        );
348
    }
349 14
350 14
    /**
351
     * Get serializer field type
352 14
     *
353
     * @param \DOMElement $field Field node
354
     * @return string|null
355 14
     */
356 14
    private function getSerializerFieldType(\DOMElement $field)
357 7
    {
358 14
        if ($field->getAttribute('type')) {
359 14
            return $field->getAttribute('type');
360 7
        }
361
362
        $xpath = new \DOMXPath($field->ownerDocument);
363
364
        $type = $xpath->query('type', $field)->item(0);
365
        return $type === null ? null : $type->nodeValue;
366
    }
367
368
    /**
369 14
     * Get validation fields
370
     *
371 14
     * @param \DOMElement $mapping Validation XML mapping
372 14
     * @return array
373
     */
374 14
    private function getValidationFields(\DOMElement $mapping)
375
    {
376
        $xpath = new \DOMXPath($mapping->ownerDocument);
377 14
        $xpath->registerNamespace('constraint', 'http://symfony.com/schema/dic/constraint-mapping');
378 14
379 7
        return array_map(
380 14
            function (\DOMElement $element) use ($xpath) {
381 14
                $constraints = $xpath->query('constraint:constraint[@name="NotBlank" or @name="NotNull"]', $element);
382 7
                return [
383
                    'fieldName' => $element->getAttribute('name'),
384
                    'required'  => $constraints->length > 0,
385
                ];
386
            },
387
            iterator_to_array($xpath->query('constraint:property', $mapping))
388
        );
389
    }
390
391 14
    /**
392
     * Get doctrine document fields
393 14
     *
394 14
     * @param \DOMElement $mapping Doctrine XML mapping
395
     * @return array
396 14
     */
397 14 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...
398
    {
399 14
        $xpath = new \DOMXPath($mapping->ownerDocument);
400 14
        $xpath->registerNamespace('doctrine', 'http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping');
401 7
402 14
        return array_map(
403 14
            function (\DOMElement $element) {
404 7
                return [
405
                    'name' => $element->getAttribute('fieldName'),
406
                    'type' => $element->getAttribute('type'),
407
                ];
408
            },
409
            iterator_to_array($xpath->query('doctrine:field', $mapping))
410
        );
411
    }
412
413
    /**
414
     * Get doctrine document embed-one fields
415
     *
416
     * @param \DOMElement $mapping Doctrine XML mapping
417
     * @return array
418
     */
419 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...
420
    {
421
        $xpath = new \DOMXPath($mapping->ownerDocument);
422
        $xpath->registerNamespace('doctrine', 'http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping');
423
424
        return array_map(
425
            function (\DOMElement $element) {
426
                return [
427
                    'name' => $element->getAttribute('field'),
428
                    'type' => $element->getAttribute('target-document'),
429
                ];
430
            },
431
            iterator_to_array($xpath->query('*[self::doctrine:embed-one or self::doctrine:reference-one]', $mapping))
432
        );
433
    }
434
435
    /**
436
     * Get doctrine document embed-many fields
437
     *
438
     * @param \DOMElement $mapping Doctrine XML mapping
439
     * @return array
440
     */
441 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...
442
    {
443
        $xpath = new \DOMXPath($mapping->ownerDocument);
444
        $xpath->registerNamespace('doctrine', 'http://doctrine-project.org/schemas/odm/doctrine-mongo-mapping');
445
446
        return array_map(
447
            function (\DOMElement $element) {
448
                return [
449
                    'name' => $element->getAttribute('field'),
450
                    'type' => $element->getAttribute('target-document'),
451
                ];
452
            },
453
            iterator_to_array($xpath->query('*[self::doctrine:embed-many or self::doctrine:reference-many]', $mapping))
454
        );
455
    }
456
457
    /**
458
     * Gets an array of all fields, flat with full internal name in dot notation as key and
459
     * the exposed field name as value. You can pass a callable to limit the fields return a subset of fields.
460
     * If the callback returns true, the field will be included in the output. You will get the field definition
461
     * passed to your callback.
462
     *
463
     * @param Document $document       The document
464
     * @param string   $documentPrefix Document field prefix
465
     * @param string   $exposedPrefix  Exposed field prefix
466
     * @param callable $callback       An optional callback where you can influence the number of fields returned
0 ignored issues
show
Documentation introduced by
Should the type for parameter $callback not be null|callable? Also, consider making the array more specific, something like array<String>, or String[].

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type array and suggests a stricter type like array<String>.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
467
     *
468
     * @return array
469
     */
470
    public function getFieldNamesFlat(
471
        Document $document,
472
        $documentPrefix = '',
473
        $exposedPrefix = '',
474
        callable $callback = null
475
    ) {
476
        $result = [];
477
        foreach ($document->getFields() as $field) {
478 View Code Duplication
            if ($this->getFlatFieldCheckCallback($field, $callback)) {
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...
479
                $result[$documentPrefix . $field->getFieldName()] = $exposedPrefix . $field->getExposedName();
480
            }
481
482
            if ($field instanceof ArrayField) {
483 View Code Duplication
                if ($this->getFlatFieldCheckCallback($field, $callback)) {
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...
484
                    $result[$documentPrefix . $field->getFieldName() . '.0'] =
485
                        $exposedPrefix . $field->getExposedName() . '.0';
486
                }
487
            } elseif ($field instanceof EmbedOne) {
488
                $result = array_merge(
489
                    $result,
490
                    $this->getFieldNamesFlat(
491
                        $field->getDocument(),
492
                        $documentPrefix.$field->getFieldName().'.',
493
                        $exposedPrefix.$field->getExposedName().'.',
494
                        $callback
495
                    )
496
                );
497
            } elseif ($field instanceof EmbedMany) {
498 View Code Duplication
                if ($this->getFlatFieldCheckCallback($field, $callback)) {
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...
499
                    $result[$documentPrefix . $field->getFieldName() . '.0'] =
500
                        $exposedPrefix . $field->getExposedName() . '.0';
501
                }
502
                $result = array_merge(
503
                    $result,
504
                    $this->getFieldNamesFlat(
505
                        $field->getDocument(),
506
                        $documentPrefix.$field->getFieldName().'.0.',
507
                        $exposedPrefix.$field->getExposedName().'.0.',
508
                        $callback
509
                    )
510
                );
511
            }
512
        }
513
514
        return $result;
515
    }
516
517
    /**
518
     * Simple function to check whether a given shall be returned in the output of getFieldNamesFlat
519
     * and the optional given callback there.
520
     *
521
     * @param AbstractField $field    field
522
     * @param callable|null $callback optional callback
523
     *
524
     * @return bool|mixed true if field should be returned, false otherwise
525
     */
526
    private function getFlatFieldCheckCallback($field, callable $callback = null)
527
    {
528
        if (!is_callable($callback)) {
529
            return true;
530
        }
531
532
        return call_user_func($callback, $field);
533
    }
534
}
535