From af5fd05262b8a08d79aa97ba97f138e684be390b Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Thu, 13 Jun 2024 01:56:18 +0300 Subject: [PATCH 01/10] Wrap application's fallback handler to provider debug headers --- config/di-web.php | 6 +++ config/params.php | 6 +++ .../Http/DebugHttpApplicationWrapper.php | 27 +++++++++++ src/Debug/Middleware/DebugFallbackHandler.php | 46 +++++++++++++++++++ src/Debug/Provider/DebugApiProvider.php | 13 +++++- 5 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 src/Debug/Http/DebugHttpApplicationWrapper.php create mode 100644 src/Debug/Middleware/DebugFallbackHandler.php diff --git a/config/di-web.php b/config/di-web.php index 4836e98..5f59c41 100644 --- a/config/di-web.php +++ b/config/di-web.php @@ -5,6 +5,7 @@ use Cycle\Database\DatabaseProviderInterface; use Psr\Container\ContainerInterface; use Yiisoft\Db\Connection\ConnectionInterface; +use Yiisoft\Yii\Debug\Api\Debug\Middleware\DebugFallbackHandler; use Yiisoft\Yii\Debug\Api\Debug\Repository\CollectorRepository; use Yiisoft\Yii\Debug\Api\Debug\Repository\CollectorRepositoryInterface; use Yiisoft\Yii\Debug\Api\Inspector\Database\Cycle\CycleSchemaProvider; @@ -34,4 +35,9 @@ ) ); }, + DebugFallbackHandler::class => [ + '__construct()' => [ + 'middlewareDefinitions' => $params['yiisoft/yii-debug-api']['fallbackHandler']['middlewares'], + ], + ], ]; diff --git a/config/params.php b/config/params.php index b6c42ba..f7797e8 100644 --- a/config/params.php +++ b/config/params.php @@ -3,6 +3,7 @@ declare(strict_types=1); use Codeception\Extension; +use Yiisoft\Yii\Debug\Api\Debug\Middleware\DebugHeaders; use Yiisoft\Yii\Debug\Api\Inspector\Command\CodeceptionCommand; use Yiisoft\Yii\Debug\Api\Inspector\Command\PHPUnitCommand; use Yiisoft\Yii\Debug\Api\Inspector\Command\PsalmCommand; @@ -34,6 +35,11 @@ ], ], ], + 'fallbackHandler' => [ + 'middlewares' => [ + DebugHeaders::class, + ], + ] ], 'yiisoft/yii-swagger' => [ 'annotation-paths' => [ diff --git a/src/Debug/Http/DebugHttpApplicationWrapper.php b/src/Debug/Http/DebugHttpApplicationWrapper.php new file mode 100644 index 0000000..e634745 --- /dev/null +++ b/src/Debug/Http/DebugHttpApplicationWrapper.php @@ -0,0 +1,27 @@ +debugFallbackHandler; + $closure = Closure::bind(static function (Application $application) use ($debugFallbackHandler) { + $application->fallbackHandler = $debugFallbackHandler->withFallbackRequestHandler($application->fallbackHandler); + }, null, $application); + + $closure($application); + } +} diff --git a/src/Debug/Middleware/DebugFallbackHandler.php b/src/Debug/Middleware/DebugFallbackHandler.php new file mode 100644 index 0000000..f908fe2 --- /dev/null +++ b/src/Debug/Middleware/DebugFallbackHandler.php @@ -0,0 +1,46 @@ +middlewareDispatcher + ->withMiddlewares($this->middlewareDefinitions) + ->dispatch($request, $handler); + } + + public function handle(ServerRequestInterface $request): ResponseInterface + { + if ($this->fallbackHandler === null) { + throw new \RuntimeException('No fallback handler defined.'); + } + + return $this->process($request, $this->fallbackHandler); + } + + public function withFallbackRequestHandler(RequestHandlerInterface $fallbackHandler): self + { + $new = clone $this; + $new->fallbackHandler = $fallbackHandler; + + return $new; + } +} diff --git a/src/Debug/Provider/DebugApiProvider.php b/src/Debug/Provider/DebugApiProvider.php index d62d5be..2bd6eee 100644 --- a/src/Debug/Provider/DebugApiProvider.php +++ b/src/Debug/Provider/DebugApiProvider.php @@ -7,7 +7,9 @@ use Psr\Container\ContainerInterface; use Yiisoft\Di\ServiceProviderInterface; use Yiisoft\Router\RouteCollectorInterface; +use Yiisoft\Yii\Debug\Api\Debug\Http\DebugHttpApplicationWrapper; use Yiisoft\Yii\Debug\Api\Debug\Middleware\DebugHeaders; +use Yiisoft\Yii\Http\Application; final class DebugApiProvider implements ServiceProviderInterface { @@ -22,10 +24,19 @@ public function getDefinitions(): array public function getExtensions(): array { return [ - RouteCollectorInterface::class => static function (ContainerInterface $container, RouteCollectorInterface $routeCollector) { + RouteCollectorInterface::class => static function ( + ContainerInterface $container, + RouteCollectorInterface $routeCollector + ) { $routeCollector->prependMiddleware(DebugHeaders::class); return $routeCollector; }, + Application::class => static function (ContainerInterface $container, Application $application) { + $applicationWrapper = $container->get(DebugHttpApplicationWrapper::class); + $applicationWrapper->wrap($application); + + return $application; + }, ]; } } From 27d4daa52b78e653df64dc60e71989bcb81bc762 Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Wed, 12 Jun 2024 22:57:04 +0000 Subject: [PATCH 02/10] Apply fixes from StyleCI --- config/params.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/params.php b/config/params.php index f7797e8..a11a878 100644 --- a/config/params.php +++ b/config/params.php @@ -39,7 +39,7 @@ 'middlewares' => [ DebugHeaders::class, ], - ] + ], ], 'yiisoft/yii-swagger' => [ 'annotation-paths' => [ From f8f59f6748ad22b482f53444bf86083e4c5b720d Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Thu, 13 Jun 2024 02:02:10 +0300 Subject: [PATCH 03/10] Ignore class --- composer-require-checker.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer-require-checker.json b/composer-require-checker.json index 23b3346..0528b49 100644 --- a/composer-require-checker.json +++ b/composer-require-checker.json @@ -4,6 +4,7 @@ "Yiisoft\\Assets\\AssetManager", "Yiisoft\\Assets\\AssetPublisherInterface", "Yiisoft\\Yii\\View\\ViewRenderer", + "Yiisoft\\Yii\\Http\\Application", "Codeception\\Event\\FailEvent", "Codeception\\Event\\PrintResultEvent", "Codeception\\Event\\TestEvent", From 9ae68ef5033cb89975ada4dbd440c99fa89b3a15 Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Thu, 13 Jun 2024 02:05:00 +0300 Subject: [PATCH 04/10] Fix tests --- src/Debug/Provider/DebugApiProvider.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Debug/Provider/DebugApiProvider.php b/src/Debug/Provider/DebugApiProvider.php index 2bd6eee..9673710 100644 --- a/src/Debug/Provider/DebugApiProvider.php +++ b/src/Debug/Provider/DebugApiProvider.php @@ -24,10 +24,7 @@ public function getDefinitions(): array public function getExtensions(): array { return [ - RouteCollectorInterface::class => static function ( - ContainerInterface $container, - RouteCollectorInterface $routeCollector - ) { + RouteCollectorInterface::class => static function (RouteCollectorInterface $routeCollector) { $routeCollector->prependMiddleware(DebugHeaders::class); return $routeCollector; }, From 4fa88340933f00fa6fa9411f0faead19797448b8 Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Fri, 14 Jun 2024 14:03:29 +0300 Subject: [PATCH 05/10] Refactor --- config/di-web.php | 6 +-- config/params.php | 8 ++-- .../Http/DebugHttpApplicationWrapper.php | 20 ++++++-- src/Debug/Middleware/DebugFallbackHandler.php | 46 ------------------- .../MiddlewareDispatcherMiddleware.php | 24 ++++++++++ src/Debug/Provider/DebugApiProvider.php | 2 +- 6 files changed, 46 insertions(+), 60 deletions(-) delete mode 100644 src/Debug/Middleware/DebugFallbackHandler.php create mode 100644 src/Debug/Middleware/MiddlewareDispatcherMiddleware.php diff --git a/config/di-web.php b/config/di-web.php index 5f59c41..0eff373 100644 --- a/config/di-web.php +++ b/config/di-web.php @@ -5,7 +5,7 @@ use Cycle\Database\DatabaseProviderInterface; use Psr\Container\ContainerInterface; use Yiisoft\Db\Connection\ConnectionInterface; -use Yiisoft\Yii\Debug\Api\Debug\Middleware\DebugFallbackHandler; +use Yiisoft\Yii\Debug\Api\Debug\Http\DebugHttpApplicationWrapper; use Yiisoft\Yii\Debug\Api\Debug\Repository\CollectorRepository; use Yiisoft\Yii\Debug\Api\Debug\Repository\CollectorRepositoryInterface; use Yiisoft\Yii\Debug\Api\Inspector\Database\Cycle\CycleSchemaProvider; @@ -35,9 +35,9 @@ ) ); }, - DebugFallbackHandler::class => [ + DebugHttpApplicationWrapper::class => [ '__construct()' => [ - 'middlewareDefinitions' => $params['yiisoft/yii-debug-api']['fallbackHandler']['middlewares'], + 'middlewareDefinitions' => $params['yiisoft/yii-debug-api']['middlewares'], ], ], ]; diff --git a/config/params.php b/config/params.php index a11a878..9630fc8 100644 --- a/config/params.php +++ b/config/params.php @@ -27,6 +27,9 @@ 'enabled' => true, 'allowedIPs' => ['127.0.0.1', '::1'], 'allowedHosts' => [], + 'middlewares' => [ + DebugHeaders::class, + ], 'inspector' => [ 'commandMap' => [ 'tests' => $testCommands, @@ -35,11 +38,6 @@ ], ], ], - 'fallbackHandler' => [ - 'middlewares' => [ - DebugHeaders::class, - ], - ], ], 'yiisoft/yii-swagger' => [ 'annotation-paths' => [ diff --git a/src/Debug/Http/DebugHttpApplicationWrapper.php b/src/Debug/Http/DebugHttpApplicationWrapper.php index e634745..39e9ec4 100644 --- a/src/Debug/Http/DebugHttpApplicationWrapper.php +++ b/src/Debug/Http/DebugHttpApplicationWrapper.php @@ -5,21 +5,31 @@ namespace Yiisoft\Yii\Debug\Api\Debug\Http; use Closure; -use Yiisoft\Yii\Debug\Api\Debug\Middleware\DebugFallbackHandler; +use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher; +use Yiisoft\Yii\Debug\Api\Debug\Middleware\MiddlewareDispatcherMiddleware; use Yiisoft\Yii\Http\Application; final readonly class DebugHttpApplicationWrapper { public function __construct( - private DebugFallbackHandler $debugFallbackHandler + private MiddlewareDispatcher $middlewareDispatcher, + private array $middlewareDefinitions, ) { } public function wrap(Application $application): void { - $debugFallbackHandler = $this->debugFallbackHandler; - $closure = Closure::bind(static function (Application $application) use ($debugFallbackHandler) { - $application->fallbackHandler = $debugFallbackHandler->withFallbackRequestHandler($application->fallbackHandler); + $middlewareDispatcher = $this->middlewareDispatcher; + $middlewareDefinitions = $this->middlewareDefinitions; + + $closure = Closure::bind(static function (Application $application) use ( + $middlewareDispatcher, + $middlewareDefinitions, + ) { + $application->dispatcher = $middlewareDispatcher->withMiddlewares([ + ...$middlewareDefinitions, + ['class' => MiddlewareDispatcherMiddleware::class, '$middlewareDispatcher' => $application->dispatcher], + ]);; }, null, $application); $closure($application); diff --git a/src/Debug/Middleware/DebugFallbackHandler.php b/src/Debug/Middleware/DebugFallbackHandler.php deleted file mode 100644 index f908fe2..0000000 --- a/src/Debug/Middleware/DebugFallbackHandler.php +++ /dev/null @@ -1,46 +0,0 @@ -middlewareDispatcher - ->withMiddlewares($this->middlewareDefinitions) - ->dispatch($request, $handler); - } - - public function handle(ServerRequestInterface $request): ResponseInterface - { - if ($this->fallbackHandler === null) { - throw new \RuntimeException('No fallback handler defined.'); - } - - return $this->process($request, $this->fallbackHandler); - } - - public function withFallbackRequestHandler(RequestHandlerInterface $fallbackHandler): self - { - $new = clone $this; - $new->fallbackHandler = $fallbackHandler; - - return $new; - } -} diff --git a/src/Debug/Middleware/MiddlewareDispatcherMiddleware.php b/src/Debug/Middleware/MiddlewareDispatcherMiddleware.php new file mode 100644 index 0000000..4cdaf74 --- /dev/null +++ b/src/Debug/Middleware/MiddlewareDispatcherMiddleware.php @@ -0,0 +1,24 @@ +middlewareDispatcher->dispatch($request, $handler); + } +} diff --git a/src/Debug/Provider/DebugApiProvider.php b/src/Debug/Provider/DebugApiProvider.php index 9673710..3bc14f2 100644 --- a/src/Debug/Provider/DebugApiProvider.php +++ b/src/Debug/Provider/DebugApiProvider.php @@ -24,7 +24,7 @@ public function getDefinitions(): array public function getExtensions(): array { return [ - RouteCollectorInterface::class => static function (RouteCollectorInterface $routeCollector) { + RouteCollectorInterface::class => static function (ContainerInterface $container, RouteCollectorInterface $routeCollector) { $routeCollector->prependMiddleware(DebugHeaders::class); return $routeCollector; }, From a449c3d5b100e108c91582672eced835093193c4 Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Fri, 14 Jun 2024 14:04:13 +0300 Subject: [PATCH 06/10] Fix test --- tests/Unit/Debug/Provider/DebugApiProviderTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/Unit/Debug/Provider/DebugApiProviderTest.php b/tests/Unit/Debug/Provider/DebugApiProviderTest.php index 0ca8861..7b99d1a 100644 --- a/tests/Unit/Debug/Provider/DebugApiProviderTest.php +++ b/tests/Unit/Debug/Provider/DebugApiProviderTest.php @@ -5,6 +5,7 @@ namespace Yiisoft\Yii\Debug\Api\Tests\Unit\Debug\Provider; use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerInterface; use Yiisoft\Router\RouteCollectorInterface; use Yiisoft\Yii\Debug\Api\Debug\Middleware\DebugHeaders; use Yiisoft\Yii\Debug\Api\Debug\Provider\DebugApiProvider; @@ -25,12 +26,13 @@ public function testExtension(): void $routeCollectorDecorator = $extensions[RouteCollectorInterface::class]; $this->assertIsCallable($routeCollectorDecorator); + $container = $this->createMock(ContainerInterface::class); $routeCollector = $this->createMock(RouteCollectorInterface::class); $routeCollector->expects($this->once()) ->method('prependMiddleware') ->with(DebugHeaders::class) ->willReturn($routeCollector); - $this->assertSame($routeCollector, $routeCollectorDecorator($routeCollector)); + $this->assertSame($routeCollector, $routeCollectorDecorator($container, $routeCollector)); } } From 2c7b01b4ed84c4ac8baf277246e3cdba773463df Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Fri, 14 Jun 2024 14:29:53 +0300 Subject: [PATCH 07/10] Add workaround for Subfolder middleware --- config/di-web.php | 10 ++++++++-- ...Wrapper.php => HttpApplicationWrapper.php} | 2 +- src/Debug/Http/RouteCollectorWrapper.php | 20 +++++++++++++++++++ src/Debug/Provider/DebugApiProvider.php | 18 ++++++++++++----- 4 files changed, 42 insertions(+), 8 deletions(-) rename src/Debug/Http/{DebugHttpApplicationWrapper.php => HttpApplicationWrapper.php} (95%) create mode 100644 src/Debug/Http/RouteCollectorWrapper.php diff --git a/config/di-web.php b/config/di-web.php index 0eff373..1e17aec 100644 --- a/config/di-web.php +++ b/config/di-web.php @@ -5,7 +5,8 @@ use Cycle\Database\DatabaseProviderInterface; use Psr\Container\ContainerInterface; use Yiisoft\Db\Connection\ConnectionInterface; -use Yiisoft\Yii\Debug\Api\Debug\Http\DebugHttpApplicationWrapper; +use Yiisoft\Yii\Debug\Api\Debug\Http\HttpApplicationWrapper; +use Yiisoft\Yii\Debug\Api\Debug\Http\RouteCollectorWrapper; use Yiisoft\Yii\Debug\Api\Debug\Repository\CollectorRepository; use Yiisoft\Yii\Debug\Api\Debug\Repository\CollectorRepositoryInterface; use Yiisoft\Yii\Debug\Api\Inspector\Database\Cycle\CycleSchemaProvider; @@ -35,7 +36,12 @@ ) ); }, - DebugHttpApplicationWrapper::class => [ + HttpApplicationWrapper::class => [ + '__construct()' => [ + 'middlewareDefinitions' => $params['yiisoft/yii-debug-api']['middlewares'], + ], + ], + RouteCollectorWrapper::class => [ '__construct()' => [ 'middlewareDefinitions' => $params['yiisoft/yii-debug-api']['middlewares'], ], diff --git a/src/Debug/Http/DebugHttpApplicationWrapper.php b/src/Debug/Http/HttpApplicationWrapper.php similarity index 95% rename from src/Debug/Http/DebugHttpApplicationWrapper.php rename to src/Debug/Http/HttpApplicationWrapper.php index 39e9ec4..c3b9b5a 100644 --- a/src/Debug/Http/DebugHttpApplicationWrapper.php +++ b/src/Debug/Http/HttpApplicationWrapper.php @@ -9,7 +9,7 @@ use Yiisoft\Yii\Debug\Api\Debug\Middleware\MiddlewareDispatcherMiddleware; use Yiisoft\Yii\Http\Application; -final readonly class DebugHttpApplicationWrapper +final readonly class HttpApplicationWrapper { public function __construct( private MiddlewareDispatcher $middlewareDispatcher, diff --git a/src/Debug/Http/RouteCollectorWrapper.php b/src/Debug/Http/RouteCollectorWrapper.php new file mode 100644 index 0000000..c58b4c0 --- /dev/null +++ b/src/Debug/Http/RouteCollectorWrapper.php @@ -0,0 +1,20 @@ +prependMiddleware(...$this->middlewareDefinitions); + } +} diff --git a/src/Debug/Provider/DebugApiProvider.php b/src/Debug/Provider/DebugApiProvider.php index 3bc14f2..7de2b6a 100644 --- a/src/Debug/Provider/DebugApiProvider.php +++ b/src/Debug/Provider/DebugApiProvider.php @@ -7,8 +7,8 @@ use Psr\Container\ContainerInterface; use Yiisoft\Di\ServiceProviderInterface; use Yiisoft\Router\RouteCollectorInterface; -use Yiisoft\Yii\Debug\Api\Debug\Http\DebugHttpApplicationWrapper; -use Yiisoft\Yii\Debug\Api\Debug\Middleware\DebugHeaders; +use Yiisoft\Yii\Debug\Api\Debug\Http\HttpApplicationWrapper; +use Yiisoft\Yii\Debug\Api\Debug\Http\RouteCollectorWrapper; use Yiisoft\Yii\Http\Application; final class DebugApiProvider implements ServiceProviderInterface @@ -24,12 +24,20 @@ public function getDefinitions(): array public function getExtensions(): array { return [ - RouteCollectorInterface::class => static function (ContainerInterface $container, RouteCollectorInterface $routeCollector) { - $routeCollector->prependMiddleware(DebugHeaders::class); + RouteCollectorInterface::class => static function ( + ContainerInterface $container, + RouteCollectorInterface $routeCollector + ) { + /** + * Register debug middlewares twice because a `Subfolder` middleware may rewrite base URL + */ + $routerCollectionWrapper = $container->get(RouteCollectorWrapper::class); + $routerCollectionWrapper->wrap($routeCollector); + return $routeCollector; }, Application::class => static function (ContainerInterface $container, Application $application) { - $applicationWrapper = $container->get(DebugHttpApplicationWrapper::class); + $applicationWrapper = $container->get(HttpApplicationWrapper::class); $applicationWrapper->wrap($application); return $application; From 0ef8f0cff87a3be9c0452bd1db4fdc74e920df21 Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Fri, 14 Jun 2024 14:34:21 +0300 Subject: [PATCH 08/10] Fix tests --- tests/Unit/Debug/Provider/DebugApiProviderTest.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/Unit/Debug/Provider/DebugApiProviderTest.php b/tests/Unit/Debug/Provider/DebugApiProviderTest.php index 7b99d1a..1d26116 100644 --- a/tests/Unit/Debug/Provider/DebugApiProviderTest.php +++ b/tests/Unit/Debug/Provider/DebugApiProviderTest.php @@ -7,6 +7,7 @@ use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; use Yiisoft\Router\RouteCollectorInterface; +use Yiisoft\Yii\Debug\Api\Debug\Http\RouteCollectorWrapper; use Yiisoft\Yii\Debug\Api\Debug\Middleware\DebugHeaders; use Yiisoft\Yii\Debug\Api\Debug\Provider\DebugApiProvider; @@ -26,11 +27,18 @@ public function testExtension(): void $routeCollectorDecorator = $extensions[RouteCollectorInterface::class]; $this->assertIsCallable($routeCollectorDecorator); + $middlewares = [DebugHeaders::class]; + $container = $this->createMock(ContainerInterface::class); + $container->expects($this->once()) + ->method('get') + ->with(RouteCollectorWrapper::class) + ->willReturn(new RouteCollectorWrapper($middlewares)); + $routeCollector = $this->createMock(RouteCollectorInterface::class); $routeCollector->expects($this->once()) ->method('prependMiddleware') - ->with(DebugHeaders::class) + ->with(...$middlewares) ->willReturn($routeCollector); $this->assertSame($routeCollector, $routeCollectorDecorator($container, $routeCollector)); From f233d9e04d6781c0273d125d7a28fa9f00f966ed Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Fri, 14 Jun 2024 14:35:23 +0300 Subject: [PATCH 09/10] Fix tests --- src/Debug/Http/RouteCollectorWrapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Debug/Http/RouteCollectorWrapper.php b/src/Debug/Http/RouteCollectorWrapper.php index c58b4c0..c31fe75 100644 --- a/src/Debug/Http/RouteCollectorWrapper.php +++ b/src/Debug/Http/RouteCollectorWrapper.php @@ -6,7 +6,7 @@ use Yiisoft\Router\RouteCollectorInterface; -final readonly class RouteCollectorWrapper +final class RouteCollectorWrapper { public function __construct( private array $middlewareDefinitions, From 2a465435c73a21c9a792dfea4ca953c33825353c Mon Sep 17 00:00:00 2001 From: Dmitrii Derepko Date: Fri, 14 Jun 2024 14:36:53 +0300 Subject: [PATCH 10/10] Add middleware dispatcher --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index f3c9455..9823507 100644 --- a/composer.json +++ b/composer.json @@ -51,6 +51,7 @@ "yiisoft/di": "^1.0", "yiisoft/friendly-exception": "^1.1", "yiisoft/http": "^1.2", + "yiisoft/middleware-dispatcher": "^5.2", "yiisoft/router": "^3.0", "yiisoft/translator": "^3.0", "yiisoft/var-dumper": "^1.4",