Router can return a default 404 response when no routes match the request.

Add functionality to Request to carve up a URI and set the corresponding members.
This commit is contained in:
PJ Dietz 2012-09-23 18:43:52 -04:00
parent 4c0434399a
commit ef31fd7292
3 changed files with 157 additions and 44 deletions

View File

@ -2,9 +2,7 @@
namespace wellrested; namespace wellrested;
/******************************************************************************* /**
* Request
*
* A Request instance contains information relating to the current HTTP request * A Request instance contains information relating to the current HTTP request
* a client sent to the server. * a client sent to the server.
* *
@ -12,58 +10,69 @@ namespace wellrested;
* request, the class exposes the static getRequest() method for obtaining a * request, the class exposes the static getRequest() method for obtaining a
* singleton Request instance. * singleton Request instance.
* *
* @package WellRESTed
*
******************************************************************************/
/**
* @property string body Entity body of the request * @property string body Entity body of the request
* @property array headers Associative array of HTTP headers * @property array headers Associative array of HTTP headers
* @property string method HTTP method or verb for the request * @property string method HTTP method or verb for the request
* @property string path Path component of the URI for the request * @property string path Path component of the URI for the request
* @property string pathParts Fragments of the path, delimited by slashes * @property string pathParts Fragments of the path, delimited by slashes
* @property array query Associative array of query parameters * @property array query Associative array of query parameters
*
* @package WellRESTed
*/ */
class Request { class Request {
/** /**
* Entity body of the request * Entity body of the request
*
* @var string * @var string
*/ */
protected $body; protected $body;
/** /**
* Associative array of HTTP headers * Associative array of HTTP headers
*
* @var array * @var array
*/ */
protected $headers; protected $headers;
/** /**
* HTTP method or verb for the request * HTTP method or verb for the request
*
* @var string * @var string
*/ */
protected $method; protected $method;
/** /**
* Path component of the URI for the request * Path component of the URI for the request
*
* @var string * @var string
*/ */
protected $path; protected $path;
/** /**
* Array of fragments of the path, delimited by slashes * Array of fragments of the path, delimited by slashes
*
* @var array * @var array
*/ */
protected $pathParts; protected $pathParts;
/** /**
* Associative array of query parameters * Associative array of query parameters
*
* @var array * @var array
*/ */
protected $query; protected $query;
/**
* The full URI of the request
*
* @var string
*/
protected $uri;
/** /**
* Singleton instance derived from reading info from Apache. * Singleton instance derived from reading info from Apache.
*
* @var Request * @var Request
* @static * @static
*/ */
@ -73,27 +82,57 @@ namespace wellrested;
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// !Accessors // !Accessors
/**
* @param string $name
* @return array|string
* @throws \Exception
*/
public function __get($name) { public function __get($name) {
switch ($name) { switch ($name) {
case 'body': case 'body':
return $this->getBody(); return $this->getBody();
case 'headers': case 'headers':
return $this->getHeaders(); return $this->getHeaders();
case 'method': case 'method':
return $this->getMethod(); return $this->getMethod();
case 'path': case 'path':
return $this->getPath(); return $this->getPath();
case 'pathParts': case 'pathParts':
return $this->getPathParts(); return $this->getPathParts();
case 'query': case 'query':
return $this->getQuery(); return $this->getQuery();
default: case 'uri':
throw new \Exception('Property ' . $name . ' does not exist.'); return $this->getUri();
default:
throw new \Exception('Property ' . $name . ' does not exist.');
} }
} // __get() } // __get()
/**
* @param string $name
* @param mixed $value
* @throws \Exception
*/
public function __set($name, $value) {
switch ($name) {
case 'path':
$this->setPath($value);
return;
case 'query':
$this->setQuery($value);
return;
case 'uri':
$this->setUri($value);
return;
default:
throw new \Exception('Property ' . $name . 'does not exist.');
}
}
public function getBody() { public function getBody() {
return $this->body; return $this->body;
} }
@ -118,6 +157,73 @@ namespace wellrested;
return $this->query; return $this->query;
} }
public function getUri() {
return $this->uri;
}
/**
* Set the path and pathParts members.
*
* @param string $path
*/
public function setPath($path) {
$this->path = $path;
$this->pathParts = explode('/', substr($path, 1));
}
/**
* @param string|array $query
* @throws \InvalidArgumentException
*/
public function setQuery($query) {
if (is_string($query)) {
$qs = $query;
parse_str($qs, $query);
}
if (is_array($query)) {
$this->query = $query;
} else {
throw new \InvalidArgumentException('Unable to parse query string.');
}
}
/**
* Set the URI for the Request. This method also sets the path, pathParts,
* and query.
*
* @param string $uri
*/
public function setUri($uri) {
/*
* TODO, eventually do all of these:
http
host
port
user
pass
path
query - after the question mark ?
fragment - after the hashmark #
*/
$this->uri = $uri;
$parsed = parse_url($uri);
$path = isset($parsed['path']) ? $parsed['path'] : '';
$this->setPath($path);
$query = isset($parsed['query']) ? $parsed['query'] : '';
$this->setQuery($query);
}
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
/** /**
@ -126,17 +232,9 @@ namespace wellrested;
protected function readHttpRequest() { protected function readHttpRequest() {
$this->body = file_get_contents("php://input"); $this->body = file_get_contents("php://input");
$this->headers = apache_request_headers(); $this->headers = apache_request_headers();
$this->method = $_SERVER['REQUEST_METHOD']; $this->method = $_SERVER['REQUEST_METHOD'];
$this->setUri($_SERVER['REQUEST_URI']);
$uri = parse_url($_SERVER['REQUEST_URI']);
$this->path = $uri['path'];
$this->pathParts = explode('/', substr($this->path, 1));
$this->query = $_GET;
} // readHttpRequest() } // readHttpRequest()

View File

@ -38,10 +38,9 @@ class Response {
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
public function __construct($statusCode=500, $body='', $headers=null) { public function __construct($statusCode=500, $body=null, $headers=null) {
$this->statusCode = $statusCode; $this->statusCode = $statusCode;
$this->body = $body;
if (is_array($headers)) { if (is_array($headers)) {
$this->headers = $headers; $this->headers = $headers;
@ -49,6 +48,10 @@ class Response {
$this->headers = array(); $this->headers = array();
} }
if (!is_null($body)) {
$this->body = $body;
}
} // __construct() } // __construct()
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------

View File

@ -3,6 +3,7 @@
namespace wellrested; namespace wellrested;
require_once(dirname(__FILE__) . '/Request.inc.php'); require_once(dirname(__FILE__) . '/Request.inc.php');
require_once(dirname(__FILE__) . '/Response.inc.php');
require_once(dirname(__FILE__) . '/Route.inc.php'); require_once(dirname(__FILE__) . '/Route.inc.php');
/******************************************************************************* /*******************************************************************************
@ -35,18 +36,17 @@ class Router {
} // addRoute() } // addRoute()
/** /**
* @param string $requestPath * @param Request $request
* @return Handler * @return Response
*/ */
public function getRequestHandler($requestPath=null) { public function getResponse($request=null) {
if (is_null($requestPath)) { if (is_null($request)) {
$request = Request::getRequest(); $request = Request::getRequest();
$path = $request->path;
} else {
$path = $requestPath;
} }
$path = $request->path;
foreach ($this->routes as $route) { foreach ($this->routes as $route) {
if (preg_match($route->pattern, $path, $matches)) { if (preg_match($route->pattern, $path, $matches)) {
@ -57,17 +57,29 @@ class Router {
require_once($route->handlerPath); require_once($route->handlerPath);
} }
// TODO: Need to rethink this plan. May not have a $request yet. $handler = new $klass($request, $matches);
return $handler = new $klass($request, $matches); return $handler->response;
} }
} }
return false; return $this->getNoRouteResponse($request);
} // getRequestHandler() } // getRequestHandler()
/**
* @param Request $request
* @return Response
*/
protected function getNoRouteResponse(Request $request) {
$response = new Response(404);
$response->body = 'No resource at ' . $request->uri;
return $response;
}
} // Router } // Router
?> ?>