wellrested/src/pjdietz/WellRESTed/Router.php

120 lines
3.6 KiB
PHP

<?php
/**
* pjdietz\WellRESTed\Router
*
* @author PJ Dietz <pj@pjdietz.com>
* @copyright Copyright 2013 by PJ Dietz
* @license MIT
*/
namespace pjdietz\WellRESTed;
use pjdietz\WellRESTed\Interfaces\HandlerInterface;
use pjdietz\WellRESTed\Interfaces\RequestInterface;
use pjdietz\WellRESTed\Interfaces\ResponseInterface;
use pjdietz\WellRESTed\Interfaces\RouteInterface;
use pjdietz\WellRESTed\Interfaces\RouterInterface;
use pjdietz\WellRESTed\Interfaces\RouteTargetInterface;
/**
* Router
*
* A Router uses a table of Routes to find the appropriate Handler for a request.
*/
class Router extends RouteTarget implements RouterInterface
{
/** @var string Fully qualified name for the interface for handlers */
const ROUTE_TARGET_INTERFACE = '\\pjdietz\\WellRESTed\\Interfaces\\RouteTargetInterface';
/** @var array Array of Route objects */
private $routes;
/** Create a new Router. */
public function __construct()
{
$this->routes = array();
}
/**
* Append a new Route instance to the Router's route table.
*
* @param RouteInterface $route
*/
public function addRoute(RouteInterface $route)
{
$this->routes[] = $route;
}
/**
* Return the response built by the handler based on the request
*
* @param RequestInterface $request
* @return ResponseInterface
*/
public function getResponse(RequestInterface $request = null)
{
if (is_null($request)) {
$request = Request::getRequest();
}
$path = $request->getPath();
foreach ($this->routes as $route) {
/** @var RouteInterface $route */
if (preg_match($route->getPattern(), $path, $matches)) {
$targetClassName = $route->getTarget();
if (is_subclass_of($targetClassName, self::ROUTE_TARGET_INTERFACE)) {
/** @var RouteTargetInterface $target */
$target = new $targetClassName();
$target->setRequest($request);
// If this instance already had argument, merge the matches with them.
$myArguments = $this->getArguments();
if (!is_null($myArguments)) {
$matches = array_merge($myArguments, $matches);
}
$target->setArguments($matches);
// If this instance already had a top-level router, pass it along.
// Otherwise, pass itself as the top-level router.
if (isset($this->router)) {
$target->setRouter($this->router);
} else {
$target->setRouter($this);
}
return $target->getResponse();
} else {
return $this->getInternalServerErrorResponse($request);
}
}
}
return $this->getNoRouteResponse($request);
}
/**
* Prepare a resonse indicating a 404 Not Found error
*
* @param RequestInterface $request
* @return ResponseInterface
*/
protected function getNoRouteResponse(RequestInterface $request)
{
$response = new Response(404);
$response->body = 'No resource at ' . $request->getPath();
return $response;
}
/** Prepare a response indicating a 500 Internal Server Error */
protected function getInternalServerErrorResponse(RequestInterface $request)
{
$response = new Response(500);
$response->body = 'Server error at ' . $request->getPath();
return $response;
}
}