Passed
Push — main ( 1304a4...1c2c64 )
by Fractal
03:50
created

ParametersExtractor::mapEnum()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 1
nop 2
dl 0
loc 6
ccs 4
cts 4
cp 1
crap 3
rs 10
c 0
b 0
f 0
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(static 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(static 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
        $enumTypes = $props
43 19
            ->filter(static fn (Entry $propEntry) => !\is_array($propEntry->value) && ClassHelper::isEnum($propEntry->value))
44 19
            ->map(fn (Entry $propEntry) => $this->mapEnum($propEntry->value, $params->get($propEntry->key)->getOrElse(null)))
45 19
            ->toAssocArray()
46 19
            ->getOrElse([])
47
        ;
48
49 19
        $simpleTypes = $props
50 19
            ->filter(static fn (Entry $propEntry) => !\is_array($propEntry->value) && !ClassHelper::isNotBuiltinAndExists($propEntry->value))
51 19
            ->map(static fn (Entry $propEntry) => $params->get($propEntry->key)->getOrElse(null))
52 19
            ->toAssocArray()
53 19
            ->getOrElse([])
54
        ;
55
56 19
        return [...$complexTypes, ...$classTypes, ...$enumTypes, ...$simpleTypes];
57
    }
58
59 3
    private function mapEnum(string $enumClassName, mixed $value = null): ?\BackedEnum
0 ignored issues
show
Bug introduced by
The type BackedEnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
60
    {
61
        return match (true) {
62 3
            is_subclass_of($enumClassName, \IntBackedEnum::class) && \is_int($value) => $enumClassName::tryFrom($value),
0 ignored issues
show
Bug introduced by
The type IntBackedEnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
63 3
            is_subclass_of($enumClassName, \StringBackedEnum::class) && \is_string($value) => $enumClassName::tryFrom($value),
0 ignored issues
show
Bug introduced by
The type StringBackedEnum was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
64 3
            default => null,
65
        };
66
    }
67
68
    private function mapPropertiesForArray(Entry $propEntry, HashMap $parameters): array
69
    {
70
        return HashMap::collect($parameters->get($propEntry->key)->get())
71
            ->map(fn (Entry $paramEntry) => $propEntry->value[$paramEntry->key])
72
            ->map(fn (Entry $paramEntry) => $this->extract($paramEntry->value, $parameters->get($propEntry->key)->get()[$paramEntry->key] ?? []))
73
            ->toAssocArray()
74
            ->get()
75
        ;
76
    }
77
78 19
    private function getPropertyMapping(string $className, mixed $value): array
79
    {
80
        try {
81 19
            $properties = ArrayList::collect((new \ReflectionClass($className))->getProperties());
82
        } catch (\ReflectionException) {
83
            $properties = ArrayList::empty();
84
        }
85
86 19
        $complexTypes = $properties
87 19
            ->filter(fn (\ReflectionProperty $p) => ConstraintsHelper::hasArrayTypeAttribute($p))
88 19
            ->map(fn (\ReflectionProperty $p) => [SerializerHelper::getSerializedNameAttribute($p)->getSerializedName() => ArrayList::range(1, \count($value))->map(fn () => ConstraintsHelper::getArrayTypeAttribute($p)->typeName)->toArray()])
89 19
            ->reduce(fn (array $prev, array $next) => [...$prev, ...$next])
90 19
            ->getOrElse([])
91
        ;
92
93 19
        $simpleTypes = $properties
94 19
            ->filter(fn (\ReflectionProperty $p) => !ConstraintsHelper::hasArrayTypeAttribute($p))
95 19
            ->map(fn (\ReflectionProperty $p) => [SerializerHelper::getSerializedNameAttribute($p)->getSerializedName() => $p->getType()?->/** @scrutinizer ignore-call */ getName()])
96 19
            ->reduce(fn (array $prev, array $next) => [...$prev, ...$next])
97 19
            ->getOrElse([])
98
        ;
99
100 19
        return [...$complexTypes, ...$simpleTypes];
101
    }
102
}
103