From ca2feb620333c355dc971c81a90a5201f737ca41 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Wed, 3 Sep 2025 16:04:48 +0300 Subject: [PATCH 1/3] implement --- .../AllowedMethodsHandler.php | 26 ++++++++++++ .../MethodFailureHandler.php | 40 +++++++++++++++++++ .../MethodFailureHandlerInterface.php | 18 +++++++++ .../MethodNotAllowedHandler.php | 26 ++++++++++++ src/Middleware/Router.php | 22 +++++----- 5 files changed, 121 insertions(+), 11 deletions(-) create mode 100644 src/MethodFailureHandler/AllowedMethodsHandler.php create mode 100644 src/MethodFailureHandler/MethodFailureHandler.php create mode 100644 src/MethodFailureHandler/MethodFailureHandlerInterface.php create mode 100644 src/MethodFailureHandler/MethodNotAllowedHandler.php diff --git a/src/MethodFailureHandler/AllowedMethodsHandler.php b/src/MethodFailureHandler/AllowedMethodsHandler.php new file mode 100644 index 00000000..d81be086 --- /dev/null +++ b/src/MethodFailureHandler/AllowedMethodsHandler.php @@ -0,0 +1,26 @@ +responseFactory + ->createResponse(Status::NO_CONTENT) + ->withHeader(Header::ALLOW, implode(', ', $allowedMethods)); + } +} diff --git a/src/MethodFailureHandler/MethodFailureHandler.php b/src/MethodFailureHandler/MethodFailureHandler.php new file mode 100644 index 00000000..6f085488 --- /dev/null +++ b/src/MethodFailureHandler/MethodFailureHandler.php @@ -0,0 +1,40 @@ +allowedMethodsHandler = $allowedMethodsHandler ?? new AllowedMethodsHandler($responseFactory); + $this->methodNotAllowedHandler = $methodNotAllowedHandler ?? new MethodNotAllowedHandler($responseFactory); + } + + /** + * @param string[] $allowedMethods + */ + public function handle(ServerRequestInterface $request, array $allowedMethods): ResponseInterface + { + if (empty($allowedMethods)) { + throw new InvalidArgumentException("Allowed methods can't be empty array."); + } + + return $request->getMethod() === Method::OPTIONS + ? $this->allowedMethodsHandler->handle($request, $allowedMethods) + : $this->methodNotAllowedHandler->handle($request, $allowedMethods); + } +} diff --git a/src/MethodFailureHandler/MethodFailureHandlerInterface.php b/src/MethodFailureHandler/MethodFailureHandlerInterface.php new file mode 100644 index 00000000..ac62502f --- /dev/null +++ b/src/MethodFailureHandler/MethodFailureHandlerInterface.php @@ -0,0 +1,18 @@ + $allowedMethods + */ + public function handle(ServerRequestInterface $request, array $allowedMethods): ResponseInterface; +} diff --git a/src/MethodFailureHandler/MethodNotAllowedHandler.php b/src/MethodFailureHandler/MethodNotAllowedHandler.php new file mode 100644 index 00000000..215f079f --- /dev/null +++ b/src/MethodFailureHandler/MethodNotAllowedHandler.php @@ -0,0 +1,26 @@ +responseFactory + ->createResponse(Status::METHOD_NOT_ALLOWED) + ->withHeader(Header::ALLOW, implode(', ', $allowedMethods)); + } +} diff --git a/src/Middleware/Router.php b/src/Middleware/Router.php index 78d130cb..3e88458c 100644 --- a/src/Middleware/Router.php +++ b/src/Middleware/Router.php @@ -15,20 +15,27 @@ use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher; use Yiisoft\Middleware\Dispatcher\MiddlewareFactory; use Yiisoft\Router\CurrentRoute; +use Yiisoft\Router\MethodFailureHandler\MethodFailureHandler; use Yiisoft\Router\UrlMatcherInterface; final class Router implements MiddlewareInterface { private readonly MiddlewareDispatcher $dispatcher; + private readonly MethodFailureHandler|null $methodFailureHandler; public function __construct( private readonly UrlMatcherInterface $matcher, - private readonly ResponseFactoryInterface $responseFactory, + ResponseFactoryInterface $responseFactory, MiddlewareFactory $middlewareFactory, private readonly CurrentRoute $currentRoute, - ?EventDispatcherInterface $eventDispatcher = null + ?EventDispatcherInterface $eventDispatcher = null, + MethodFailureHandler|false|null $methodFailureHandler = null, ) { $this->dispatcher = new MiddlewareDispatcher($middlewareFactory, $eventDispatcher); + $this->methodFailureHandler = $methodFailureHandler === false + ? null + : $methodFailureHandler ?? new MethodFailureHandler($responseFactory); + } public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface @@ -37,15 +44,8 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $this->currentRoute->setUri($request->getUri()); - if ($result->isMethodFailure()) { - if ($request->getMethod() === Method::OPTIONS) { - return $this->responseFactory - ->createResponse(Status::NO_CONTENT) - ->withHeader('Allow', implode(', ', $result->methods())); - } - return $this->responseFactory - ->createResponse(Status::METHOD_NOT_ALLOWED) - ->withHeader('Allow', implode(', ', $result->methods())); + if ($result->isMethodFailure() && $this->methodFailureHandler !== null) { + return $this->methodFailureHandler->handle($request, $result->methods()); } if (!$result->isSuccess()) { From d3ce11618848c6c8abfa6c19bc9f0212f189679a Mon Sep 17 00:00:00 2001 From: StyleCI Bot Date: Wed, 3 Sep 2025 13:05:06 +0000 Subject: [PATCH 2/3] Apply fixes from StyleCI --- src/Middleware/Router.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Middleware/Router.php b/src/Middleware/Router.php index 3e88458c..bbd5a6b9 100644 --- a/src/Middleware/Router.php +++ b/src/Middleware/Router.php @@ -10,8 +10,6 @@ use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; -use Yiisoft\Http\Method; -use Yiisoft\Http\Status; use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher; use Yiisoft\Middleware\Dispatcher\MiddlewareFactory; use Yiisoft\Router\CurrentRoute; @@ -32,10 +30,9 @@ public function __construct( MethodFailureHandler|false|null $methodFailureHandler = null, ) { $this->dispatcher = new MiddlewareDispatcher($middlewareFactory, $eventDispatcher); - $this->methodFailureHandler = $methodFailureHandler === false - ? null - : $methodFailureHandler ?? new MethodFailureHandler($responseFactory); - + $this->methodFailureHandler = $methodFailureHandler === false + ? null + : $methodFailureHandler ?? new MethodFailureHandler($responseFactory); } public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface From 5b5d2b5f4f90bf32d9daeb85061938024c953452 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Wed, 3 Sep 2025 16:49:03 +0300 Subject: [PATCH 3/3] improve --- .../AllowedMethodsHandler.php | 26 --------- .../MethodFailureHandler.php | 40 -------------- .../MethodFailureHandlerInterface.php | 2 - .../MethodNotAllowedHandler.php | 26 --------- .../StandardMethodFailureHandler.php | 55 +++++++++++++++++++ src/Middleware/Router.php | 9 +-- 6 files changed, 60 insertions(+), 98 deletions(-) delete mode 100644 src/MethodFailureHandler/AllowedMethodsHandler.php delete mode 100644 src/MethodFailureHandler/MethodFailureHandler.php delete mode 100644 src/MethodFailureHandler/MethodNotAllowedHandler.php create mode 100644 src/MethodFailureHandler/StandardMethodFailureHandler.php diff --git a/src/MethodFailureHandler/AllowedMethodsHandler.php b/src/MethodFailureHandler/AllowedMethodsHandler.php deleted file mode 100644 index d81be086..00000000 --- a/src/MethodFailureHandler/AllowedMethodsHandler.php +++ /dev/null @@ -1,26 +0,0 @@ -responseFactory - ->createResponse(Status::NO_CONTENT) - ->withHeader(Header::ALLOW, implode(', ', $allowedMethods)); - } -} diff --git a/src/MethodFailureHandler/MethodFailureHandler.php b/src/MethodFailureHandler/MethodFailureHandler.php deleted file mode 100644 index 6f085488..00000000 --- a/src/MethodFailureHandler/MethodFailureHandler.php +++ /dev/null @@ -1,40 +0,0 @@ -allowedMethodsHandler = $allowedMethodsHandler ?? new AllowedMethodsHandler($responseFactory); - $this->methodNotAllowedHandler = $methodNotAllowedHandler ?? new MethodNotAllowedHandler($responseFactory); - } - - /** - * @param string[] $allowedMethods - */ - public function handle(ServerRequestInterface $request, array $allowedMethods): ResponseInterface - { - if (empty($allowedMethods)) { - throw new InvalidArgumentException("Allowed methods can't be empty array."); - } - - return $request->getMethod() === Method::OPTIONS - ? $this->allowedMethodsHandler->handle($request, $allowedMethods) - : $this->methodNotAllowedHandler->handle($request, $allowedMethods); - } -} diff --git a/src/MethodFailureHandler/MethodFailureHandlerInterface.php b/src/MethodFailureHandler/MethodFailureHandlerInterface.php index ac62502f..94067039 100644 --- a/src/MethodFailureHandler/MethodFailureHandlerInterface.php +++ b/src/MethodFailureHandler/MethodFailureHandlerInterface.php @@ -11,8 +11,6 @@ interface MethodFailureHandlerInterface { /** * @param string[] $allowedMethods - * - * @psalm-param non-empty-array $allowedMethods */ public function handle(ServerRequestInterface $request, array $allowedMethods): ResponseInterface; } diff --git a/src/MethodFailureHandler/MethodNotAllowedHandler.php b/src/MethodFailureHandler/MethodNotAllowedHandler.php deleted file mode 100644 index 215f079f..00000000 --- a/src/MethodFailureHandler/MethodNotAllowedHandler.php +++ /dev/null @@ -1,26 +0,0 @@ -responseFactory - ->createResponse(Status::METHOD_NOT_ALLOWED) - ->withHeader(Header::ALLOW, implode(', ', $allowedMethods)); - } -} diff --git a/src/MethodFailureHandler/StandardMethodFailureHandler.php b/src/MethodFailureHandler/StandardMethodFailureHandler.php new file mode 100644 index 00000000..838b3962 --- /dev/null +++ b/src/MethodFailureHandler/StandardMethodFailureHandler.php @@ -0,0 +1,55 @@ +getMethod() === Method::OPTIONS + ? $this->createAllowedMethodsResponse($allowedMethods) + : $this->createMethodNotAllowedResponse($allowedMethods); + } + + /** + * @param string[] $allowedMethods + */ + private function createAllowedMethodsResponse(array $allowedMethods): ResponseInterface + { + return $this->responseFactory + ->createResponse(Status::NO_CONTENT) + ->withHeader(Header::ALLOW, implode(', ', $allowedMethods)); + } + + /** + * @param string[] $allowedMethods + */ + private function createMethodNotAllowedResponse(array $allowedMethods): ResponseInterface + { + return $this->responseFactory + ->createResponse(Status::METHOD_NOT_ALLOWED) + ->withHeader(Header::ALLOW, implode(', ', $allowedMethods)); + } +} diff --git a/src/Middleware/Router.php b/src/Middleware/Router.php index bbd5a6b9..2f483612 100644 --- a/src/Middleware/Router.php +++ b/src/Middleware/Router.php @@ -13,13 +13,14 @@ use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher; use Yiisoft\Middleware\Dispatcher\MiddlewareFactory; use Yiisoft\Router\CurrentRoute; -use Yiisoft\Router\MethodFailureHandler\MethodFailureHandler; +use Yiisoft\Router\MethodFailureHandler\StandardMethodFailureHandler; +use Yiisoft\Router\MethodFailureHandler\MethodFailureHandlerInterface; use Yiisoft\Router\UrlMatcherInterface; final class Router implements MiddlewareInterface { private readonly MiddlewareDispatcher $dispatcher; - private readonly MethodFailureHandler|null $methodFailureHandler; + private readonly MethodFailureHandlerInterface|null $methodFailureHandler; public function __construct( private readonly UrlMatcherInterface $matcher, @@ -27,12 +28,12 @@ public function __construct( MiddlewareFactory $middlewareFactory, private readonly CurrentRoute $currentRoute, ?EventDispatcherInterface $eventDispatcher = null, - MethodFailureHandler|false|null $methodFailureHandler = null, + MethodFailureHandlerInterface|false|null $methodFailureHandler = null, ) { $this->dispatcher = new MiddlewareDispatcher($middlewareFactory, $eventDispatcher); $this->methodFailureHandler = $methodFailureHandler === false ? null - : $methodFailureHandler ?? new MethodFailureHandler($responseFactory); + : $methodFailureHandler ?? new StandardMethodFailureHandler($responseFactory); } public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface