Test Setup Failed
Push — main ( c2f1dd...c584c3 )
by Fractal
11:13
created

ParametersExtractor::mapPropertiesForArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 5
c 0
b 0
f 0
nc 1
nop 2
dl 0
loc 7
rs 10
ccs 0
cts 0
cp 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace FRZB\Component\RequestMapper\Extractor;
6
7
use Fp\Collections\ArrayList;
8
use Fp\Collections\Entry;
9
use Fp\Collections\HashMap;
10
use FRZB\Component\DependencyInjection\Attribute\AsService;
11
use FRZB\Component\RequestMapper\Helper\ClassHelper;
12
use FRZB\Component\RequestMapper\Helper\ConstraintsHelper;
13 19
use FRZB\Component\RequestMapper\Helper\SerializerHelper;
14
15 19
#[AsService]
16
class ParametersExtractor
17
{
18 19
    public function extract(string $class, array $parameters): array
19
    {
20 19
        return [...$parameters, ...$this->mapProperties($this->getPropertyMapping($class, $parameters), $parameters)];
21 19
    }
22 19
23
    private function mapProperties(array $properties, array $parameters): array
24
    {
25 19
        $params = HashMap::collect($parameters);
26
        $props = HashMap::collect($properties);
27
28
        $complexTypes = $props
29
            ->filter(fn (Entry $propEntry) => is_array($propEntry->value))
30
            ->map(fn (Entry $propEntry) => $this->mapPropertiesForArray($propEntry, $params))
31
            ->toAssocArray()
32
            ->getOrElse([])
33
        ;
34
35
        $classTypes = $props
36
            ->filter(fn (Entry $propEntry) => !is_array($propEntry->value) && ClassHelper::isNotBuiltinAndExists($propEntry->value))
37
            ->map(fn (Entry $propEntry) => $this->extract($propEntry->value, $params->get($propEntry->key)->getOrElse([])))
38
            ->toAssocArray()
39
            ->getOrElse([])
40
        ;
41
42
        $simpleTypes = $props
43
            ->filter(fn (Entry $propEntry) => !is_array($propEntry->value) && !ClassHelper::isNotBuiltinAndExists($propEntry->value))
44
            ->map(fn (Entry $propEntry) => $params->get($propEntry->key)->getOrElse(null))
45
            ->toAssocArray()
46
            ->getOrElse([])
47
        ;
48
49
        return [...$complexTypes, ...$classTypes, ...$simpleTypes];
50
    }
51
52
    private function mapPropertiesForArray(Entry $propEntry, HashMap $parameters): array
53
    {
54
        return HashMap::collect($parameters->get($propEntry->key)->get())
55
            ->map(fn (Entry $paramEntry) => $propEntry->value[$paramEntry->key])
56
            ->map(fn (Entry $paramEntry) => $this->extract($paramEntry->value, $parameters->get($propEntry->key)->get()[$paramEntry->key] ?? []))
57
            ->toAssocArray()
58
            ->get()
59
            ;
60
    }
61
62
    private function getPropertyMapping(string $className, mixed $value)
63
    {
64
        try {
65
            $properties = ArrayList::collect((new \ReflectionClass($className))->getProperties());
66
        } catch (\ReflectionException) {
67
            $properties = ArrayList::empty();
68
        }
69
70
        $complexTypes = $properties
71
            ->filter(fn (\ReflectionProperty $p) => ConstraintsHelper::hasArrayTypeAttribute($p))
72
            ->map(fn (\ReflectionProperty $p) => [SerializerHelper::getSerializedNameAttribute($p)->getSerializedName() => ArrayList::range(1, count($value))->map(fn () => ConstraintsHelper::getArrayTypeAttribute($p)->typeName)->toArray()])
73
            ->reduce(fn (array $prev, array $next) => [...$prev, ...$next])
74
            ->getOrElse([])
75
        ;
76
77
        $simpleTypes = $properties
78
            ->filter(fn (\ReflectionProperty $p) => !ConstraintsHelper::hasArrayTypeAttribute($p))
79
            ->map(fn (\ReflectionProperty $p) => [SerializerHelper::getSerializedNameAttribute($p)->getSerializedName() => $p->getType()?->/** @scrutinizer ignore-call */ getName()])
80
            ->reduce(fn (array $prev, array $next) => [...$prev, ...$next])
81
            ->getOrElse([])
82
        ;
83
84
        return [...$complexTypes, ...$simpleTypes];
85
    }
86
}
87