Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
56 / 56 |
|
100.00% |
6 / 6 |
CRAP | |
100.00% |
1 / 1 |
Reflector | |
100.00% |
56 / 56 |
|
100.00% |
6 / 6 |
23 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getMethodRoutes | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
getObjectOrigins | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
4 | |||
getRoutes | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
6 | |||
getMethodRoutesNotFound | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
3 | |||
getRoutesNotFound | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
6 |
1 | <?php declare(strict_types=1); |
2 | /* |
3 | * This file is part of Aplus Framework Routing Library. |
4 | * |
5 | * (c) Natan Felles <natanfelles@gmail.com> |
6 | * |
7 | * For the full copyright and license information, please view the LICENSE |
8 | * file that was distributed with this source code. |
9 | */ |
10 | namespace Framework\Routing; |
11 | |
12 | use Framework\Routing\Attributes\Origin; |
13 | use Framework\Routing\Attributes\Route; |
14 | use Framework\Routing\Attributes\RouteNotFound; |
15 | use ReflectionClass; |
16 | use ReflectionException; |
17 | |
18 | /** |
19 | * Class Reflector. |
20 | * |
21 | * @package routing |
22 | */ |
23 | class Reflector |
24 | { |
25 | /** |
26 | * @var ReflectionClass<object> |
27 | */ |
28 | protected ReflectionClass $reflection; |
29 | |
30 | /** |
31 | * @template T of object |
32 | * |
33 | * @param class-string<T>|object $routeActions |
34 | * |
35 | * @throws ReflectionException |
36 | */ |
37 | public function __construct(object | string $routeActions) |
38 | { |
39 | $this->reflection = new ReflectionClass($routeActions); // @phpstan-ignore-line |
40 | } |
41 | |
42 | /** |
43 | * @param string $method |
44 | * |
45 | * @throws ReflectionException |
46 | * |
47 | * @return array<Route> |
48 | */ |
49 | protected function getMethodRoutes(string $method) : array |
50 | { |
51 | $reflectionMethod = $this->reflection->getMethod($method); |
52 | $routes = []; |
53 | foreach ($reflectionMethod->getAttributes() as $attribute) { |
54 | if ($attribute->getName() === Route::class) { |
55 | $routes[] = $attribute->newInstance(); |
56 | } |
57 | } |
58 | return $routes; // @phpstan-ignore-line |
59 | } |
60 | |
61 | /** |
62 | * @template T of object |
63 | * |
64 | * @param ReflectionClass<T> $reflection |
65 | * |
66 | * @return array<int,string> |
67 | */ |
68 | protected function getObjectOrigins(ReflectionClass $reflection) : array |
69 | { |
70 | $origins = []; |
71 | foreach ($reflection->getAttributes() as $attribute) { |
72 | if ($attribute->getName() === Origin::class) { |
73 | /** |
74 | * @var Origin $origin |
75 | */ |
76 | $origin = $attribute->newInstance(); |
77 | $origins[] = $origin->getOrigin(); |
78 | } |
79 | } |
80 | $parent = $reflection->getParentClass(); |
81 | if ($parent) { |
82 | $origins = [...$origins, ...$this->getObjectOrigins($parent)]; |
83 | } |
84 | $origins = \array_unique($origins); |
85 | \sort($origins); |
86 | return $origins; |
87 | } |
88 | |
89 | /** |
90 | * @throws ReflectionException |
91 | * |
92 | * @return array<mixed> |
93 | */ |
94 | public function getRoutes() : array |
95 | { |
96 | $origins = $this->getObjectOrigins($this->reflection); |
97 | $result = []; |
98 | foreach ($this->reflection->getMethods() as $method) { |
99 | if ( ! $method->isPublic()) { |
100 | continue; |
101 | } |
102 | $routes = $this->getMethodRoutes($method->getName()); |
103 | if (empty($routes)) { |
104 | continue; |
105 | } |
106 | foreach ($routes as $route) { |
107 | $result[] = [ |
108 | 'origins' => $route->getOrigins() ?: $origins, |
109 | 'methods' => $route->getMethods(), |
110 | 'path' => $route->getPath(), |
111 | 'arguments' => $route->getArguments(), |
112 | 'name' => $route->getName(), |
113 | 'action' => $this->reflection->name . '::' . $method->name, |
114 | ]; |
115 | } |
116 | } |
117 | return $result; |
118 | } |
119 | |
120 | /** |
121 | * @param string $method |
122 | * |
123 | * @throws ReflectionException |
124 | * |
125 | * @return array<RouteNotFound> |
126 | */ |
127 | protected function getMethodRoutesNotFound(string $method) : array |
128 | { |
129 | $reflectionMethod = $this->reflection->getMethod($method); |
130 | $routes = []; |
131 | foreach ($reflectionMethod->getAttributes() as $attribute) { |
132 | if ($attribute->getName() === RouteNotFound::class) { |
133 | $routes[] = $attribute->newInstance(); |
134 | } |
135 | } |
136 | return $routes; // @phpstan-ignore-line |
137 | } |
138 | |
139 | /** |
140 | * @throws ReflectionException |
141 | * |
142 | * @return array<mixed> |
143 | */ |
144 | public function getRoutesNotFound() : array |
145 | { |
146 | $origins = $this->getObjectOrigins($this->reflection); |
147 | $result = []; |
148 | foreach ($this->reflection->getMethods() as $method) { |
149 | if ( ! $method->isPublic()) { |
150 | continue; |
151 | } |
152 | $routes = $this->getMethodRoutesNotFound($method->getName()); |
153 | if (empty($routes)) { |
154 | continue; |
155 | } |
156 | foreach ($routes as $route) { |
157 | $result[] = [ |
158 | 'origins' => $route->getOrigins() ?: $origins, |
159 | 'action' => $this->reflection->name . '::' . $method->name, |
160 | ]; |
161 | } |
162 | } |
163 | return $result; |
164 | } |
165 | } |