Passed
Push — main ( c584c3...c783d7 )
by Fractal
16:29 queued 03:45
created

ParametersExtractor::extract()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 2
b 0
f 0
nc 1
nop 2
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
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
use FRZB\Component\RequestMapper\Helper\SerializerHelper;
14
15
#[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
    }
22
23 19
    private function mapProperties(array $properties, array $parameters): array
24
    {
25 19
        $params = HashMap::collect($parameters);
26 19
        $props = HashMap::collect($properties);
27
28 19
        $complexTypes = $props
29 19
            ->filter(fn (Entry $propEntry) => \is_array($propEntry->value))
30 19
            ->map(fn (Entry $propEntry) => $this->mapPropertiesForArray($propEntry, $params))
31 19
            ->toAssocArray()
32 19
            ->getOrElse([])
33
        ;
34
35 19
        $classTypes = $props
36 19
            ->filter(fn (Entry $propEntry) => !\is_array($propEntry->value) && ClassHelper::isNotBuiltinAndExists($propEntry->value))
37 19
            ->map(fn (Entry $propEntry) => $this->extract($propEntry->value, $params->get($propEntry->key)->getOrElse([])))
38 19
            ->toAssocArray()
39 19
            ->getOrElse([])
40
        ;
41
42 19
        $simpleTypes = $props
43 19
            ->filter(fn (Entry $propEntry) => !\is_array($propEntry->value) && !ClassHelper::isNotBuiltinAndExists($propEntry->value))
44 19
            ->map(fn (Entry $propEntry) => $params->get($propEntry->key)->getOrElse(null))
45 19
            ->toAssocArray()
46 19
            ->getOrElse([])
47
        ;
48
49 19
        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 19
    private function getPropertyMapping(string $className, mixed $value): array
63
    {
64
        try {
65 19
            $properties = ArrayList::collect((new \ReflectionClass($className))->getProperties());
66
        } catch (\ReflectionException) {
67
            $properties = ArrayList::empty();
68
        }
69
70 19
        $complexTypes = $properties
71 19
            ->filter(fn (\ReflectionProperty $p) => ConstraintsHelper::hasArrayTypeAttribute($p))
72 19
            ->map(fn (\ReflectionProperty $p) => [SerializerHelper::getSerializedNameAttribute($p)->getSerializedName() => ArrayList::range(1, \count($value))->map(fn () => ConstraintsHelper::getArrayTypeAttribute($p)->typeName)->toArray()])
73 19
            ->reduce(fn (array $prev, array $next) => [...$prev, ...$next])
74 19
            ->getOrElse([])
75
        ;
76
77 19
        $simpleTypes = $properties
78 19
            ->filter(fn (\ReflectionProperty $p) => !ConstraintsHelper::hasArrayTypeAttribute($p))
79 19
            ->map(fn (\ReflectionProperty $p) => [SerializerHelper::getSerializedNameAttribute($p)->getSerializedName() => $p->getType()?->/** @scrutinizer ignore-call */ getName()])
80 19
            ->reduce(fn (array $prev, array $next) => [...$prev, ...$next])
81 19
            ->getOrElse([])
82
        ;
83
84 19
        return [...$complexTypes, ...$simpleTypes];
85
    }
86
}
87