Skip to content

Commit 0cdfd4a

Browse files
committed
Issue #383: Implemented route grouping
Signed-off-by: alexmerlin <[email protected]>
1 parent 0353184 commit 0cdfd4a

File tree

9 files changed

+121
-99
lines changed

9 files changed

+121
-99
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
"dotkernel/dot-errorhandler": "^4.0.0",
5959
"dotkernel/dot-mail": "^5.3.0",
6060
"dotkernel/dot-response-header": "^3.4.1",
61+
"dotkernel/dot-router": "^1.0.4",
6162
"laminas/laminas-component-installer": "^3.5.0",
6263
"laminas/laminas-config-aggregator": "^1.18.0",
6364
"laminas/laminas-hydrator": "^4.16.0",

config/config.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class_exists(Mezzio\Tooling\ConfigProvider::class)
4646
Dot\Mail\ConfigProvider::class,
4747
Dot\DataFixtures\ConfigProvider::class,
4848
Dot\Cache\ConfigProvider::class,
49+
Dot\Router\ConfigProvider::class,
4950

5051
// Default App module config
5152
Core\Admin\ConfigProvider::class,

src/Admin/src/RoutesDelegator.php

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,33 +13,42 @@
1313
use Api\Admin\Handler\Admin\PostAdminResourceHandler;
1414
use Api\Admin\Handler\Admin\Role\GetAdminRoleCollectionHandler;
1515
use Api\Admin\Handler\Admin\Role\GetAdminRoleResourceHandler;
16+
use Dot\Router\RouteCollectorInterface;
1617
use Mezzio\Application;
18+
use Psr\Container\ContainerExceptionInterface;
1719
use Psr\Container\ContainerInterface;
18-
19-
use function assert;
20+
use Psr\Container\NotFoundExceptionInterface;
2021

2122
class RoutesDelegator
2223
{
24+
/**
25+
* @throws ContainerExceptionInterface
26+
* @throws NotFoundExceptionInterface
27+
*/
2328
public function __invoke(ContainerInterface $container, string $serviceName, callable $callback): Application
2429
{
25-
$app = $callback();
26-
assert($app instanceof Application);
27-
2830
$uuid = \Api\App\RoutesDelegator::REGEXP_UUID;
2931

30-
$app->get('/admin', GetAdminCollectionHandler::class, 'admin::list-admin');
31-
$app->post('/admin', PostAdminResourceHandler::class, 'admin::create-admin');
32+
/** @var RouteCollectorInterface $routeCollector */
33+
$routeCollector = $container->get(RouteCollectorInterface::class);
34+
35+
$routeCollector->group('/admin')
36+
->get('', GetAdminCollectionHandler::class, 'admin::list-admin')
37+
->post('', PostAdminResourceHandler::class, 'admin::create-admin');
3238

33-
$app->delete('/admin/' . $uuid, DeleteAdminResourceHandler::class, 'admin::delete-admin');
34-
$app->get('/admin/' . $uuid, GetAdminResourceHandler::class, 'admin::view-admin');
35-
$app->patch('/admin/' . $uuid, PatchAdminResourceHandler::class, 'admin::update-admin');
39+
$routeCollector->group('/admin/' . $uuid)
40+
->delete('', DeleteAdminResourceHandler::class, 'admin::delete-admin')
41+
->get('', GetAdminResourceHandler::class, 'admin::view-admin')
42+
->patch('', PatchAdminResourceHandler::class, 'admin::update-admin');
3643

37-
$app->get('/admin/role', GetAdminRoleCollectionHandler::class, 'admin::list-role');
38-
$app->get('/admin/role/' . $uuid, GetAdminRoleResourceHandler::class, 'admin::view-role');
44+
$routeCollector->group('/admin/role')
45+
->get('', GetAdminRoleCollectionHandler::class, 'admin::list-role')
46+
->get('/' . $uuid, GetAdminRoleResourceHandler::class, 'admin::view-role');
3947

40-
$app->get('/admin/account', GetAdminAccountResourceHandler::class, 'admin::view-account');
41-
$app->patch('/admin/account', PatchAdminAccountResourceHandler::class, 'admin::update-account');
48+
$routeCollector->group('/admin/account')
49+
->get('', GetAdminAccountResourceHandler::class, 'admin::view-account')
50+
->patch('', PatchAdminAccountResourceHandler::class, 'admin::update-account');
4251

43-
return $app;
52+
return $callback();
4453
}
4554
}

src/App/src/Command/RouteListCommand.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int
5656

