Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"dotkernel/dot-errorhandler": "^4.0.0",
"dotkernel/dot-mail": "^5.3.0",
"dotkernel/dot-response-header": "^3.4.1",
"dotkernel/dot-router": "^1.0.4",
"laminas/laminas-component-installer": "^3.5.0",
"laminas/laminas-config-aggregator": "^1.18.0",
"laminas/laminas-hydrator": "^4.16.0",
Expand Down
1 change: 1 addition & 0 deletions config/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class_exists(Mezzio\Tooling\ConfigProvider::class)
Dot\Mail\ConfigProvider::class,
Dot\DataFixtures\ConfigProvider::class,
Dot\Cache\ConfigProvider::class,
Dot\Router\ConfigProvider::class,

// Default App module config
Core\Admin\ConfigProvider::class,
Expand Down
82 changes: 43 additions & 39 deletions documentation/command/route-list.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,49 @@ php ./bin/cli.php route:list
The command runs through all routes and extracts endpoint information in realtime.
The output should be similar to the following:

| Request method | Route name | Route path |
|-----------------|---------------------------------|--------------------------------|
| DELETE | admin.delete | /admin/{uuid} |
| DELETE | user.my-account.delete | /user/my-account |
| DELETE | user.my-avatar.delete | /user/my-avatar |
| DELETE | user.delete | /user/{uuid} |
| DELETE | user.avatar.delete | /user/{uuid}/avatar |
| GET | home | / |
| GET | account.reset-password.validate | /account/reset-password/{hash} |
| GET | admin.list | /admin |
| GET | admin.my-account.view | /admin/my-account |
| GET | admin.role.list | /admin/role |
| GET | admin.role.view | /admin/role/{uuid} |
| GET | admin.view | /admin/{uuid} |
| GET | user.list | /user |
| GET | user.my-account.view | /user/my-account |
| GET | user.my-avatar.view | /user/my-avatar |
| GET | user.role.list | /user/role |
| GET | user.role.view | /user/role/{uuid} |
| GET | user.view | /user/{uuid} |
| GET | user.avatar.view | /user/{uuid}/avatar |
| PATCH | account.activate | /account/activate/{hash} |
| PATCH | account.modify-password | /account/reset-password/{hash} |
| PATCH | admin.my-account.update | /admin/my-account |
| PATCH | admin.update | /admin/{uuid} |
| PATCH | user.my-account.update | /user/my-account |
| PATCH | user.update | /user/{uuid} |
| POST | account.activate.request | /account/activate |
| POST | account.recover-identity | /account/recover-identity |
| POST | account.register | /account/register |
| POST | account.reset-password.request | /account/reset-password |
| POST | admin.create | /admin |
| POST | error.report | /error-report |
| POST | security.generate-token | /security/generate-token |
| POST | security.refresh-token | /security/refresh-token |
| POST | user.create | /user |
| POST | user.my-avatar.create | /user/my-avatar |
| POST | user.activate | /user/{uuid}/activate |
| POST | user.avatar.create | /user/{uuid}/avatar |
```text
+------+----------------+-------------------- 37 Routes ------+-------------------------------------+
| # | Request method | Route name | Route path |
+------+----------------+-------------------------------------+-------------------------------------+
| 1 | GET | app::view-index | / |
| 2 | GET | admin::list-admin | /admin |
| 3 | POST | admin::create-admin | /admin |
| 4 | GET | admin::view-account | /admin/account |
| 5 | PATCH | admin::update-account | /admin/account |
| 6 | GET | admin::list-role | /admin/role |
| 7 | GET | admin::view-role | /admin/role/{uuid} |
| 8 | DELETE | admin::delete-admin | /admin/{uuid} |
| 9 | GET | admin::view-admin | /admin/{uuid} |
| 10 | PATCH | admin::update-admin | /admin/{uuid} |
| 11 | POST | app::create-error-report | /error-report |
| 12 | POST | security::token | /security/token |
| 13 | GET | user::list-user | /user |
| 14 | POST | user::create-user | /user |
| 15 | DELETE | user::delete-account | /user/account |
| 16 | GET | user::view-account | /user/account |
| 17 | PATCH | user::update-account | /user/account |
| 18 | POST | user::create-account | /user/account |
| 19 | POST | user::request-activate-account | /user/account/activate |
| 20 | PATCH | user::activate-account | /user/account/activate/{hash} |
| 21 | DELETE | user::delete-account-avatar | /user/account/avatar |
| 22 | GET | user::view-account-avatar | /user/account/avatar |
| 23 | POST | user::create-account-avatar | /user/account/avatar |
| 24 | POST | user::recover-account | /user/account/recover |
| 25 | POST | user::create-account-reset-password | /user/account/reset-password |
| 26 | GET | user::check-account-reset-password | /user/account/reset-password/{hash} |
| 27 | PATCH | user::update-account-reset-password | /user/account/reset-password/{hash} |
| 28 | GET | user::list-role | /user/role |
| 29 | GET | user::view-role | /user/role/{uuid} |
| 30 | DELETE | user::delete-user | /user/{uuid} |
| 31 | GET | user::view-user | /user/{uuid} |
| 32 | PATCH | user::update-user | /user/{uuid} |
| 33 | PATCH | user::activate-user | /user/{uuid}/activate |
| 34 | DELETE | user::delete-user-avatar | /user/{uuid}/avatar |
| 35 | GET | user::view-user-avatar | /user/{uuid}/avatar |
| 36 | POST | user::create-user-avatar | /user/{uuid}/avatar |
| 37 | PATCH | user::deactivate-user | /user/{uuid}/deactivate |
+------+----------------+-------------------------------------+-------------------------------------+
```

