diff --git a/src/Route.php b/src/Route.php new file mode 100644 index 00000000..e3359cce --- /dev/null +++ b/src/Route.php @@ -0,0 +1,48 @@ +query = $query; + $this->route = $route; + $this->regex = $this->getRegex(); + } + + public function handle($query) + { + $query = trim($query, '/'); + if (!preg_match($this->regex, $query, $matches)) + return false; + $routeArguments = $this->getRouteArguments($matches); + call_user_func_array($this->route, $routeArguments); + return true; + } + + private function getRegex() + { + $quotedQuery = preg_quote(trim($this->query, '/'), '/'); + return '/^' . preg_replace('/\\\?\:([a-zA-Z_-]*)/', '(?P<\1>[^\/]+)', $quotedQuery) . '$/i'; + } + + private function getRouteArguments($matches) + { + $reflectionFunction = new \ReflectionFunction($this->route); + $arguments = []; + foreach ($reflectionFunction->getParameters() as $reflectionParameter) + { + $key = $reflectionParameter->name; + if (isset($matches[$key])) + $arguments[$key] = $matches[$key]; + elseif ($reflectionParameter->isDefaultValueAvailable()) + $arguments[$key] = $reflectionParameter->getDefaultValue(); + else + $arguments[$key] = null; + } + return $arguments; + } +} diff --git a/src/Router.php b/src/Router.php new file mode 100644 index 00000000..a8683702 --- /dev/null +++ b/src/Router.php @@ -0,0 +1,46 @@ +route('GET', $query, $route); + } + + public function put($query, $route) + { + $this->route('PUT', $query, $route); + } + + public function delete($query, $route) + { + $this->route('DELETE', $query, $route); + } + + public function post($query, $route) + { + $this->route('POST', $query, $route); + } + + private function route($method, $query, $route) + { + $this->routes[$method] []= new Route($query, $route); + } + + public function handle($method, $request) + { + if (!isset($this->routes[$method])) + throw new \DomainException('Unhandled request method: ' . $method); + + foreach ($this->routes[$method] as $route) + { + if ($route->handle($request)) + return; + } + + throw new \DomainException('Unhandled request address: ' . $request); + } +} diff --git a/tests/RouterTest.php b/tests/RouterTest.php new file mode 100644 index 00000000..3f4526ca --- /dev/null +++ b/tests/RouterTest.php @@ -0,0 +1,100 @@ +get('/test', function() use (&$testOk) { $testOk = true; }); + $router->handle('GET', '/test'); + $this->assertTrue($testOk); + } + + public function testTrailingSlashes() + { + $router = new \Szurubooru\Router; + $testOk = false; + $router->get('/test', function() use (&$testOk) { $testOk = true; }); + $router->handle('GET', '/test/'); + $this->assertTrue($testOk); + } + + public function testUnhandledMethod() + { + $router = new \Szurubooru\Router; + $router->get('/test', function() { $this->fail('Route shouldn\'t be executed'); }); + $this->setExpectedException('\DomainException'); + $router->handle('POST', '/test'); + } + + public function testUnhandledQuery() + { + $router = new \Szurubooru\Router; + $router->get('/test', function() { $this->fail('Route shouldn\'t be executed'); }); + $this->setExpectedException('\DomainException'); + $router->handle('GET', '/test2'); + } + + public function testTwoMethodsHandling() + { + $router = new \Szurubooru\Router; + $testOk = false; + $router->get('/test', function() { $this->fail('Route shouldn\'t be executed'); }); + $router->post('/test', function() use (&$testOk) { $testOk = true; }); + $router->handle('POST', '/test'); + $this->assertTrue($testOk); + } + + public function testParameterHandling() + { + $router = new \Szurubooru\Router; + $testOk = false; + $router->get('/tests/:id', function($id) use (&$testOk) { + $this->assertEquals($id, 'test_id'); + $testOk = true; }); + + $router->handle('GET', '/tests/test_id'); + $this->assertTrue($testOk); + } + + public function testTwoParameterHandling() + { + $router = new \Szurubooru\Router; + $testOk = false; + $router->get('/tests/:id/:page', function($id, $page) use (&$testOk) { + $this->assertEquals($id, 'test_id'); + $this->assertEquals($page, 'test_page'); + $testOk = true; }); + + $router->handle('GET', '/tests/test_id/test_page'); + $this->assertTrue($testOk); + } + + public function testMissingParameterHandling() + { + $router = new \Szurubooru\Router; + $testOk = false; + $router->get('/tests/:id', function($id, $page) use (&$testOk) { + $this->assertEquals($id, 'test_id'); + $this->assertNull($page); + $testOk = true; }); + + $router->handle('GET', '/tests/test_id'); + $this->assertTrue($testOk); + } + + public function testMissingDefaultParameterHandling() + { + $router = new \Szurubooru\Router; + $testOk = false; + $router->get('/tests/:id', function($id, $page = 1) use (&$testOk) { + $this->assertEquals($id, 'test_id'); + $this->assertEquals(1, $page); + $testOk = true; }); + + $router->handle('GET', '/tests/test_id'); + $this->assertTrue($testOk); + } +}