diff --git a/src/Lunr/Corona/Request.php b/src/Lunr/Corona/Request.php index ee48e64c..f20750a7 100644 --- a/src/Lunr/Corona/Request.php +++ b/src/Lunr/Corona/Request.php @@ -10,6 +10,9 @@ namespace Lunr\Corona; +use BackedEnum; +use RuntimeException; + /** * Request abstraction class. * Manages access to $_POST, $_GET values, as well as @@ -64,7 +67,7 @@ class Request * * @var array */ - protected readonly array $request; + protected array $request; /** * Stored $_FILES values @@ -90,6 +93,12 @@ class Request */ protected readonly RequestParserInterface $parser; + /** + * Set of registered request value parsers. + * @var array + */ + protected array $parsers; + /** * The request values to mock. * @var array @@ -103,7 +112,8 @@ class Request */ public function __construct($parser) { - $this->parser = $parser; + $this->parser = $parser; + $this->parsers = []; $this->request = $parser->parse_request(); $this->server = $parser->parse_server(); @@ -122,8 +132,8 @@ public function __construct($parser) */ public function __destruct() { - // Intentionally not unsetting $this->mock and $this->raw_data, since - // that may break access to mocked request values during PHP shutdown. + // Intentionally not unsetting request value properties, since + // that may break access to them during PHP shutdown. } /** @@ -154,6 +164,47 @@ public function __get(string $name) } } + /** + * Get a request value. + * + * @param BackedEnum&RequestValueInterface $key The identifier/name of the request value to get + * + * @return scalar The requested value + */ + public function get(BackedEnum&RequestValueInterface $key): bool|float|int|string|null + { + if (array_key_exists($key->value, $this->mock)) + { + return $this->mock[$key->value]; + } + + if (array_key_exists($key->value, $this->request)) + { + return $this->request[$key->value]; + } + + if (!isset($this->parsers[$key::class])) + { + throw new RuntimeException('No parser registered for requested value ("' . $key->value . '")!'); + } + + $this->request[$key->value] = $this->parsers[$key::class]->get($key); + + return $this->request[$key->value]; + } + + /** + * Register a request value parser. + * + * @param RequestValueParserInterface $parser A request value parser + * + * @return void + */ + public function register_parser(RequestValueParserInterface $parser): void + { + $this->parsers[$parser->get_request_value_type()] = $parser; + } + /** * Override request values detected from the request parser. * Replace all previous mock values. diff --git a/src/Lunr/Corona/RequestValueInterface.php b/src/Lunr/Corona/RequestValueInterface.php new file mode 100644 index 00000000..48fe4581 --- /dev/null +++ b/src/Lunr/Corona/RequestValueInterface.php @@ -0,0 +1,20 @@ + diff --git a/src/Lunr/Corona/RequestValueParserInterface.php b/src/Lunr/Corona/RequestValueParserInterface.php new file mode 100644 index 00000000..e94411d6 --- /dev/null +++ b/src/Lunr/Corona/RequestValueParserInterface.php @@ -0,0 +1,38 @@ + diff --git a/src/Lunr/Corona/Tests/Helpers/MockRequestValue.php b/src/Lunr/Corona/Tests/Helpers/MockRequestValue.php new file mode 100644 index 00000000..a143e99d --- /dev/null +++ b/src/Lunr/Corona/Tests/Helpers/MockRequestValue.php @@ -0,0 +1,27 @@ + diff --git a/src/Lunr/Corona/Tests/RequestBaseTest.php b/src/Lunr/Corona/Tests/RequestBaseTest.php index 6c52d78a..02e793fa 100644 --- a/src/Lunr/Corona/Tests/RequestBaseTest.php +++ b/src/Lunr/Corona/Tests/RequestBaseTest.php @@ -10,6 +10,8 @@ namespace Lunr\Corona\Tests; +use Lunr\Corona\RequestValueParserInterface; + /** * Basic tests for the case of empty superglobals. * @@ -95,6 +97,29 @@ public function testRequestDefaultValues($key, $value): void $this->assertEquals($value, $request[$key]); } + /** + * Test that register_parser() registers a parser. + * + * @covers Lunr\Corona\Request::register_parser + */ + public function testRegisterParser(): void + { + $parser = $this->getMockBuilder(RequestValueParserInterface::class) + ->getMock(); + + $parser->expects($this->once()) + ->method('get_request_value_type') + ->willReturn('Lunr\Corona\Parser\Foo\Foo'); + + $this->class->register_parser($parser); + + $parsers = $this->get_reflection_property_value('parsers'); + + $this->assertCount(1, $parsers); + $this->assertArrayHasKey('Lunr\Corona\Parser\Foo\Foo', $parsers); + $this->assertEquals($parser, $parsers['Lunr\Corona\Parser\Foo\Foo']); + } + } ?> diff --git a/src/Lunr/Corona/Tests/RequestGetValueTest.php b/src/Lunr/Corona/Tests/RequestGetValueTest.php new file mode 100644 index 00000000..097f202a --- /dev/null +++ b/src/Lunr/Corona/Tests/RequestGetValueTest.php @@ -0,0 +1,106 @@ + 'bar', + ]; + + $this->set_reflection_property_value('request', $cache); + + $value = $this->class->get(MockRequestValue::Foo); + + $this->assertEquals('bar', $value); + } + + /** + * Check that get() returns mocked values. + * + * @covers Lunr\Corona\Request::get + */ + public function testGetWithMockedValue(): void + { + $cache = [ + 'foo' => 'bar', + ]; + + $mock = [ + 'foo' => 'baz', + ]; + + $this->set_reflection_property_value('request', $cache); + $this->set_reflection_property_value('mock', $mock); + + $value = $this->class->get(MockRequestValue::Foo); + + $this->assertEquals('baz', $value); + } + + /** + * Check that get() throws an exception for a value with an unregistered parser. + * + * @covers Lunr\Corona\Request::get + */ + public function testGetWithUncachedValueAndUnregisteredParserThrowsException(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('No parser registered for requested value ("foo")!'); + + $this->class->get(MockRequestValue::Foo); + } + + /** + * Check that get() returns uncached values. + * + * @covers Lunr\Corona\Request::get + */ + public function testGetWithUncachedValue(): void + { + $parser = $this->getMockBuilder(RequestValueParserInterface::class) + ->getMock(); + + $parsers = [ + MockRequestValue::class => $parser, + ]; + + $this->set_reflection_property_value('parsers', $parsers); + + $parser->expects($this->once()) + ->method('get') + ->with(MockRequestValue::Foo) + ->willReturn('bar'); + + $value = $this->class->get(MockRequestValue::Foo); + + $this->assertEquals('bar', $value); + } + +} + +?>