diff --git a/ChangeLog.md b/ChangeLog.md index 75f0b21..2df1f5c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -3,6 +3,11 @@ Web change log ## ?.?.? / ????-??-?? +## 4.3.0 / 2024-05-20 + +* Extended `web.Request::dispatch()` to accept query strings inside path + (@thekid) + ## 4.2.0 / 2024-05-20 * Deprecated the `web.Dispatch` class. This class was never intended to diff --git a/src/main/php/web/Request.class.php b/src/main/php/web/Request.class.php index 36f5934..95352c1 100755 --- a/src/main/php/web/Request.class.php +++ b/src/main/php/web/Request.class.php @@ -255,7 +255,17 @@ public function cookies() { * @return iterable */ public function dispatch($path, $params= []) { - yield 'dispatch' => $this->uri()->using()->path($path)->params($params)->create(); + if (false === ($p= strpos($path, '?'))) { + $uri= $this->uri()->using()->path($path)->params($params); + } else { + $uri= $this->uri()->using()->path(substr($path, 0, $p))->query(substr($path, $p + 1), false); + + // Merge parameters instead of overwriting them all via `params()` + foreach ($params as $name => $value) { + $uri->param($name, $value); + } + } + yield 'dispatch' => $uri->create(); } /** diff --git a/src/test/php/web/unittest/ApplicationTest.class.php b/src/test/php/web/unittest/ApplicationTest.class.php index 530d3fd..95c7e5b 100755 --- a/src/test/php/web/unittest/ApplicationTest.class.php +++ b/src/test/php/web/unittest/ApplicationTest.class.php @@ -162,6 +162,22 @@ public function dispatch_request_without_query() { #[Test] public function dispatch_request_with_query() { + $passed= null; + $this->handle(function() use(&$passed) { + return [ + '/deref' => function($request, $response) use(&$passed) { + $passed= $request->params(); + }, + '/' => function($request, $response) { + return $request->dispatch('/deref?url=http://example.com/'); + }, + ]; + }); + Assert::equals(['url' => 'http://example.com/'], $passed); + } + + #[Test] + public function dispatch_request_with_params() { $passed= null; $this->handle(function() use(&$passed) { return [ @@ -176,6 +192,22 @@ public function dispatch_request_with_query() { Assert::equals(['url' => 'http://example.com/'], $passed); } + #[Test, Values([['/test?a=b&c=d', []], ['/test?a=b', ['c' => 'd']], ['/test', ['a' => 'b', 'c' => 'd']], ['/test?a=#', ['a' => 'b', 'c' => 'd']], ['/test', ['a' => 'b', 'c' => 'd']], ['/test?x=#', ['a' => 'b', 'c' => 'd', 'x' => null]]])] + public function dispatch_request_with_query_and_params($path, $params) { + $passed= null; + $this->handle(function() use($path, $params, &$passed) { + return [ + '/test' => function($request, $response) use(&$passed) { + $passed= $request->params(); + }, + '/' => function($request, $response) use($path, $params) { + return $request->dispatch($path, $params); + }, + ]; + }); + Assert::equals(['a' => 'b', 'c' => 'd'], $passed); + } + #[Test, Expect(class: Error::class, message: '/Internal redirect loop/')] public function dispatch_request_to_self_causes_error() { $this->assertHandled($handled, function() use(&$handled) {