5757
$routes = [];
5858
foreach ($this->application->getRoutes() as $route) {
59-
foreach ($route->getAllowedMethods() as $method) {
59+
$methods = $route->getAllowedMethods();
60+
if (empty($methods)) {
61+
$methods = ['*'];
62+
}
63+
64+
foreach ($methods as $method) {
6065
if (! str_contains($route->getName(), $nameFilter)) {
6166
continue;
6267
}

src/App/src/ConfigProvider.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Api\App\Factory\HandlerDelegatorFactory;
1111
use Api\App\Factory\RouteListCommandFactory;
1212
use Api\App\Factory\TokenGenerateCommandFactory;
13+
use Api\App\Handler\GetIndexResourceHandler;
1314
use Api\App\Handler\PostErrorReportResourceHandler;
1415
use Api\App\Middleware\AuthenticationMiddleware;
1516
use Api\App\Middleware\AuthorizationMiddleware;
@@ -52,6 +53,7 @@ public function getDependencies(): array
5253
return [
5354
'delegators' => [
5455
Application::class => [RoutesDelegator::class],
56+
GetIndexResourceHandler::class => [HandlerDelegatorFactory::class],
5557
PostErrorReportResourceHandler::class => [HandlerDelegatorFactory::class],
5658
],
5759
'factories' => [
@@ -63,6 +65,7 @@ public function getDependencies(): array
6365
DeprecationMiddleware::class => AttributedServiceFactory::class,
6466
Environment::class => TwigEnvironmentFactory::class,
6567
ErrorReportPermissionMiddleware::class => AttributedServiceFactory::class,
68+
GetIndexResourceHandler::class => AttributedServiceFactory::class,
6669
PostErrorReportResourceHandler::class => AttributedServiceFactory::class,
6770
ErrorReportService::class => AttributedServiceFactory::class,
6871
ResponseMiddleware::class => AttributedServiceFactory::class,

src/App/src/Middleware/DeprecationMiddleware.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
use Api\App\Exception\DeprecationConflictException;
1010
use Core\App\Message;
1111
use Dot\DependencyInjection\Attribute\Inject;
12+
use Dot\Router\Middleware\LazyLoadingMiddleware;
1213
use Laminas\Stratigility\MiddlewarePipe;
13-
use Mezzio\Middleware\LazyLoadingMiddleware;
14+
use Mezzio\Middleware\LazyLoadingMiddleware as MezzioLazyLoadingMiddleware;
1415
use Mezzio\Router\RouteResult;
1516
use Psr\Http\Message\ResponseInterface;
1617
use Psr\Http\Message\ServerRequestInterface;
@@ -141,7 +142,10 @@ private function getReflectionAttributes(ReflectionClass $reflectionObject): arr
141142
private function getHandler(MiddlewareInterface $routeMiddleware): ?ReflectionClass
142143
{
143144
$reflectionHandler = null;
144-
if ($routeMiddleware instanceof LazyLoadingMiddleware) {
145+
if (
146+
$routeMiddleware instanceof MezzioLazyLoadingMiddleware
147+
|| $routeMiddleware instanceof LazyLoadingMiddleware
148+
) {
145149
/** @var class-string $routeMiddlewareName */
146150
$routeMiddlewareName = $routeMiddleware->middlewareName;
147151
$reflectionMiddlewareClass = new ReflectionClass($routeMiddlewareName);

src/App/src/RoutesDelegator.php

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,33 @@
77
use Api\App\Handler\GetIndexResourceHandler;
88
use Api\App\Handler\PostErrorReportResourceHandler;
99
use Api\App\Middleware\ErrorReportPermissionMiddleware;
10+
use Dot\Router\RouteCollectorInterface;
1011
use Mezzio\Application;
12+
use Psr\Container\ContainerExceptionInterface;
1113
use Psr\Container\ContainerInterface;
12-
13-
use function assert;
14+
use Psr\Container\NotFoundExceptionInterface;
1415

1516
class RoutesDelegator
1617
{
1718
public const REGEXP_UUID = '{uuid:[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}}';
1819

20+
/**
21+
* @throws ContainerExceptionInterface
22+
* @throws NotFoundExceptionInterface
23+
*/
1924
public function __invoke(ContainerInterface $container, string $serviceName, callable $callback): Application
2025
{
21-
$app = $callback();
22-
assert($app instanceof Application);
23-
24-
// Home page
25-
$app->get('/', GetIndexResourceHandler::class, 'app::view-index');
26-
27-
// Other application reports an error
28-
$app->post(
29-
'/error-report',
30-
[ErrorReportPermissionMiddleware::class, PostErrorReportResourceHandler::class],
31-
'app::create-error-report'
32-
);
33-
34-
return $app;
26+
/** @var RouteCollectorInterface $routeCollector */
27+
$routeCollector = $container->get(RouteCollectorInterface::class);
28+
29+
$routeCollector
30+
->get('/', GetIndexResourceHandler::class, 'app::view-index')
31+
->post(
32+
'/error-report',
33+
[ErrorReportPermissionMiddleware::class, PostErrorReportResourceHandler::class],
34+
'app::create-error-report'
35+
);
36+
37+
return $callback();
3538
}
3639
}

src/Security/src/RoutesDelegator.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,30 @@
55
namespace Api\Security;
66

77
use Api\Security\Middleware\ErrorResponseMiddleware;
8+
use Dot\Router\RouteCollectorInterface;
89
use Mezzio\Application;
910
use Mezzio\Authentication\OAuth2\TokenEndpointHandler;
11+
use Psr\Container\ContainerExceptionInterface;
1012
use Psr\Container\ContainerInterface;
11-
12-
use function assert;
13+
use Psr\Container\NotFoundExceptionInterface;
1314

1415
class RoutesDelegator
1516
{
17+
/**
18+
* @throws ContainerExceptionInterface
19+
* @throws NotFoundExceptionInterface
20+
*/
1621
public function __invoke(ContainerInterface $container, string $serviceName, callable $callback): Application
1722
{
18-
$app = $callback();
19-
assert($app instanceof Application);
23+
/** @var RouteCollectorInterface $routeCollector */
24+
$routeCollector = $container->get(RouteCollectorInterface::class);
2025

21-
$app->post(
26+
$routeCollector->post(
2227
'/security/token',
2328
[ErrorResponseMiddleware::class, TokenEndpointHandler::class],
2429
'security::token'
2530
);
2631

27-
return $app;
32+
return $callback();
2833
}
2934
}

src/User/src/RoutesDelegator.php

Lines changed: 50 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -29,73 +29,64 @@
2929
use Api\User\Handler\User\PostUserResourceHandler;
3030
use Api\User\Handler\User\Role\GetUserRoleCollectionHandler;
3131
use Api\User\Handler\User\Role\GetUserRoleResourceHandler;
32+
use Dot\Router\RouteCollectorInterface;
3233
use Mezzio\Application;
34+
use Psr\Container\ContainerExceptionInterface;
3335
use Psr\Container\ContainerInterface;
34-
35-
use function assert;
36+
use Psr\Container\NotFoundExceptionInterface;
3637

3738
class RoutesDelegator
3839
{
40+
/**
41+
* @throws ContainerExceptionInterface
42+
* @throws NotFoundExceptionInterface
43+
*/
3944
public function __invoke(ContainerInterface $container, string $serviceName, callable $callback): Application
4045
{
41-
$app = $callback();
42-
assert($app instanceof Application);
43-
4446
$uuid = \Api\App\RoutesDelegator::REGEXP_UUID;
4547

46-
// Accounts having higher than user permissions manage user accounts
47-
48-
$app->get('/user', GetUserCollectionHandler::class, 'user::list-user');
49-
$app->post('/user', PostUserResourceHandler::class, 'user::create-user');
50-
51-
$app->delete('/user/' . $uuid, DeleteUserResourceHandler::class, 'user::delete-user');
52-
$app->get('/user/' . $uuid, GetUserResourceHandler::class, 'user::view-user');
53-
$app->patch('/user/' . $uuid, PatchUserResourceHandler::class, 'user::update-user');
54-
55-
$app->delete('/user/' . $uuid . '/avatar', DeleteUserAvatarResourceHandler::class, 'user::delete-user-avatar');
56-
$app->get('/user/' . $uuid . '/avatar', GetUserAvatarResourceHandler::class, 'user::view-user-avatar');
57-
$app->post('/user/' . $uuid . '/avatar', PostUserAvatarResourceHandler::class, 'user::create-user-avatar');
58-
59-
$app->get('/user/role', GetUserRoleCollectionHandler::class, 'user::list-role');
60-
$app->get('/user/role/' . $uuid, GetUserRoleResourceHandler::class, 'user::view-role');
61-
62-
$app->patch('/user/' . $uuid . '/activate', PatchUserActivateHandler::class, 'user::activate-user');
63-
$app->patch('/user/' . $uuid . '/deactivate', PatchUserDeactivateHandler::class, 'user::deactivate-user');
64-
65-
// Users manage their user accounts
66-
67-
$app->delete('/user/account', DeleteUserAccountResourceHandler::class, 'user::delete-account');
68-
$app->get('/user/account', GetUserAccountResourceHandler::class, 'user::view-account');
69-
$app->patch('/user/account', PatchUserAccountResourceHandler::class, 'user::update-account');
70-
$app->post('/user/account', PostUserAccountResourceHandler::class, 'user::create-account');
71-
72-
$app->delete('/user/account/avatar', DeleteUserAccountAvatarHandler::class, 'user::delete-account-avatar');
73-
$app->get('/user/account/avatar', GetUserAccountAvatarHandler::class, 'user::view-account-avatar');
74-
$app->post('/user/account/avatar', PostUserAccountAvatarHandler::class, 'user::create-account-avatar');
75-
76-
// Unauthenticated users manage their user accounts
77-
78-
$app->patch('/user/account/activate/{hash}', PatchUserAccountActivateHandler::class, 'user::activate-account');
79-
$app->post('/user/account/activate', PostUserAccountActivateHandler::class, 'user::request-activate-account');
80-
81-
$app->post('/user/account/recover', PostUserAccountRecoverHandler::class, 'user::recover-account');
82-
83-
$app->get(
84-
'/user/account/reset-password/{hash}',
85-
GetUserAccountResetPasswordHandler::class,
86-
'user::check-account-reset-password'
87-
);
88-
$app->patch(
89-
'/user/account/reset-password/{hash}',
90-
PatchUserAccountResetPasswordHandler::class,
91-
'user::update-account-reset-password'
92-
);
93-
$app->post(
94-
'/user/account/reset-password',
95-
PostUserAccountResetPasswordHandler::class,
96-
'user::create-account-reset-password'
97-
);
98-
99-
return $app;
48+
/** @var RouteCollectorInterface $routeCollector */
49+
$routeCollector = $container->get(RouteCollectorInterface::class);
50+
51+
$routeCollector->group('/user')
52+
->get('', GetUserCollectionHandler::class, 'user::list-user')
53+
->post('', PostUserResourceHandler::class, 'user::create-user')
54+
->patch('/' . $uuid . '/activate', PatchUserActivateHandler::class, 'user::activate-user')
55+
->patch('/' . $uuid . '/deactivate', PatchUserDeactivateHandler::class, 'user::deactivate-user');
56+
57+
$routeCollector->group('/user')
58+
->delete('/' . $uuid, DeleteUserResourceHandler::class, 'user::delete-user')
59+
->get('/' . $uuid, GetUserResourceHandler::class, 'user::view-user')
60+
->patch('/' . $uuid, PatchUserResourceHandler::class, 'user::update-user');
61+
62+
$routeCollector->group('/user/' . $uuid . '/avatar')
63+
->delete('', DeleteUserAvatarResourceHandler::class, 'user::delete-user-avatar')
64+
->get('', GetUserAvatarResourceHandler::class, 'user::view-user-avatar')
65+
->post('', PostUserAvatarResourceHandler::class, 'user::create-user-avatar');
66+
67+
$routeCollector->group('/user/role')
68+
->get('', GetUserRoleCollectionHandler::class, 'user::list-role')
69+
->get('/' . $uuid, GetUserRoleResourceHandler::class, 'user::view-role');
70+
71+
$routeCollector->group('/user/account')
72+
->delete('', DeleteUserAccountResourceHandler::class, 'user::delete-account')
73+
->get('', GetUserAccountResourceHandler::class, 'user::view-account')
74+
->patch('', PatchUserAccountResourceHandler::class, 'user::update-account')
75+
->post('', PostUserAccountResourceHandler::class, 'user::create-account')
76+
->patch('/activate/{hash}', PatchUserAccountActivateHandler::class, 'user::activate-account')
77+
->post('/activate', PostUserAccountActivateHandler::class, 'user::request-activate-account')
78+
->post('/recover', PostUserAccountRecoverHandler::class, 'user::recover-account');
79+
80+
$routeCollector->group('/user/account/avatar')
81+
->delete('', DeleteUserAccountAvatarHandler::class, 'user::delete-account-avatar')
82+
->get('', GetUserAccountAvatarHandler::class, 'user::view-account-avatar')
83+
->post('', PostUserAccountAvatarHandler::class, 'user::create-account-avatar');
84+
85+
$routeCollector->group('/user/account/reset-password')
86+
->get('/{hash}', GetUserAccountResetPasswordHandler::class, 'user::check-account-reset-password')
87+
->patch('/{hash}', PatchUserAccountResetPasswordHandler::class, 'user::update-account-reset-password')
88+
->post('', PostUserAccountResetPasswordHandler::class, 'user::create-account-reset-password');
89+
90+
return $callback();
10091
}
10192
}

0 commit comments

Comments
 (0)