From 18fd41db3e0e13316c23dd7df375d8d9a94cd5fe Mon Sep 17 00:00:00 2001 From: Howriq Date: Wed, 28 Oct 2026 14:48:36 +0200 Subject: [PATCH] add QUERY method to dot-router --- docs/book/v1/tutorials/create-route-group.md | 21 ++++++++++ docs/book/v1/tutorials/create-single-route.md | 15 ++++++- src/RouteCollector.php | 15 +++++++ src/RouteCollectorInterface.php | 6 +++ src/RouteGroupCollector.php | 16 ++++++++ src/RouteGroupCollectorInterface.php | 7 ++++ test/RouteCollectorTest.php | 16 ++++++++ test/RouteGroupCollectorTest.php | 40 +++++++++++++++++++ 8 files changed, 135 insertions(+), 1 deletion(-) diff --git a/docs/book/v1/tutorials/create-route-group.md b/docs/book/v1/tutorials/create-route-group.md index 6771000..bc0b049 100644 --- a/docs/book/v1/tutorials/create-route-group.md +++ b/docs/book/v1/tutorials/create-route-group.md @@ -171,3 +171,24 @@ $routeCollector->group('/resource', [SomeMiddleware::class, OtherMiddleware::cla - **middleware**: required, (array of) request handler(s)/middleware(s) - **name**: optional, if omitted, it will be set using the pattern **route path**^PUT - **excludeMiddleware**: optional, (array of) request handler(s)/middleware(s) to exclude for this route + +### Append a route that matches **QUERY** requests + +```php +$routeCollector->group('/resource', [SomeMiddleware::class, OtherMiddleware::class]) + ->query('', ResourceHandler::class, 'route-name'); +``` + +If this route does not need to be piped through specific middleware(s), you can specify the fourth argument `$excludeMiddleware` exclude those middlewares at route level (makes sense when there are multiple routes in a group): + +```php +$routeCollector->group('/resource', [SomeMiddleware::class, OtherMiddleware::class]) + ->query('', ResourceHandler::class, 'route-name', excludeMiddleware: SomeMiddleware::class); +``` + +`query()` method arguments: + +- **path**: required, of type string +- **middleware**: required, (array of) request handler(s)/middleware(s) +- **name**: optional, if omitted, it will be set using the pattern **route path**^QUERY +- **excludeMiddleware**: optional, (array of) request handler(s)/middleware(s) to exclude for this route diff --git a/docs/book/v1/tutorials/create-single-route.md b/docs/book/v1/tutorials/create-single-route.md index 6586f19..0b36dfa 100644 --- a/docs/book/v1/tutorials/create-single-route.md +++ b/docs/book/v1/tutorials/create-single-route.md @@ -96,6 +96,18 @@ $routeCollector->put('/resource/{id}', SomeHandler::class, 'route-name'); - **middleware**: required, (array of) request handler(s)/middleware(s) - **name**: optional, if omitted, it will be set using the pattern **route path**^PUT +### Create a route that matches **QUERY** requests + +```php +$routeCollector->query('/resource', SomeHandler::class, 'route-name'); +``` + +`query()` method arguments: + +- **path**: required, of type string +- **middleware**: required, (array of) request handler(s)/middleware(s) +- **name**: optional, if omitted, it will be set using the pattern **route path**^QUERY + ## Chain routes to the RouteCollector To facilitate creating routes, each `$routeCollector` method returns the existing `RouteCollector` instance, so you can chain routes like this: @@ -108,5 +120,6 @@ $routeCollector ->get('/order/{id}', SomeHandler::class, 'app::view-order') ->patch('/order/{id}', SomeHandler::class, 'app::update-order') ->post('/order', SomeHandler::class, 'app::create-order') - ->put('/order/{id}', SomeHandler::class, 'app::replace-order'); + ->put('/order/{id}', SomeHandler::class, 'app::replace-order') + ->query('/order', SomeHandler::class, 'app::search-order'); ``` diff --git a/src/RouteCollector.php b/src/RouteCollector.php index 4130385..47144cd 100644 --- a/src/RouteCollector.php +++ b/src/RouteCollector.php @@ -117,6 +117,21 @@ public function put( return $this; } + public function query( + string $path, + string|array|callable|MiddlewareInterface|RequestHandlerInterface $middleware, + ?string $name = null, + ): RouteCollectorInterface { + $this->routeCollector->route( + $path, + $this->middlewareFactory->prepare($middleware), + ['QUERY'], + $name + ); + + return $this; + } + /** * @return list */ diff --git a/src/RouteCollectorInterface.php b/src/RouteCollectorInterface.php index e863f11..c18d4bf 100644 --- a/src/RouteCollectorInterface.php +++ b/src/RouteCollectorInterface.php @@ -58,6 +58,12 @@ public function put( ?string $name = null, ): RouteCollectorInterface; + public function query( + string $path, + string|array|callable|MiddlewareInterface|RequestHandlerInterface $middleware, + ?string $name = null, + ): RouteCollectorInterface; + /** * @return list */ diff --git a/src/RouteGroupCollector.php b/src/RouteGroupCollector.php index db1f3c3..87db54d 100644 --- a/src/RouteGroupCollector.php +++ b/src/RouteGroupCollector.php @@ -160,6 +160,22 @@ public function put( return $this; } + public function query( + string $path, + string|array|callable|MiddlewareInterface|RequestHandlerInterface $middleware, + ?string $name = null, + array|string $excludeMiddleware = [], + ): RouteGroupCollectorInterface { + $this->routeCollector->route( + $this->preparePath($path), + $this->prepareMiddleware($middleware, $excludeMiddleware), + ['QUERY'], + $name + ); + + return $this; + } + /** * @return list */ diff --git a/src/RouteGroupCollectorInterface.php b/src/RouteGroupCollectorInterface.php index e075e72..c981366 100644 --- a/src/RouteGroupCollectorInterface.php +++ b/src/RouteGroupCollectorInterface.php @@ -70,6 +70,13 @@ public function put( array|string $excludeMiddleware = [], ): RouteGroupCollectorInterface; + public function query( + string $path, + string|array|callable|MiddlewareInterface|RequestHandlerInterface $middleware, + ?string $name = null, + array|string $excludeMiddleware = [], + ): RouteGroupCollectorInterface; + /** * @return list */ diff --git a/test/RouteCollectorTest.php b/test/RouteCollectorTest.php index c4f9b30..777332a 100644 --- a/test/RouteCollectorTest.php +++ b/test/RouteCollectorTest.php @@ -194,6 +194,22 @@ public static function methodProvider(): array 'generatedName' => 'app::put', 'allowedMethods' => ['PUT'], ], + [ + 'requestMethod' => 'query', + 'routePath' => '/query', + 'routeName' => null, + 'generatedPath' => '/query', + 'generatedName' => '/query^QUERY', + 'allowedMethods' => ['QUERY'], + ], + [ + 'requestMethod' => 'query', + 'routePath' => '/query', + 'routeName' => 'app::query', + 'generatedPath' => '/query', + 'generatedName' => 'app::query', + 'allowedMethods' => ['QUERY'], + ], ]; } diff --git a/test/RouteGroupCollectorTest.php b/test/RouteGroupCollectorTest.php index 10181ad..0c3bb3c 100644 --- a/test/RouteGroupCollectorTest.php +++ b/test/RouteGroupCollectorTest.php @@ -349,6 +349,46 @@ public static function methodProvider(): array 'allowedMethods' => ['PUT'], 'excludeMiddleware' => [MiddlewareInterface::class], ], + [ + 'groupPrefix' => '/group', + 'requestMethod' => 'query', + 'routePath' => '/query', + 'routeName' => null, + 'generatedPath' => '/group/query', + 'generatedName' => '/group/query^QUERY', + 'allowedMethods' => ['QUERY'], + 'excludeMiddleware' => [], + ], + [ + 'groupPrefix' => '/group', + 'requestMethod' => 'query', + 'routePath' => '/query', + 'routeName' => null, + 'generatedPath' => '/group/query', + 'generatedName' => '/group/query^QUERY', + 'allowedMethods' => ['QUERY'], + 'excludeMiddleware' => [MiddlewareInterface::class], + ], + [ + 'groupPrefix' => '/group', + 'requestMethod' => 'query', + 'routePath' => '/query', + 'routeName' => 'app::group-query', + 'generatedPath' => '/group/query', + 'generatedName' => 'app::group-query', + 'allowedMethods' => ['QUERY'], + 'excludeMiddleware' => [], + ], + [ + 'groupPrefix' => '/group', + 'requestMethod' => 'query', + 'routePath' => '/query', + 'routeName' => 'app::group-query', + 'generatedPath' => '/group/query', + 'generatedName' => 'app::group-query', + 'allowedMethods' => ['QUERY'], + 'excludeMiddleware' => [MiddlewareInterface::class], + ], ]; }