## Filtering results

Expand Down
39 changes: 24 additions & 15 deletions src/Admin/src/RoutesDelegator.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,42 @@
use Api\Admin\Handler\Admin\PostAdminResourceHandler;
use Api\Admin\Handler\Admin\Role\GetAdminRoleCollectionHandler;
use Api\Admin\Handler\Admin\Role\GetAdminRoleResourceHandler;
use Dot\Router\RouteCollectorInterface;
use Mezzio\Application;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;

use function assert;
use Psr\Container\NotFoundExceptionInterface;

class RoutesDelegator
{
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function __invoke(ContainerInterface $container, string $serviceName, callable $callback): Application
{
$app = $callback();
assert($app instanceof Application);

$uuid = \Api\App\RoutesDelegator::REGEXP_UUID;

$app->get('/admin', GetAdminCollectionHandler::class, 'admin::list-admin');
$app->post('/admin', PostAdminResourceHandler::class, 'admin::create-admin');
/** @var RouteCollectorInterface $routeCollector */
$routeCollector = $container->get(RouteCollectorInterface::class);

$routeCollector->group('/admin')
->get('', GetAdminCollectionHandler::class, 'admin::list-admin')
->post('', PostAdminResourceHandler::class, 'admin::create-admin');

$app->delete('/admin/' . $uuid, DeleteAdminResourceHandler::class, 'admin::delete-admin');
$app->get('/admin/' . $uuid, GetAdminResourceHandler::class, 'admin::view-admin');
$app->patch('/admin/' . $uuid, PatchAdminResourceHandler::class, 'admin::update-admin');
$routeCollector->group('/admin/' . $uuid)
->delete('', DeleteAdminResourceHandler::class, 'admin::delete-admin')
->get('', GetAdminResourceHandler::class, 'admin::view-admin')
->patch('', PatchAdminResourceHandler::class, 'admin::update-admin');

$app->get('/admin/role', GetAdminRoleCollectionHandler::class, 'admin::list-role');
$app->get('/admin/role/' . $uuid, GetAdminRoleResourceHandler::class, 'admin::view-role');
$routeCollector->group('/admin/role')
->get('', GetAdminRoleCollectionHandler::class, 'admin::list-role')
->get('/' . $uuid, GetAdminRoleResourceHandler::class, 'admin::view-role');

$app->get('/admin/account', GetAdminAccountResourceHandler::class, 'admin::view-account');
$app->patch('/admin/account', PatchAdminAccountResourceHandler::class, 'admin::update-account');
$routeCollector->group('/admin/account')
->get('', GetAdminAccountResourceHandler::class, 'admin::view-account')
->patch('', PatchAdminAccountResourceHandler::class, 'admin::update-account');

return $app;
return $callback();
}
}
14 changes: 13 additions & 1 deletion src/App/src/Command/RouteListCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Api\App\Command;

use Api\App\RoutesDelegator;
use Fig\Http\Message\RequestMethodInterface;
use Mezzio\Application;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
Expand Down Expand Up @@ -56,7 +57,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int

