Passed
Push — scalar-object ( c5e998 )
by Akihito
03:09
created

ScalarParam::getProps()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 7
c 1
b 0
f 0
nc 3
nop 3
dl 0
loc 15
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BEAR\Resource;
6
7
use BackedEnum;
8
use BEAR\Resource\Exception\ParameterEnumTypeException;
9
use BEAR\Resource\Exception\ParameterException;
10
use BEAR\Resource\Exception\ParameterInvalidEnumException;
11
use Ray\Di\InjectorInterface;
12
use ReflectionEnum;
0 ignored issues
show
Bug introduced by
The type ReflectionEnum 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...
13
use ReflectionNamedType;
14
use ReflectionParameter;
15
use UnitEnum;
16
17
use function assert;
18
use function class_exists;
19
use function enum_exists;
0 ignored issues
show
introduced by
The function enum_exists was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
20
use function is_a;
21
use function is_int;
22
use function is_string;
23
use function ltrim;
24
use function preg_replace;
25
use function strtolower;
26
27
final class ScalarParam implements ParamInterface
28
{
29
    private readonly string $type;
30
    private readonly bool $isDefaultAvailable;
31
    private readonly mixed $defaultValue; // @phpstan-ignore-line
32
33
    public function __construct(
34
        ReflectionNamedType $type,
35
        ReflectionParameter $parameter,
36
    ) {
37
        $this->type = $type->getName();
0 ignored issues
show
Bug introduced by
The property type is declared read-only in BEAR\Resource\ScalarParam.
Loading history...
38
        $this->isDefaultAvailable = $parameter->isDefaultValueAvailable();
0 ignored issues
show
Bug introduced by
The property isDefaultAvailable is declared read-only in BEAR\Resource\ScalarParam.
Loading history...
39
        if (! $this->isDefaultAvailable) {
40
            return;
41
        }
42
43
        $this->defaultValue = $parameter->getDefaultValue();
0 ignored issues
show
Bug introduced by
The property defaultValue is declared read-only in BEAR\Resource\ScalarParam.
Loading history...
44
    }
45
46
    /**
47
     * {@inheritDoc}
48
     */
49
    public function __invoke(string $varName, array $query, InjectorInterface $injector)
50
    {
51
        try {
52
            /** @psalm-suppress MixedAssignment */
53
            $props = $this->getProps($varName, $query, $injector);
54
        } catch (ParameterException $e) {
55
            if ($this->isDefaultAvailable) {
56
                return $this->defaultValue;
57
            }
58
59
            throw $e;
60
        }
61
62
        assert(class_exists($this->type));
63
64
        return new $this->type($props);
65
    }
66
67
    /** @param array<string, mixed> $query */
68
    private function getProps(string $varName, array $query, InjectorInterface $injector): mixed
69
    {
70
        if (isset($query[$varName])) {
71
            return $query[$varName];
72
        }
73
74
        // try camelCase variable name
75
        $snakeName = ltrim(strtolower((string) preg_replace('/[A-Z]/', '_\0', $varName)), '_');
76
        if (isset($query[$snakeName])) {
77
            return $query[$snakeName];
78
        }
79
80
        unset($injector);
81
82
        throw new ParameterException($varName);
83
    }
84
85
    /**
86
     * @param class-string $type
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string.
Loading history...
87
     *
88
     * @psalm-suppress MixedArgument
89
     */
90
    private function enum(string $type, mixed $props, string $varName): mixed
91
    {
92
        /** @var class-string<UnitEnum> $type */
93
        $refEnum = new ReflectionEnum($type);
94
        assert(enum_exists($type));
0 ignored issues
show
Bug introduced by
The function enum_exists was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

94
        assert(/** @scrutinizer ignore-call */ enum_exists($type));
Loading history...
95
96
        if (! $refEnum->isBacked()) {
97
            throw new NotBackedEnumException($type);
98
        }
99
100
        assert(is_a($type, BackedEnum::class, true));
101
        if (! (is_int($props) || is_string($props))) {
102
            throw new ParameterEnumTypeException($varName);
103
        }
104
105
        /**  @psalm-suppress MixedAssignment */
106
        $value = $type::tryFrom($props);
107
        if ($value === null) {
108
            throw new ParameterInvalidEnumException($varName);
109
        }
110
111
        return $value;
112
    }
113
}
114