From 98e04ab63ba479b705950adc35123ef7bf5e6c25 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sun, 26 May 2013 14:55:48 -0400 Subject: [PATCH] Define interfaces more clearly and clean up code. --- .../Exceptions/WellRESTedException.php | 2 +- src/pjdietz/WellRESTed/Handler.php | 95 +++++----- src/pjdietz/WellRESTed/HandlerInterface.php | 16 -- .../Interfaces/HandlerInterface.php | 39 +++++ .../Interfaces/RequestInterface.php | 39 +++++ .../Interfaces/ResponseInterface.php | 47 +++++ .../WellRESTed/Interfaces/RouteInterface.php | 30 ++++ .../WellRESTed/Interfaces/RouterInterface.php | 26 +++ src/pjdietz/WellRESTed/Message.php | 40 +---- src/pjdietz/WellRESTed/Request.php | 163 ++++++++---------- src/pjdietz/WellRESTed/RequestInterface.php | 15 -- src/pjdietz/WellRESTed/Response.php | 70 +++----- src/pjdietz/WellRESTed/ResponseInterface.php | 12 -- src/pjdietz/WellRESTed/Route.php | 78 ++++----- src/pjdietz/WellRESTed/RouteInterface.php | 38 ---- src/pjdietz/WellRESTed/Router.php | 48 +++--- 16 files changed, 389 insertions(+), 369 deletions(-) delete mode 100644 src/pjdietz/WellRESTed/HandlerInterface.php create mode 100644 src/pjdietz/WellRESTed/Interfaces/HandlerInterface.php create mode 100644 src/pjdietz/WellRESTed/Interfaces/RequestInterface.php create mode 100644 src/pjdietz/WellRESTed/Interfaces/ResponseInterface.php create mode 100644 src/pjdietz/WellRESTed/Interfaces/RouteInterface.php create mode 100644 src/pjdietz/WellRESTed/Interfaces/RouterInterface.php delete mode 100644 src/pjdietz/WellRESTed/RequestInterface.php delete mode 100644 src/pjdietz/WellRESTed/ResponseInterface.php delete mode 100644 src/pjdietz/WellRESTed/RouteInterface.php diff --git a/src/pjdietz/WellRESTed/Exceptions/WellRESTedException.php b/src/pjdietz/WellRESTed/Exceptions/WellRESTedException.php index 1ded69b..70f8e44 100644 --- a/src/pjdietz/WellRESTed/Exceptions/WellRESTedException.php +++ b/src/pjdietz/WellRESTed/Exceptions/WellRESTedException.php @@ -10,7 +10,7 @@ namespace pjdietz\WellRESTed\Exceptions; -use \Exception; +use Exception; /** * Top level class for custom exceptions thrown by Well RESTed. diff --git a/src/pjdietz/WellRESTed/Handler.php b/src/pjdietz/WellRESTed/Handler.php index d8bfec3..61e3535 100644 --- a/src/pjdietz/WellRESTed/Handler.php +++ b/src/pjdietz/WellRESTed/Handler.php @@ -10,33 +10,26 @@ namespace pjdietz\WellRESTed; +use pjdietz\WellRESTed\Interfaces\HandlerInterface; +use pjdietz\WellRESTed\Interfaces\RequestInterface; +use pjdietz\WellRESTed\Interfaces\ResponseInterface; +use pjdietz\WellRESTed\Interfaces\RouterInterface; + /** * A Handler issues a response for a given resource. * - * @property-read Response response The Response to the request + * @property-read ResponseInterface response The Response to the request */ abstract class Handler implements HandlerInterface { - /** - * Matches array from the preg_match() call used to find this Handler. - * - * @var array - */ + /** @var array Matches array from the preg_match() call used to find this Handler */ protected $args; - - /** - * The HTTP request to respond to. - * - * @var Request - */ + /** @var RequestInterface The HTTP request to respond to. */ protected $request; - - /** - * The HTTP response to send based on the request. - * - * @var Response - */ + /** @var ResponseInterface The HTTP response to send based on the request. */ protected $response; + /** @var RouterInterface The router that dispatched this handler */ + protected $router; // ------------------------------------------------------------------------- // Accessors @@ -56,43 +49,43 @@ abstract class Handler implements HandlerInterface return null; } - /** - * @param array $args - */ + /** @param array $args */ public function setArguments(array $args) { $this->args = $args; } - /** - * @return array - */ + /** @return array */ public function getArguments() { return $this->args; } - /** - * @param RequestInterface $request - */ - public function setRequest(RequestInterface $request) - { - $this->request = $request; - } - - /** - * @return \pjdietz\WellRESTed\Request - */ + /** @return RequestInterface */ public function getRequest() { return $this->request; } - /** - * Return the instance's Reponse - * - * @return ResponseInterface - */ + /** @param RequestInterface $request */ + public function setRequest(RequestInterface $request) + { + $this->request = $request; + } + + /** @return RouterInterface */ + public function getRouter() + { + return $this->router; + } + + /** @param RouterInterface $router */ + public function setRouter(RouterInterface $router) + { + $this->router = $router; + } + + /** @return ResponseInterface */ public function getResponse() { $this->response = new Response(); @@ -107,7 +100,7 @@ abstract class Handler implements HandlerInterface */ protected function buildResponse() { - switch ($this->request->method) { + switch ($this->request->getMethod()) { case 'GET': $this->get(); @@ -159,6 +152,14 @@ abstract class Handler implements HandlerInterface $this->respondWithMethodNotAllowed(); } + /** + * Provide a default response for unsupported methods. + */ + protected function respondWithMethodNotAllowed() + { + $this->response->setStatusCode(405); + } + /** * Method for handling HTTP HEAD requests. * @@ -171,8 +172,8 @@ abstract class Handler implements HandlerInterface $this->get(); - if ($this->response->statusCode == 200) { - $this->response->setBody('', false); + if ($this->response->getStatusCode() == 200) { + $this->response->setBody(''); } } @@ -226,12 +227,4 @@ abstract class Handler implements HandlerInterface $this->respondWithMethodNotAllowed(); } - /** - * Provide a default response for unsupported methods. - */ - protected function respondWithMethodNotAllowed() - { - $this->response->statusCode = 405; - } - } diff --git a/src/pjdietz/WellRESTed/HandlerInterface.php b/src/pjdietz/WellRESTed/HandlerInterface.php deleted file mode 100644 index 583b6de..0000000 --- a/src/pjdietz/WellRESTed/HandlerInterface.php +++ /dev/null @@ -1,16 +0,0 @@ - + * @copyright Copyright 2013 by PJ Dietz + * @license MIT + */ + +namespace pjdietz\WellRESTed\Interfaces; + +/** + * Interface for a creating a response in reaction to a request or arguments. + * @package pjdietz\WellRESTed + */ +interface HandlerInterface +{ + /** @return array Associative array used to obtain a response */ + public function getArguments(); + + /** @param array $args Associative array used to obtain a response */ + public function setArguments(array $args); + + /** @return RequestInterface Request used to obtain a response */ + public function getRequest(); + + /** @param RequestInterface $request Request used to obtain a response */ + public function setRequest(RequestInterface $request); + + /** @return RouterInterface Reference to the router used to dispatch this handler */ + public function getRouter(); + + /** @param RouterInterface $router Request used to obtain a response */ + public function setRouter(RouterInterface $router); + + /** @return ResponseInterface Response obtained based on the args and request */ + public function getResponse(); +} diff --git a/src/pjdietz/WellRESTed/Interfaces/RequestInterface.php b/src/pjdietz/WellRESTed/Interfaces/RequestInterface.php new file mode 100644 index 0000000..2ac4abb --- /dev/null +++ b/src/pjdietz/WellRESTed/Interfaces/RequestInterface.php @@ -0,0 +1,39 @@ + + * @copyright Copyright 2013 by PJ Dietz + * @license MIT + */ + +namespace pjdietz\WellRESTed\Interfaces; + +/** + * Interface for representing an HTTP request. + * @package pjdietz\WellRESTed + */ +interface RequestInterface +{ + /** @return string HTTP request method (e.g., GET, POST, PUT). */ + public function getMethod(); + + /** @return string Path component of the request URI */ + public function getPath(); + + /** @return array Query paramters as key-value pairs */ + public function getQuery(); + + /** + * Return the value for this header name + * + * @param $headerName + * @return string $headerName + */ + public function getHeader($headerName); + + /** @return string Requst body */ + public function getBody(); + +} diff --git a/src/pjdietz/WellRESTed/Interfaces/ResponseInterface.php b/src/pjdietz/WellRESTed/Interfaces/ResponseInterface.php new file mode 100644 index 0000000..51278b1 --- /dev/null +++ b/src/pjdietz/WellRESTed/Interfaces/ResponseInterface.php @@ -0,0 +1,47 @@ + + * @copyright Copyright 2013 by PJ Dietz + * @license MIT + */ + +namespace pjdietz\WellRESTed\Interfaces; + +/** + * Interface for representing an HTTP response. + * @package pjdietz\WellRESTed + */ +interface ResponseInterface +{ + /** @return int HTTP status code */ + public function getStatusCode(); + + /** @param int $statusCode HTTP status code */ + public function setStatusCode($statusCode); + + /** + * Return the value for this header name + * + * @param $headerName + * @return string $headerName + */ + public function getHeader($headerName); + + /** + * @param string $headerName + * @param string $headerValue + */ + public function setHeader($headerName, $headerValue); + + /** @return string */ + public function getBody(); + + /** @param string $body */ + public function setBody($body); + + /** Issue the reponse to the client. */ + public function respond(); +} diff --git a/src/pjdietz/WellRESTed/Interfaces/RouteInterface.php b/src/pjdietz/WellRESTed/Interfaces/RouteInterface.php new file mode 100644 index 0000000..6fff10e --- /dev/null +++ b/src/pjdietz/WellRESTed/Interfaces/RouteInterface.php @@ -0,0 +1,30 @@ + + * @copyright Copyright 2013 by PJ Dietz + * @license MIT + */ + +namespace pjdietz\WellRESTed\Interfaces; + +/** + * Interface for a route to relate a pattern for matching a URI to a handler class. + * @package pjdietz\WellRESTed + */ +interface RouteInterface +{ + /** @return string Regex pattern used to match the URI */ + public function getPattern(); + + /** @para string $pattern Regex pattern used to match the URI */ + public function setPattern($pattern); + + /** @return string Fully qualified name of the class the route will dispatch. */ + public function getHandler(); + + /** @param string $className Fully qualified name of the class the route will dispatch. */ + public function setHandler($className); +} diff --git a/src/pjdietz/WellRESTed/Interfaces/RouterInterface.php b/src/pjdietz/WellRESTed/Interfaces/RouterInterface.php new file mode 100644 index 0000000..931fe3e --- /dev/null +++ b/src/pjdietz/WellRESTed/Interfaces/RouterInterface.php @@ -0,0 +1,26 @@ + + * @copyright Copyright 2013 by PJ Dietz + * @license MIT + */ + +namespace pjdietz\WellRESTed\Interfaces; + +/** + * The RouterInterface provides a mechanism for obtaining a response given a request. + * @package pjdietz\WellRESTed + */ +interface RouterInterface +{ + /** + * Return the response for the given request. + * + * @param RequestInterface $request + * @return ResponseInterface + */ + public function getResponse(RequestInterface $request = null); +} \ No newline at end of file diff --git a/src/pjdietz/WellRESTed/Message.php b/src/pjdietz/WellRESTed/Message.php index 37e80c6..4311afe 100644 --- a/src/pjdietz/WellRESTed/Message.php +++ b/src/pjdietz/WellRESTed/Message.php @@ -21,20 +21,10 @@ namespace pjdietz\WellRESTed; */ abstract class Message { - /** - * Entity body of the message - * - * @var string - */ + /** @var string Entity body of the message */ protected $body; - - /** - * Associative array of HTTP headers - * - * @var array - */ + /** @var array Associative array of HTTP headers */ protected $headers; - /** * Associative array of lowercase header field names as keys with * corresponding case sensitive field names from the $headers array as @@ -43,19 +33,9 @@ abstract class Message * @var array */ protected $headerLookup; - - /** - * Name of the protocol to use. - * - * @var string - */ + /** @var string Name of the protocol to use. */ protected $protocol = 'HTTP'; - - /** - * Version of the protocol to use. - * - * @var string - */ + /** @var string Version of the protocol to use. */ protected $protocolVersion = '1.1'; // ------------------------------------------------------------------------- @@ -156,9 +136,7 @@ abstract class Message return isset($this->body); } - /** - * Unset the body property - */ + /** Unset the body property */ public function unsetBody() { unset($this->body); @@ -315,9 +293,7 @@ abstract class Message return isset($this->protocol); } - /** - * Unset the protocol property. - */ + /** Unset the protocol property. */ public function unsetProtocol() { unset($this->protocol); @@ -353,9 +329,7 @@ abstract class Message return isset($this->protocolVersion); } - /** - * Unset the version portion of the protocol. - */ + /** Unset the version portion of the protocol. */ public function unsetProtocolVersion() { unset($this->protocolVersion); diff --git a/src/pjdietz/WellRESTed/Request.php b/src/pjdietz/WellRESTed/Request.php index edbdfba..060f852 100644 --- a/src/pjdietz/WellRESTed/Request.php +++ b/src/pjdietz/WellRESTed/Request.php @@ -10,7 +10,7 @@ namespace pjdietz\WellRESTed; -// TODO: Include port in the URI +use pjdietz\WellRESTed\Interfaces\RequestInterface; /** * A Request instance represents an HTTP request. This class has two main uses: @@ -31,40 +31,7 @@ namespace pjdietz\WellRESTed; */ class Request extends Message implements RequestInterface { - /** - * The Hostname for the request (e.g., www.google.com) - * - * @var string - */ - private $hostname; - - /** - * HTTP method or verb for the request - * - * @var string - */ - private $method = 'GET'; - - /** - * Path component of the URI for the request - * - * @var string - */ - private $path = '/'; - - /** - * Array of fragments of the path, delimited by slashes - * - * @var array - */ - private $pathParts; - - /** - * Associative array of query parameters - * - * @var array - */ - private $query; + // TODO: Include port in the URI /** * Singleton instance derived from reading info from Apache. @@ -73,6 +40,16 @@ class Request extends Message implements RequestInterface * @static */ static protected $theRequest; + /** @var string The Hostname for the request (e.g., www.google.com) */ + private $hostname; + /** @var string HTTP method or verb for the request */ + private $method = 'GET'; + /** @var string Path component of the URI for the request */ + private $path = '/'; + /** @var array Array of fragments of the path, delimited by slashes */ + private $pathParts; + /**@var array Associative array of query parameters */ + private $query; // ------------------------------------------------------------------------- @@ -96,6 +73,62 @@ class Request extends Message implements RequestInterface // ------------------------------------------------------------------------- // Accessors + /** + * Set the URI for the Request. This sets the other members, such as path, + * hostname, etc. + * + * @param string $uri + */ + public function setUri($uri) + { + $parsed = parse_url($uri); + + $host = isset($parsed['host']) ? $parsed['host'] : ''; + $this->setHostname($host); + + $path = isset($parsed['path']) ? $parsed['path'] : ''; + $this->setPath($path); + + $query = isset($parsed['query']) ? $parsed['query'] : ''; + $this->setQuery($query); + } + + /** + * Return a reference to the singleton instance of the Request derived + * from the server's information about the request sent to the script. + * + * @return Request + * @static + */ + public static function getRequest() + { + if (!isset(self::$theRequest)) { + $request = new Request(); + $request->readHttpRequest(); + self::$theRequest = $request; + } + + return self::$theRequest; + } + + /** + * Set instance members based on the HTTP request sent to the server. + */ + public function readHttpRequest() + { + $this->setBody(file_get_contents("php://input"), false); + $this->headers = apache_request_headers(); + + // Add case insensitive headers to the lookup table. + foreach ($this->headers as $key => $value) { + $this->headerLookup[strtolower($key)] = $key; + } + + $this->method = $_SERVER['REQUEST_METHOD']; + $this->uri = $_SERVER['REQUEST_URI']; + $this->hostname = $_SERVER['HTTP_HOST']; + } + /** * Return the hostname portion of the URI * @@ -195,6 +228,8 @@ class Request extends Message implements RequestInterface return $this->query; } + // ------------------------------------------------------------------------- + /** * Set the query. The value passed can be a query string of key-value pairs * joined by ampersands or it can be an associative array. @@ -232,28 +267,6 @@ class Request extends Message implements RequestInterface return $uri; } - /** - * Set the URI for the Request. This sets the other members, such as path, - * hostname, etc. - * - * @param string $uri - */ - public function setUri($uri) - { - $parsed = parse_url($uri); - - $host = isset($parsed['host']) ? $parsed['host'] : ''; - $this->setHostname($host); - - $path = isset($parsed['path']) ? $parsed['path'] : ''; - $this->setPath($path); - - $query = isset($parsed['query']) ? $parsed['query'] : ''; - $this->setQuery($query); - } - - // ------------------------------------------------------------------------- - /** * Make a cURL request out of the instance and return a Response. * @@ -335,40 +348,4 @@ class Request extends Message implements RequestInterface return $resp; } - /** - * Set instance members based on the HTTP request sent to the server. - */ - public function readHttpRequest() - { - $this->setBody(file_get_contents("php://input"), false); - $this->headers = apache_request_headers(); - - // Add case insensitive headers to the lookup table. - foreach ($this->headers as $key => $value) { - $this->headerLookup[strtolower($key)] = $key; - } - - $this->method = $_SERVER['REQUEST_METHOD']; - $this->uri = $_SERVER['REQUEST_URI']; - $this->hostname = $_SERVER['HTTP_HOST']; - } - - /** - * Return a reference to the singleton instance of the Request derived - * from the server's information about the request sent to the script. - * - * @return Request - * @static - */ - public static function getRequest() - { - if (!isset(self::$theRequest)) { - $request = new Request(); - $request->readHttpRequest(); - self::$theRequest = $request; - } - - return self::$theRequest; - } - } diff --git a/src/pjdietz/WellRESTed/RequestInterface.php b/src/pjdietz/WellRESTed/RequestInterface.php deleted file mode 100644 index 3b6e4ec..0000000 --- a/src/pjdietz/WellRESTed/RequestInterface.php +++ /dev/null @@ -1,15 +0,0 @@ -reasonPhrase; } - /** - * Return true if the status code is in the 2xx range. - * - * @return bool - */ - public function getSuccess() - { - return $this->statusCode >= 200 && $this->statusCode < 300; - } - /** * Assign an explaination for the status code. Not normally needed. * @@ -114,11 +96,13 @@ class Response extends Message implements ResponseInterface $this->reasonPhrase = $statusCodeMessage; } - /** - * Return the status code. - * - * @return int - */ + /** @return bool True if the status code is in the 2xx range. */ + public function getSuccess() + { + return $this->statusCode >= 200 && $this->statusCode < 300; + } + + /** @return int */ public function getStatusCode() { return $this->statusCode; @@ -268,24 +252,6 @@ class Response extends Message implements ResponseInterface } - /** - * Return HTTP status line, e.g. HTTP/1.1 200 OK. - * - * @return string - */ - protected function getStatusLine() - { - return sprintf( - '%s/%s %s %s', - strtoupper($this->protocol), - $this->protocolVersion, - $this->statusCode, - $this->reasonPhrase - ); - } - - // ------------------------------------------------------------------------- - /** * Output the response to the client. * @@ -307,4 +273,18 @@ class Response extends Message implements ResponseInterface } } + // ------------------------------------------------------------------------- + + /** @return string HTTP status line, e.g. HTTP/1.1 200 OK. */ + protected function getStatusLine() + { + return sprintf( + '%s/%s %s %s', + strtoupper($this->protocol), + $this->protocolVersion, + $this->statusCode, + $this->reasonPhrase + ); + } + } diff --git a/src/pjdietz/WellRESTed/ResponseInterface.php b/src/pjdietz/WellRESTed/ResponseInterface.php deleted file mode 100644 index cf9e888..0000000 --- a/src/pjdietz/WellRESTed/ResponseInterface.php +++ /dev/null @@ -1,12 +0,0 @@ -handler = $handler; } - /** - * @param string $handler - */ - public function setHandler($handler) - { - $this->handler = $handler; - } - - /** - * @return string - */ - public function getHandler() - { - return $this->handler; - } - - /** - * @param string $pattern - */ - public function setPattern($pattern) - { - $this->pattern = $pattern; - } - - /** - * @return string - */ - public function getPattern() - { - return $this->pattern; - } - /** * Create a new Route using a URI template to generate the pattern. * * @param string $uriTemplate * @param string $handler * @param array $variables - * @throws Exception + * @throws WellRESTedException * @return Route */ static public function newFromUriTemplate( @@ -155,7 +117,7 @@ class Route implements RouteInterface } else { // Not sure why this would happen. - throw new Exception('Invalid URI Template.'); + throw new WellRESTedException('Invalid URI Template.'); } } else { @@ -173,4 +135,36 @@ class Route implements RouteInterface } + /** + * @return string + */ + public function getHandler() + { + return $this->handler; + } + + /** + * @param string $handler + */ + public function setHandler($handler) + { + $this->handler = $handler; + } + + /** + * @return string + */ + public function getPattern() + { + return $this->pattern; + } + + /** + * @param string $pattern + */ + public function setPattern($pattern) + { + $this->pattern = $pattern; + } + } diff --git a/src/pjdietz/WellRESTed/RouteInterface.php b/src/pjdietz/WellRESTed/RouteInterface.php deleted file mode 100644 index cd5b5be..0000000 --- a/src/pjdietz/WellRESTed/RouteInterface.php +++ /dev/null @@ -1,38 +0,0 @@ -routes = array(); @@ -44,28 +45,29 @@ class Router } /** - * Return the Response built by the Handler based on the Request + * Return the response built by the handler based on the request * - * @param Request $request - * @return Response + * @param RequestInterface $request + * @return ResponseInterface */ - public function getResponse($request = null) + public function getResponse(RequestInterface $request = null) { if (is_null($request)) { $request = Request::getRequest(); } - $path = $request->path; + $path = $request->getPath(); foreach ($this->routes as $route) { /** @var RouteInterface $route */ if (preg_match($route->getPattern(), $path, $matches)) { $handlerClassName = $route->getHandler(); - if (is_subclass_of($handlerClassName, '\pjdietz\WellRESTed\HandlerInterface')) { + if (is_subclass_of($handlerClassName, self::HANDLER_INTERFACE)) { /** @var HandlerInterface $handler */ $handler = new $handlerClassName(); $handler->setRequest($request); $handler->setArguments($matches); + $handler->setRouter($this); return $handler->getResponse(); } else { return $this->getNoRouteResponse($request); @@ -77,15 +79,15 @@ class Router } /** - * Prepare a Resonse indicating a 404 Not Found error + * Prepare a resonse indicating a 404 Not Found error * - * @param Request $request - * @return Response + * @param RequestInterface $request + * @return ResponseInterface */ - protected function getNoRouteResponse(Request $request) + protected function getNoRouteResponse(RequestInterface $request) { $response = new Response(404); - $response->body = 'No resource at ' . $request->uri; + $response->body = 'No resource at ' . $request->getPath(); return $response; }