$routes = [];
foreach ($this->application->getRoutes() as $route) {
foreach ($route->getAllowedMethods() as $method) {
$methods = $route->getAllowedMethods();
if (empty($methods)) {
$methods = [
RequestMethodInterface::METHOD_DELETE,
RequestMethodInterface::METHOD_GET,
RequestMethodInterface::METHOD_PATCH,
RequestMethodInterface::METHOD_POST,
RequestMethodInterface::METHOD_PUT,
];
}

foreach ($methods as $method) {
if (! str_contains($route->getName(), $nameFilter)) {
continue;
}
Expand Down
3 changes: 3 additions & 0 deletions src/App/src/ConfigProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Api\App\Factory\HandlerDelegatorFactory;
use Api\App\Factory\RouteListCommandFactory;
use Api\App\Factory\TokenGenerateCommandFactory;
use Api\App\Handler\GetIndexResourceHandler;
use Api\App\Handler\PostErrorReportResourceHandler;
use Api\App\Middleware\AuthenticationMiddleware;
use Api\App\Middleware\AuthorizationMiddleware;
Expand Down Expand Up @@ -52,6 +53,7 @@ public function getDependencies(): array
return [
'delegators' => [
Application::class => [RoutesDelegator::class],
GetIndexResourceHandler::class => [HandlerDelegatorFactory::class],
PostErrorReportResourceHandler::class => [HandlerDelegatorFactory::class],
],
'factories' => [
Expand All @@ -63,6 +65,7 @@ public function getDependencies(): array
DeprecationMiddleware::class => AttributedServiceFactory::class,
Environment::class => TwigEnvironmentFactory::class,
ErrorReportPermissionMiddleware::class => AttributedServiceFactory::class,
GetIndexResourceHandler::class => AttributedServiceFactory::class,
PostErrorReportResourceHandler::class => AttributedServiceFactory::class,
ErrorReportService::class => AttributedServiceFactory::class,
ResponseMiddleware::class => AttributedServiceFactory::class,
Expand Down
8 changes: 6 additions & 2 deletions src/App/src/Middleware/DeprecationMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
use Api\App\Exception\DeprecationConflictException;
use Core\App\Message;
use Dot\DependencyInjection\Attribute\Inject;
use Dot\Router\Middleware\LazyLoadingMiddleware;
use Laminas\Stratigility\MiddlewarePipe;
use Mezzio\Middleware\LazyLoadingMiddleware;
use Mezzio\Middleware\LazyLoadingMiddleware as MezzioLazyLoadingMiddleware;
use Mezzio\Router\RouteResult;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
Expand Down Expand Up @@ -141,7 +142,10 @@ private function getReflectionAttributes(ReflectionClass $reflectionObject): arr
private function getHandler(MiddlewareInterface $routeMiddleware): ?ReflectionClass
{
$reflectionHandler = null;
if ($routeMiddleware instanceof LazyLoadingMiddleware) {
if (
$routeMiddleware instanceof MezzioLazyLoadingMiddleware
|| $routeMiddleware instanceof LazyLoadingMiddleware
) {
/** @var class-string $routeMiddlewareName */
$routeMiddlewareName = $routeMiddleware->middlewareName;
$reflectionMiddlewareClass = new ReflectionClass($routeMiddlewareName);
Expand Down
35 changes: 19 additions & 16 deletions src/App/src/RoutesDelegator.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,33 @@
use Api\App\Handler\GetIndexResourceHandler;
use Api\App\Handler\PostErrorReportResourceHandler;
use Api\App\Middleware\ErrorReportPermissionMiddleware;
use Dot\Router\RouteCollectorInterface;
use Mezzio\Application;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;

use function assert;
use Psr\Container\NotFoundExceptionInterface;

class RoutesDelegator
{
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}}';

/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function __invoke(ContainerInterface $container, string $serviceName, callable $callback): Application
{
$app = $callback();
assert($app instanceof Application);

// Home page
$app->get('/', GetIndexResourceHandler::class, 'app::view-index');

// Other application reports an error
$app->post(
'/error-report',
[ErrorReportPermissionMiddleware::class, PostErrorReportResourceHandler::class],
'app::create-error-report'
);

return $app;
/** @var RouteCollectorInterface $routeCollector */
$routeCollector = $container->get(RouteCollectorInterface::class);

$routeCollector
->get('/', GetIndexResourceHandler::class, 'app::view-index')
->post(
'/error-report',
[ErrorReportPermissionMiddleware::class, PostErrorReportResourceHandler::class],
'app::create-error-report'
);

return $callback();
}
}
17 changes: 11 additions & 6 deletions src/Security/src/RoutesDelegator.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,30 @@
namespace Api\Security;

use Api\Security\Middleware\ErrorResponseMiddleware;
use Dot\Router\RouteCollectorInterface;
use Mezzio\Application;
use Mezzio\Authentication\OAuth2\TokenEndpointHandler;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;

use function assert;
use Psr\Container\NotFoundExceptionInterface;

class RoutesDelegator
{
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function __invoke(ContainerInterface $container, string $serviceName, callable $callback): Application
{
$app = $callback();
assert($app instanceof Application);
/** @var RouteCollectorInterface $routeCollector */
$routeCollector = $container->get(RouteCollectorInterface::class);

$app->post(
$routeCollector->post(
'/security/token',
[ErrorResponseMiddleware::class, TokenEndpointHandler::class],
'security::token'
);

return $app;
return $callback();
}
}
Loading