129 lines
4.0 KiB
PHP
129 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace WellRESTed\Routing;
|
|
|
|
use Psr\Http\Message\ResponseInterface;
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
use WellRESTed\Dispatching\DispatcherInterface;
|
|
|
|
class MethodMap implements MethodMapInterface
|
|
{
|
|
private $dispatcher;
|
|
private $map;
|
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
public function __construct(DispatcherInterface $dispatcher)
|
|
{
|
|
$this->map = [];
|
|
$this->dispatcher = $dispatcher;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// MethodMapInterface
|
|
|
|
/**
|
|
* Register a dispatchable (handler or middleware) with a method.
|
|
*
|
|
* $method may be:
|
|
* - A single verb ("GET"),
|
|
* - A comma-separated list of verbs ("GET,PUT,DELETE")
|
|
* - "*" to indicate any method.
|
|
*
|
|
* $dispatchable may be anything a Dispatcher can dispatch.
|
|
* @see DispatcherInterface::dispatch
|
|
*
|
|
* $dispatchable may also be null, in which case any previously set
|
|
* handlers and middle for that method or methods will be unset.
|
|
*
|
|
* @param string $method
|
|
* @param mixed $dispatchable
|
|
*/
|
|
public function register($method, $dispatchable)
|
|
{
|
|
$methods = explode(",", $method);
|
|
$methods = array_map("trim", $methods);
|
|
foreach ($methods as $method) {
|
|
$this->map[$method] = $dispatchable;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// MiddlewareInterface
|
|
|
|
/**
|
|
* @param ServerRequestInterface $request
|
|
* @param ResponseInterface $response
|
|
* @param callable $next
|
|
* @return ResponseInterface
|
|
*/
|
|
public function __invoke(
|
|
ServerRequestInterface $request,
|
|
ResponseInterface $response,
|
|
$next
|
|
) {
|
|
$method = $request->getMethod();
|
|
// Dispatch middleware registered with the explicitly matching method.
|
|
if (isset($this->map[$method])) {
|
|
$middleware = $this->map[$method];
|
|
return $this->dispatchMiddleware($middleware, $request, $response, $next);
|
|
}
|
|
// For HEAD, dispatch GET by default.
|
|
if ($method === "HEAD" && isset($this->map["GET"])) {
|
|
$middleware = $this->map["GET"];
|
|
return $this->dispatchMiddleware($middleware, $request, $response, $next);
|
|
}
|
|
// Dispatch * middleware, if registered.
|
|
if (isset($this->map["*"])) {
|
|
$middleware = $this->map["*"];
|
|
return $this->dispatchMiddleware($middleware, $request, $response, $next);
|
|
}
|
|
// Respond describing the allowed methods, either as a 405 response or
|
|
// in response to an OPTIONS request.
|
|
if ($method === "OPTIONS") {
|
|
$response = $response->withStatus(200);
|
|
} else {
|
|
$response = $response->withStatus(405);
|
|
}
|
|
return $this->addAllowHeader($response);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
private function addAllowHeader(ResponseInterface $response)
|
|
{
|
|
$methods = join(",", $this->getAllowedMethods());
|
|
return $response->withHeader("Allow", $methods);
|
|
}
|
|
|
|
private function getAllowedMethods()
|
|
{
|
|
$methods = array_keys($this->map);
|
|
// Add HEAD if GET is allowed and HEAD is not present.
|
|
if (in_array("GET", $methods) && !in_array("HEAD", $methods)) {
|
|
$methods[] = "HEAD";
|
|
}
|
|
// Add OPTIONS if not already present.
|
|
if (!in_array("OPTIONS", $methods)) {
|
|
$methods[] = "OPTIONS";
|
|
}
|
|
return $methods;
|
|
}
|
|
|
|
/**
|
|
* @param $middleware
|
|
* @param ServerRequestInterface $request
|
|
* @param ResponseInterface $response
|
|
* @param $next
|
|
* @return ResponseInterface
|
|
*/
|
|
private function dispatchMiddleware(
|
|
$middleware,
|
|
ServerRequestInterface $request,
|
|
ResponseInterface &$response,
|
|
$next
|
|
) {
|
|
return $this->dispatcher->dispatch($middleware, $request, $response, $next);
|
|
}
|
|
}
|