Meta   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 91
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 38
dl 0
loc 91
rs 10
c 1
b 0
f 0
wmc 12

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getOptions() 0 14 3
A getUri() 0 10 1
A getParams() 0 17 3
A getAllows() 0 13 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BEAR\Resource;
6
7
use LogicException;
8
use ReflectionClass;
9
use ReflectionMethod;
10
11
use function array_shift;
12
use function class_exists;
13
use function explode;
14
use function implode;
15
use function str_starts_with;
16
use function strtolower;
17
use function substr;
18
19
final class Meta
20
{
21
    private const EXTRAS_VENDOR = 'vendor';
22
    private const EXTRAS_PACKAGE = 'package';
23
24
    /** @var string */
25
    public $uri;
26
27
    /** @var Options */
28
    public $options;
29
30
    /** @var array{vendor?: string, package?: string} */
31
    public $extras = [];
32
33
    /** @param class-string $class */
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...
34
    public function __construct(string $class)
35
    {
36
        $this->uri = $this->getUri($class);
37
        $this->options = $this->getOptions($class);
38
    }
39
40
    private function getUri(string $class): string
41
    {
42
        $classPath = explode('\\', $class);
43
        // $class
44
        $this->extras[self::EXTRAS_VENDOR] = array_shift($classPath); // @phpstan-ignore-line
45
        $this->extras[self::EXTRAS_PACKAGE] = array_shift($classPath); // @phpstan-ignore-line
46
        array_shift($classPath); // "/Resource/"
47
        $scheme = array_shift($classPath);
48
49
        return strtolower("{$scheme}://self/" . implode('/', $classPath));
50
    }
51
52
    /**
53
     * Return available resource request method
54
     */
55
    private function getOptions(string $class): Options
56
    {
57
        if (! class_exists($class)) {
58
            throw new LogicException(); // @codeCoverageIgnore
59
        }
60
61
        $ref = new ReflectionClass($class);
62
        $allows = $this->getAllows($ref->getMethods());
63
        $params = [];
64
        foreach ($allows as $method) {
65
            $params[] = $this->getParams($class, $method);
66
        }
67
68
        return new Options($allows, $params);
69
    }
70
71
    /**
72
     * @param ReflectionMethod[] $methods
73
     *
74
     * @return string[]
75
     * @psalm-return list<string>
76
     */
77
    private function getAllows(array $methods): array
78
    {
79
        $allows = [];
80
        foreach ($methods as $method) {
81
            $isRequestMethod = str_starts_with($method->name, 'on') && ! str_starts_with($method->name, 'onLink');
82
            if (! $isRequestMethod) {
83
                continue;
84
            }
85
86
            $allows[] = strtolower(substr($method->name, 2));
87
        }
88
89
        return $allows;
90
    }
91
92
    /** @param class-string $class */
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...
93
    private function getParams(string $class, string $method): Params
94
    {
95
        $refMethod = new ReflectionMethod($class, 'on' . $method);
96
        $parameters = $refMethod->getParameters();
97
        $optionalParams = $requiredParams = [];
98
        foreach ($parameters as $parameter) {
99
            $name = $parameter->name;
100
            if ($parameter->isOptional()) {
101
                $optionalParams[] = $name;
102
103
                continue;
104
            }
105
106
            $requiredParams[] = $name;
107
        }
108
109
        return new Params($method, $requiredParams, $optionalParams);
110
    }
111
}
112