• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

contributte / api-router / 19974859358

05 Dec 2025 08:16PM UTC coverage: 88.272% (-0.4%) from 88.72%
19974859358

push

github

f3l1x
CI: add PHP 8.5

286 of 324 relevant lines covered (88.27%)

0.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.43
/src/DI/ApiRouterExtension.php
1
<?php declare(strict_types = 1);
2

3
namespace Contributte\ApiRouter\DI;
4

5
use Contributte\ApiRouter\ApiRoute;
6
use Contributte\Utils\Annotations;
7
use Nette\Application\IPresenter;
8
use Nette\DI\CompilerExtension;
9
use Nette\DI\ContainerBuilder;
10
use Nette\DI\Definitions\Definition;
11
use Nette\DI\Definitions\Statement;
12
use Nette\PhpGenerator\ClassType as GClassType;
13
use ReflectionClass;
14
use ReflectionMethod;
15

16
class ApiRouterExtension extends CompilerExtension
17
{
18

19
        private ?Definition $definition = null;
20

21
        public function beforeCompile(): void
22
        {
23
                $builder = $this->getContainerBuilder();
1✔
24

25
                $routes = $this->findRoutes($builder);
1✔
26
                $routesStatements = [];
1✔
27

28
                foreach ($routes as $route) {
1✔
29
                        $routesStatements[] = new Statement(ApiRoute::class . '::fromArray', [$route->toArray()]);
1✔
30
                }
31

32
                $this->definition = $builder->addDefinition($this->prefix('resolver'))
1✔
33
                        ->setType(ApiRoutesResolver::class)
1✔
34
                        ->addSetup('prepandRoutes', [$builder->getDefinition('router'), $routesStatements]);
1✔
35
        }
1✔
36

37
        public function afterCompile(GClassType $class): void
1✔
38
        {
39
                parent::afterCompile($class);
1✔
40

41
                $class->getMethod('initialize')->addBody('$this->getService(?);', [$this->definition->getName()]);
1✔
42
        }
1✔
43

44
        /**
45
         * @return array<string, ApiRoute[]>
46
         */
47
        private function findRoutes(ContainerBuilder $builder): array
1✔
48
        {
49
                /**
50
                 * Find all presenters and their routes
51
                 */
52
                $presentersDec = $builder->findByType(IPresenter::class);
1✔
53
                $routes = [];
1✔
54

55
                foreach ($presentersDec as $presenterDec) {
1✔
56
                        $this->findRoutesInPresenter($presenterDec->getType(), $routes);
1✔
57
                }
58

59
                /**
60
                 * Return routes sorted by priority
61
                 */
62
                return $this->sortByPriority($routes);
1✔
63
        }
64

65
        /**
66
         * @param array<ApiRoute> $routes
67
         */
68
        private function findRoutesInPresenter(string $presenter, array &$routes): void
1✔
69
        {
70
                $r = new ReflectionClass($presenter);
1✔
71

72
                $attributes = $r->getAttributes(ApiRoute::class);
1✔
73

74
                if ($attributes === []) {
1✔
75
                        return;
×
76
                }
77

78
                $route = $attributes[0]->newInstance();
1✔
79

80
                /**
81
                 * Add route to priority-half-sorted list
82
                 */
83
                if ($routes !== [] && !$routes[$route->getPriority()]) {
1✔
84
                        $routes[$route->getPriority()] = [];
×
85
                }
86

87
                $route->setDescription(Annotations::getAnnotation($r, 'description'));
1✔
88

89
                if (!$route->getPresenter()) {
1✔
90
                        $route->setPresenter(preg_replace('/Presenter$/', '', $r->getShortName()));
1✔
91
                }
92

93
                /**
94
                 * Find apropriate methods
95
                 */
96
                foreach ($r->getMethods() as $method_r) {
1✔
97
                        $this->findPresenterMethodRoute($method_r, $routes, $route);
1✔
98
                }
99

100
                /**
101
                 * Add ApiRouter annotated presenter route only if there are some remaining
102
                 * methods without ApiRouter annotated presenter method
103
                 */
104
                if ($route->getMethods() !== []) {
1✔
105
                        $routes[$route->getPriority()][] = $route;
1✔
106
                }
107
        }
1✔
108

109
        /**
110
         * @param array<ApiRoute> $routes
111
         */
112
        private function findPresenterMethodRoute(
1✔
113
                ReflectionMethod $method_reflection,
114
                array &$routes,
115
                ApiRoute $route
116
        ): void
117
        {
118
                $attributes = $method_reflection->getAttributes(ApiRoute::class);
1✔
119
                $actionRoute = $attributes !== [] ? $attributes[0]->newInstance() : null;
1✔
120

121
                /**
122
                 * Get action without that ^action string
123
                 */
124
                $action = lcfirst(preg_replace('/^action/', '', $method_reflection->name));
1✔
125

126
                /**
127
                 * Route can be defined also for particular action
128
                 */
129
                if (!$actionRoute) {
1✔
130
                        $route->setAction($action);
1✔
131

132
                        return;
1✔
133
                }
134

135
                $actionRoute->setDescription(Annotations::getAnnotation($method_reflection, 'description'));
1✔
136

137
                /**
138
                 * Action route will inherit presenter name, priority, etc from parent route
139
                 */
140
                $actionRoute->setPresenter($actionRoute->getPresenter() ?: $route->getPresenter());
1✔
141
                $actionRoute->setPriority($actionRoute->getPriority() ?: $route->getPriority());
1✔
142
                $actionRoute->setFormat($actionRoute->getFormat() ?: $route->getFormat());
1✔
143
                $actionRoute->setSection($actionRoute->getSection() ?: $route->getSection());
1✔
144
                $actionRoute->setAction($action, $actionRoute->getMethod() ?: null);
1✔
145

146
                $routes[$route->getPriority()][] = $actionRoute;
1✔
147
        }
1✔
148

149
        /**
150
         * @param array<ApiRoute> $routes
151
         * @return array<ApiRoute>
152
         */
153
        private function sortByPriority(array $routes): array
1✔
154
        {
155
                $return = [];
1✔
156

157
                foreach ($routes as $priority_routes) {
1✔
158
                        foreach ($priority_routes as $route) {
1✔
159
                                $return[] = $route;
1✔
160
                        }
161
                }
162

163
                return $return;
1✔
164
        }
165

166
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc