Passed
Pull Request — master (#196)
by Rustam
02:49
created

AttributeRoutesProvider::getRoutes()   B

Complexity

Conditions 8
Paths 12

Size

Total Lines 36
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 8
eloc 26
c 2
b 0
f 0
nc 12
nop 0
dl 0
loc 36
ccs 0
cts 28
cp 0
crap 72
rs 8.4444
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Router\Provider;
6
7
use olvlvl\ComposerAttributeCollector\Attributes;
8
use ReflectionAttribute;
9
use ReflectionClass;
10
use Yiisoft\Router\Attribute\RouteAttributeInterface;
11
use Yiisoft\Router\Group;
12
use Yiisoft\Router\Route;
13
14
/**
15
 * An attribute provider provides routes that declared via PHP Attributes.
16
 * Currently, uses `olvlvl/composer-attribute-collector`. {@link https://github.com/olvlvl/composer-attribute-collector}.
17
 */
18
final class AttributeRoutesProvider implements RoutesProviderInterface
19
{
20
    /**
21
     * @var array<class-string, ReflectionClass>
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<class-string, ReflectionClass> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string, ReflectionClass>.
Loading history...
22
     */
23
    private static array $reflectionsCache = [];
24
25
    public function getRoutes(): array
26
    {
27
        $routes = [];
28
        $groupRoutes = [];
29
        $routePredicate = Attributes::predicateForAttributeInstanceOf(RouteAttributeInterface::class);
30
        $targetMethods = Attributes::filterTargetMethods($routePredicate);
31
        foreach ($targetMethods as $targetMethod) {
32
            /** @var RouteAttributeInterface $routeAttribute */
33
            $routeAttribute = $targetMethod->attribute;
34
            $route = $routeAttribute->getRoute();
35
            $targetMethodReflection = self::$reflectionsCache[$targetMethod->class] ??= new ReflectionClass(
36
                $targetMethod->class
37
            );
38
            /** @var Group[] $groupAttributes */
39
            $groupAttributes = $targetMethodReflection->getAttributes(
40
                Group::class,
41
                ReflectionAttribute::IS_INSTANCEOF
42
            );
43
            if (!empty($groupAttributes)) {
44
                $groupRoutes[$targetMethod->class][] = $route->action([$targetMethod->class, $targetMethod->name]);
45
            } else {
46
                $routes[] = $route->action([$targetMethod->class, $targetMethod->name]);
47
            }
48
        }
49
        $groupPredicate = static fn (string $attribute): bool => is_a($attribute, Route::class, true)
50
            || is_a($attribute, Group::class, true);
51
        $targetClasses = Attributes::filterTargetClasses($groupPredicate);
52
        foreach ($targetClasses as $targetClass) {
53
            $group = $targetClass->attribute;
54
            if ($group instanceof Group && isset($groupRoutes[$targetClass->name])) {
55
                $routes[] = $group->routes(...$groupRoutes[$targetClass->name]);
56
            } elseif ($group instanceof Route) {
57
                $routes[] = $group->action($targetClass->name);
58
            }
59
        }
60
        return $routes;
0 ignored issues
show
introduced by
The expression return $routes returns an array which contains values of type Yiisoft\Router\Route which are incompatible with the return type Yiisoft\Router\Group mandated by Yiisoft\Router\Provider\...rInterface::getRoutes().
Loading history...
61
    }
62
}
63