Skip to content

Commit

Permalink
Support HTTP 405 response code
Browse files Browse the repository at this point in the history
  • Loading branch information
jtojnar committed Jan 18, 2022
1 parent 0d55477 commit 78c0e66
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 14 deletions.
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,11 +280,15 @@ $router->get('/cars/(\d+)', 'Car@showProfile');

### Custom 404

The default 404 handler sets a 404 status code and exits. You can override this default 404 handler by using `$router->set404(callable);`
The default 404 handler sets a 404 or 405 status code and exits. You can override this default 404 handler by using `$router->set404(callable);`

```php
$router->set404(function() {
header('HTTP/1.1 404 Not Found');
$router->set404(function($handledByOtherMethod) {
if ($handledByOtherMethod) {
header('HTTP/1.1 405 Method Not Allowed');
} else {
header('HTTP/1.1 404 Not Found');
}
// ... do something special here
});
```
Expand Down
36 changes: 27 additions & 9 deletions src/Bramus/Router/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,10 @@ public function match($methods, $pattern, $fn)
$pattern = $this->baseRoute ? rtrim($pattern, '/') : $pattern;

$handledMethods = is_array($methods) ? $methods : explode('|', $methods);
foreach ($handledMethods as $method) {
foreach (self::ALL_METHODS as $method) {
$this->afterRoutes[$method][] = array(
'pattern' => $pattern,
'fn' => $fn,
'fn' => in_array($method, $handledMethods, true) ? $fn : null,
);
}
}
Expand Down Expand Up @@ -289,13 +289,16 @@ public function run($callback = null)

// Handle all routes
$numHandled = 0;
$numHandledByOtherMethods = 0;
if (isset($this->afterRoutes[$this->requestedMethod])) {
$numHandled = $this->handle($this->afterRoutes[$this->requestedMethod], true);
$handled = $this->handle($this->afterRoutes[$this->requestedMethod], true);
$numHandled = $handled->numHandled;
$numHandledByOtherMethods = $handled->numHandledByOtherMethods;
}

// If no route was handled, trigger the 404 (if any)
if ($numHandled === 0) {
$this->trigger404();
$this->trigger404($numHandledByOtherMethods > 0);
} // If a route was handled, perform the finish callback (if any)
else {
if ($callback && is_callable($callback)) {
Expand Down Expand Up @@ -329,8 +332,10 @@ public function set404($match_fn, $fn = null)

/**
* Triggers 404 response
*
* @param bool $handledByOtherMethod Whether the match is handled by other method.
*/
public function trigger404(){
public function trigger404($handledByOtherMethod = false){

// Counter to keep track of the number of routes we've handled
$numHandled = 0;
Expand Down Expand Up @@ -366,16 +371,20 @@ public function trigger404(){
return isset($match[0][0]) && $match[0][1] != -1 ? trim($match[0][0], '/') : null;
}, $matches, array_keys($matches));

$this->invoke($route_callable);
$this->invoke($route_callable, [$handledByOtherMethod]);

++$numHandled;
}
}
}
if (($numHandled == 0) && (isset($this->notFoundCallback['/']))) {
$this->invoke($this->notFoundCallback['/']);
$this->invoke($this->notFoundCallback['/'], [$handledByOtherMethod]);
} elseif ($numHandled == 0) {
header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found');
if ($handledByOtherMethod) {
header($_SERVER['SERVER_PROTOCOL'] . ' 405 Method Not Allowed');
} else {
header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found');
}
}
}

Expand Down Expand Up @@ -411,6 +420,7 @@ private function handle($routes, $quitAfterRun = false)
{
// Counter to keep track of the number of routes we've handled
$numHandled = 0;
$numHandledByOtherMethods = 0;

// The current page URL
$uri = $this->getCurrentUri();
Expand All @@ -423,6 +433,11 @@ private function handle($routes, $quitAfterRun = false)

// is there a valid match?
if ($is_match) {
if ($route['fn'] === null) {
++$numHandledByOtherMethods;

continue;
}

// Rework matches to only contain the matches, not the orig string
$matches = array_slice($matches, 1);
Expand Down Expand Up @@ -453,7 +468,10 @@ private function handle($routes, $quitAfterRun = false)
}

// Return the number of routes handled
return $numHandled;
return (object) [
'numHandled' => $numHandled,
'numHandledByOtherMethods' => $numHandledByOtherMethods,
];
}

private function invoke($fn, $params = array())
Expand Down
14 changes: 12 additions & 2 deletions tests/RouterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -626,8 +626,8 @@ public function test404()
$router->get('/', function () {
echo 'home';
});
$router->set404(function () {
echo 'route not found';
$router->set404(function ($handledByOtherMethod) {
echo $handledByOtherMethod ? 'method not allowed' : 'route not found';
});

$router->set404('/api(/.*)?', function () {
Expand All @@ -639,11 +639,21 @@ public function test404()
$this->assertEquals('home', $responseBody);
});

// Test route existing for other method
run_request($router, 'POST', '/', function ($responseBody) {
$this->assertEquals('method not allowed', $responseBody);
});

// Test non-existing route
run_request($router, 'GET', '/foo', function ($responseBody) {
$this->assertEquals('route not found', $responseBody);
});

// Test non-existing route
run_request($router, 'POST', '/foo', function ($responseBody) {
$this->assertEquals('route not found', $responseBody);
});

// Test the custom api 404
run_request($router, 'POST', '/api/getUser', function ($responseBody) {
$this->assertEquals('api route not found', $responseBody);
Expand Down

0 comments on commit 78c0e66

Please sign in to comment.