Refactor for better PSR compliance. Still need to finish with samples.

This commit is contained in:
PJ Dietz 2013-01-24 21:27:57 -05:00
parent 3ff2371edd
commit 8597b9be06
19 changed files with 415 additions and 333 deletions

6
.gitignore vendored
View File

@ -0,0 +1,6 @@
# Composer
vendor/
# PhpStorm
workspace.xml

View File

@ -5,46 +5,54 @@ namespace apisample;
use pjdietz\WellRESTed\Router; use pjdietz\WellRESTed\Router;
use pjdietz\WellRESTed\Route; use pjdietz\WellRESTed\Route;
// TODO Revise with autoload required.
require_once(dirname(__FILE__) . '/../../Router.php');
/** /**
* Loads and instantiates handlers based on URI. * Loads and instantiates handlers based on URI.
*/ */
class ApiSampleRouter extends Router { class ApiSampleRouter extends Router
{
public function __construct() { public function __construct()
{
parent::__construct(); parent::__construct();
$this->addTemplate('/articles/', $this->addTemplate(
'ArticleCollectionHandler', '/articles/',
'ArticleCollectionHandler.php'); 'ArticleCollectionHandler',
'ArticleCollectionHandler.php'
);
$this->addTemplate('/articles/{id}', $this->addTemplate(
'ArticleItemHandler', '/articles/{id}',
'ArticleItemHandler.inc.php', 'ArticleItemHandler',
array('id' => Route::RE_NUM)); 'ArticleItemHandler.inc.php',
array('id' => Route::RE_NUM)
);
$this->addTemplate('/articles/{slug}', $this->addTemplate(
'ArticleItemHandler', '/articles/{slug}',
'ArticleItemHandler.inc.php', 'ArticleItemHandler',
array('slug' => Route::RE_SLUG)); 'ArticleItemHandler.inc.php',
array('slug' => Route::RE_SLUG)
);
} }
public function addTemplate($template, $handlerClassName, $handlerFilePath, $variables=null) { public function addTemplate($template, $handlerClassName, $handlerFilePath, $variables = null)
{
// Customize as needed based on your server. // Customize as needed based on your server.
$template = '/wellrested/samples/apisample' . $template; $template = '/wellrested/samples/apisample' . $template;
$handlerClassName = '\apisample\handlers\\' . $handlerClassName; $handlerClassName = '\apisample\handlers\\' . $handlerClassName;
$handlerFilePath = dirname(__FILE__) . '/handlers/' . $handlerFilePath; $handlerFilePath = dirname(__FILE__) . '/handlers/' . $handlerFilePath;
$this->addRoute(Route::newFromUriTemplate( $this->addRoute(
$template, $handlerClassName, $handlerFilePath, $variables)); Route::newFromUriTemplate(
$template,
$handlerClassName,
$handlerFilePath,
$variables
)
);
} }
} }
?>

View File

@ -5,60 +5,57 @@ namespace apisample;
/** /**
* Simple class for reading and writing articles to a text file. * Simple class for reading and writing articles to a text file.
*/ */
class ArticlesController { class ArticlesController
{
public $data; public $data;
protected $path; protected $path;
public function __construct() { public function __construct()
{
$this->path = dirname(__FILE__) . '/data/articles.json'; $this->path = dirname(__FILE__) . '/data/articles.json';
$this->load(); $this->load();
} }
public function load() { public function load()
{
if (file_exists($this->path)) { if (file_exists($this->path)) {
$data = file_get_contents($this->path); $data = file_get_contents($this->path);
$this->data = json_decode($data, true); $this->data = json_decode($data, true);
} }
} }
public function save() { public function save()
{
if (is_writable($this->path)) { if (is_writable($this->path)) {
$data = json_encode($this->data); $data = json_encode($this->data);
return file_put_contents($this->path, $data); return file_put_contents($this->path, $data);
} }
return false; return false;
} }
public function getArticleById($id) { public function getArticleById($id)
{
foreach ($this->data as $article) { foreach ($this->data as $article) {
if ($article['articleId'] == $id) { if ($article['articleId'] == $id) {
return $article; return $article;
} }
} }
return false; return false;
} }
public function getArticleBySlug($slug) { public function getArticleBySlug($slug)
{
foreach ($this->data as $article) { foreach ($this->data as $article) {
if ($article['slug'] == $slug) { if ($article['slug'] == $slug) {
return $article; return $article;
} }
} }
return false; return false;
} }
public function addArticle($newArticle) { public function addArticle($newArticle)
{
$validatedArticle = array( $validatedArticle = array(
'articleId' => $this->getNewId(), 'articleId' => $this->getNewId(),
'slug' => $newArticle['slug'], 'slug' => $newArticle['slug'],
@ -69,11 +66,10 @@ class ArticlesController {
$this->data[] = $validatedArticle; $this->data[] = $validatedArticle;
return $validatedArticle; return $validatedArticle;
} }
public function updateArticle($newArticle) { public function updateArticle($newArticle)
{
foreach ($this->data as &$oldArticle) { foreach ($this->data as &$oldArticle) {
if ($oldArticle['articleId'] == $newArticle['articleId']) { if ($oldArticle['articleId'] == $newArticle['articleId']) {
@ -86,11 +82,10 @@ class ArticlesController {
} }
return false; return false;
} }
public function removeArticle($id) { public function removeArticle($id)
{
foreach ($this->data as $index => $article) { foreach ($this->data as $index => $article) {
if ($article['articleId'] == $id) { if ($article['articleId'] == $id) {
unset($this->data[$index]); unset($this->data[$index]);
@ -99,12 +94,10 @@ class ArticlesController {
} }
return false; return false;
} }
protected function getNewId()
protected function getNewId() { {
$maxId = 0; $maxId = 0;
foreach ($this->data as $article) { foreach ($this->data as $article) {
@ -112,9 +105,6 @@ class ArticlesController {
} }
return $maxId + 1; return $maxId + 1;
} }
} }
?>

View File

@ -1,12 +1,9 @@
The apisample directory contains a mini API project that demonstrates the The apisample directory contains a mini API project that demonstrates the main features of Well RESTEd.
main features of Well RESTEd.
Resources Resources
--------- ---------
For this sample project, the only resources For this sample project, the only resources are "articles", which are kind of like little mini blog posts or news feed items. Each article contains the following fields:
are "articles", which are kind of like little mini blog posts or news feed
items. Each article contains the following fields:
articleId: Numeric unique identifier for the article articleId: Numeric unique identifier for the article
slug: A human readable unique identifier for the article slug: A human readable unique identifier for the article

View File

@ -2,18 +2,19 @@
namespace apisample\handlers; namespace apisample\handlers;
require_once(dirname(__FILE__) . '/../../../Handler.php'); use \pjdietz\WellRESTed\Handler;
require_once(dirname(__FILE__) . '/../ArticlesController.php');
/** /**
* Handler class for a list of articles. * Handler class for a list of articles.
*/ */
class ArticleCollectionHandler extends \pjdietz\WellRESTed\Handler { class ArticleCollectionHandler extends Handler
{
/** /**
* Respond to a GET request. * Respond to a GET request.
*/ */
protected function get() { protected function get()
{
// Display the list of articles. // Display the list of articles.
$articles = new \apisample\ArticlesController(); $articles = new \apisample\ArticlesController();
@ -37,7 +38,8 @@ class ArticleCollectionHandler extends \pjdietz\WellRESTed\Handler {
/** /**
* Respond to a POST request. * Respond to a POST request.
*/ */
protected function post() { protected function post()
{
// Read the request body, and ensure it is in the proper format. // Read the request body, and ensure it is in the proper format.
$article = json_decode($this->request->body, true); $article = json_decode($this->request->body, true);
@ -100,5 +102,3 @@ class ArticleCollectionHandler extends \pjdietz\WellRESTed\Handler {
} }
} }
?>

View File

@ -2,8 +2,7 @@
namespace apisample\handlers; namespace apisample\handlers;
require_once(dirname(__FILE__) . '/../../../Handler.php'); use \pjdietz\WellRESTed\Handler;
require_once(dirname(__FILE__) . '/../ArticlesController.php');
/** /**
* Handler class for one specific article. * Handler class for one specific article.
@ -11,12 +10,14 @@ require_once(dirname(__FILE__) . '/../ArticlesController.php');
* When instantiated by the Router, this class should receive an id or slug * When instantiated by the Router, this class should receive an id or slug
* argument to identify the article. * argument to identify the article.
*/ */
class ArticleItemHandler extends \pjdietz\WellRESTed\Handler { class ArticleItemHandler extends Handler
{
/** /**
* Respond to a GET request. * Respond to a GET request.
*/ */
protected function get() { protected function get()
{
// Read the list of articles. // Read the list of articles.
$articles = new \apisample\ArticlesController(); $articles = new \apisample\ArticlesController();
@ -53,7 +54,8 @@ class ArticleItemHandler extends \pjdietz\WellRESTed\Handler {
/** /**
* Respond to a PUT request. * Respond to a PUT request.
*/ */
protected function put() { protected function put()
{
// Read the request body, and ensure it is in the proper format. // Read the request body, and ensure it is in the proper format.
$article = json_decode($this->request->body, true); $article = json_decode($this->request->body, true);
@ -156,7 +158,8 @@ class ArticleItemHandler extends \pjdietz\WellRESTed\Handler {
/** /**
* Respond to a DELETE request. * Respond to a DELETE request.
*/ */
protected function delete() { protected function delete()
{
// Read the list of articles. // Read the list of articles.
$articles = new \apisample\ArticlesController(); $articles = new \apisample\ArticlesController();
@ -199,5 +202,3 @@ class ArticleItemHandler extends \pjdietz\WellRESTed\Handler {
} }
} }
?>

View File

@ -1,10 +1,8 @@
<?php <?php
require_once('ApiSampleRouter.php'); require_once('../../vendor/autoload.php');
$router = new \apisample\ApiSampleRouter(); $router = new \apisample\ApiSampleRouter();
$response = $router->getResponse(); $response = $router->getResponse();
$response->respond(); $response->respond();
exit; exit;
?>

View File

@ -9,12 +9,15 @@
* Please modify samples/client-side-endpoint.php to see results. * Please modify samples/client-side-endpoint.php to see results.
*/ */
// Include the Well RESTed Request and Response class files. // Include the autoload script.
require_once('../Request.php'); require_once('../vendor/autoload.php');
require_once('../Response.php');
use \pjdietz\WellRESTed\Request;
use \pjdietz\WellRESTed\Response;
use \pjdietz\WellRESTed\Exceptions\CurlException;
// Make a custom request to talk to the server. // Make a custom request to talk to the server.
$rqst = new \pjdietz\WellRESTed\Request(); $rqst = new Request();
// Use the client-site-endpoint.php script // Use the client-site-endpoint.php script
$rqst->hostname = $_SERVER['HTTP_HOST']; $rqst->hostname = $_SERVER['HTTP_HOST'];
@ -23,10 +26,10 @@ $rqst->path = '/wellrested/samples/server-side-response.php';
// Issue the request, and read the response returned by the server. // Issue the request, and read the response returned by the server.
try { try {
$resp = $rqst->request(); $resp = $rqst->request();
} catch (\wellrested\exceptions\CurlException $e) { } catch (CurlException $e) {
// Explain the cURL error and provide an error status code. // Explain the cURL error and provide an error status code.
$myResponse = new \wellrested\Response(); $myResponse = new Response();
$myResponse->statusCode = 500; $myResponse->statusCode = 500;
$myResponse->setHeader('Content-Type', 'text/plain'); $myResponse->setHeader('Content-Type', 'text/plain');
$myResponse->body = 'Message: ' .$e->getMessage() ."\n"; $myResponse->body = 'Message: ' .$e->getMessage() ."\n";
@ -37,7 +40,7 @@ try {
} }
// Create new response to send to output to the browser. // Create new response to send to output to the browser.
$myResponse = new \wellrested\Response(); $myResponse = new Response();
$myResponse->statusCode = 200; $myResponse->statusCode = 200;
$myResponse->setHeader('Content-Type', 'application/json'); $myResponse->setHeader('Content-Type', 'application/json');
@ -50,5 +53,3 @@ $myResponse->body = json_encode($json);
$myResponse->respond(); $myResponse->respond();
exit; exit;
?>

View File

@ -4,11 +4,13 @@
* This script will make a request to google and output the response. * This script will make a request to google and output the response.
*/ */
// Include the Well RESTed Request and Response class files. // Include the autoload script.
require_once('../Request.php'); require_once('../vendor/autoload.php');
use \pjdietz\WellRESTed\Request;
// Make a requst to Google in one line: // Make a requst to Google in one line:
$rqst = new \pjdietz\WellRESTed\Request(); $rqst = new Request();
$rqst->uri = 'https://www.google.com/search?q=my+search+terms'; $rqst->uri = 'https://www.google.com/search?q=my+search+terms';
// You could also set the members individually, like this: // You could also set the members individually, like this:
@ -23,5 +25,3 @@ $resp = $rqst->request();
// Output the response body and exit. // Output the response body and exit.
print $resp->body; print $resp->body;
exit; exit;
?>

View File

@ -7,15 +7,17 @@
* with JSON descrition of the original request. * with JSON descrition of the original request.
*/ */
// Include the Well RESTed Request and Response class files. // Include the autoload script.
require_once('../Request.php'); require_once('../vendor/autoload.php');
require_once('../Response.php');
use \pjdietz\WellRESTed\Request;
use \pjdietz\WellRESTed\Response;
// Read the request sent to the server as the singleton instance. // Read the request sent to the server as the singleton instance.
$rqst = \pjdietz\WellRESTed\Request::getRequest(); $rqst = Request::getRequest();
// Alternatively, you can create a new Request and call readHttpRequest(). // Alternatively, you can create a new Request and call readHttpRequest().
// $rqst = new \wellrested\Request(); // $rqst = new Request();
// $rqst->readHttpRequest(); // $rqst->readHttpRequest();
// Read some info from the request and store it to an associative array. // Read some info from the request and store it to an associative array.
@ -28,7 +30,7 @@ $rtn = array(
); );
// Create a new Response instance. // Create a new Response instance.
$resp = new \wellrested\Response(); $resp = new Response();
// Set the status code to 200 OK. // Set the status code to 200 OK.
$resp->statusCode = 200; $resp->statusCode = 200;
@ -42,5 +44,3 @@ $resp->body = json_encode($rtn);
// Output the response. // Output the response.
$resp->respond(); $resp->respond();
?>

View File

@ -4,14 +4,15 @@
* Create and output a response from the server. * Create and output a response from the server.
*/ */
require_once('../Response.php'); // Include the autoload script.
require_once('../vendor/autoload.php');
use \pjdietz\WellRESTed\Response;
// Create a new Response instance. // Create a new Response instance.
$resp = new \pjdietz\WellRESTed\Response(); $resp = new Response();
$resp->statusCode = 200; $resp->statusCode = 200;
$resp->setHeader('Content-Type', 'text/plain'); $resp->setHeader('Content-Type', 'text/plain');
$resp->body = 'This is a response.'; $resp->body = 'This is a response.';
$resp->respond(); $resp->respond();
exit; exit;
?>

View File

@ -2,9 +2,6 @@
namespace pjdietz\WellRESTed; namespace pjdietz\WellRESTed;
require_once(dirname(__FILE__) . '/Request.php');
require_once(dirname(__FILE__) . '/Response.php');
/******************************************************************************* /*******************************************************************************
* Handler * Handler
* *
@ -17,22 +14,26 @@ require_once(dirname(__FILE__) . '/Response.php');
/** /**
* @property Response response The Response to the request * @property Response response The Response to the request
*/ */
class Handler { class Handler
{
/** /**
* The HTTP request to respond to. * The HTTP request to respond to.
*
* @var Request * @var Request
*/ */
protected $request; protected $request;
/** /**
* The HTTP response to send based on the request. * The HTTP response to send based on the request.
*
* @var Response * @var Response
*/ */
protected $response; protected $response;
/** /**
* Matches array from the preg_match() call used to find this Handler. * Matches array from the preg_match() call used to find this Handler.
*
* @var array * @var array
*/ */
protected $args; protected $args;
@ -43,8 +44,8 @@ class Handler {
* @param Request $request * @param Request $request
* @param array $args * @param array $args
*/ */
public function __construct($request, $args=null) { public function __construct($request, $args = null)
{
$this->request = $request; $this->request = $request;
if (is_null($args)) { if (is_null($args)) {
@ -54,7 +55,6 @@ class Handler {
$this->response = new Response(); $this->response = new Response();
$this->buildResponse(); $this->buildResponse();
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@ -65,21 +65,21 @@ class Handler {
* @return Response * @return Response
* @throws \Exception * @throws \Exception
*/ */
public function __get($name) { public function __get($name)
{
switch ($name) { switch ($name) {
case 'response': case 'response':
return $this->getResponse(); return $this->getResponse();
default: default:
throw new \Exception('Property ' . $name . ' does not exist.'); throw new \Exception('Property ' . $name . ' does not exist.');
} }
} }
/** /**
* @return Response * @return Response
*/ */
public function getResponse() { public function getResponse()
{
return $this->response; return $this->response;
} }
@ -88,40 +88,39 @@ class Handler {
* repond to any non-standard HTTP methods. Otherwise, override the * repond to any non-standard HTTP methods. Otherwise, override the
* get, post, put, etc. methods. * get, post, put, etc. methods.
*/ */
protected function buildResponse() { protected function buildResponse()
{
switch ($this->request->method) { switch ($this->request->method) {
case 'GET': case 'GET':
$this->get(); $this->get();
break; break;
case 'HEAD': case 'HEAD':
$this->head(); $this->head();
break; break;
case 'POST': case 'POST':
$this->post(); $this->post();
break; break;
case 'PUT': case 'PUT':
$this->put(); $this->put();
break; break;
case 'DELETE': case 'DELETE':
$this->delete(); $this->delete();
break; break;
case 'PATCH': case 'PATCH':
$this->patch(); $this->patch();
break; break;
case 'OPTIONS': case 'OPTIONS':
$this->options(); $this->options();
break; break;
} }
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@ -136,15 +135,16 @@ class Handler {
/** /**
* Method for handling HTTP GET requests. * Method for handling HTTP GET requests.
*/ */
protected function get() { protected function get()
{
$this->response->statusCode = 405; $this->response->statusCode = 405;
} }
/** /**
* Method for handling HTTP HEAD requests. * Method for handling HTTP HEAD requests.
*/ */
protected function head() { protected function head()
{
// The default function calls the instance's get() method, then sets // The default function calls the instance's get() method, then sets
// the resonse's body member to an empty string. // the resonse's body member to an empty string.
@ -153,44 +153,46 @@ class Handler {
if ($this->response->statusCode == 200) { if ($this->response->statusCode == 200) {
$this->response->setBody('', false); $this->response->setBody('', false);
} }
} }
/** /**
* Method for handling HTTP POST requests. * Method for handling HTTP POST requests.
*/ */
protected function post() { protected function post()
{
$this->response->statusCode = 405; $this->response->statusCode = 405;
} }
/** /**
* Method for handling HTTP PUT requests. * Method for handling HTTP PUT requests.
*/ */
protected function put() { protected function put()
{
$this->response->statusCode = 405; $this->response->statusCode = 405;
} }
/** /**
* Method for handling HTTP DELETE requests. * Method for handling HTTP DELETE requests.
*/ */
protected function delete() { protected function delete()
{
$this->response->statusCode = 405; $this->response->statusCode = 405;
} }
/** /**
* Method for handling HTTP PATCH requests. * Method for handling HTTP PATCH requests.
*/ */
protected function patch() { protected function patch()
{
$this->response->statusCode = 405; $this->response->statusCode = 405;
} }
/** /**
* Method for handling HTTP OPTION requests. * Method for handling HTTP OPTION requests.
*/ */
protected function options() { protected function options()
{
$this->response->statusCode = 405; $this->response->statusCode = 405;
} }
} }
?>

View File

@ -8,8 +8,8 @@ namespace pjdietz\WellRESTed;
* @property string body Entity body of the message * @property string body Entity body of the message
* @property array headers Associative array of HTTP headers * @property array headers Associative array of HTTP headers
*/ */
abstract class Message { abstract class Message
{
/** /**
* Entity body of the message * Entity body of the message
* *
@ -35,12 +35,14 @@ abstract class Message {
/** /**
* Name of the protocol to use. * Name of the protocol to use.
*
* @var string * @var string
*/ */
protected $protocol = 'HTTP'; protected $protocol = 'HTTP';
/** /**
* Version of the protocol to use. * Version of the protocol to use.
*
* @var string * @var string
*/ */
protected $protocolVersion = '1.1'; protected $protocolVersion = '1.1';
@ -53,8 +55,8 @@ abstract class Message {
* @return array|string * @return array|string
* @throws \Exception * @throws \Exception
*/ */
public function __get($name) { public function __get($name)
{
switch ($name) { switch ($name) {
case 'body': case 'body':
return $this->getBody(); return $this->getBody();
@ -67,7 +69,6 @@ abstract class Message {
default: default:
throw new \Exception('Property ' . $name . ' does not exist.'); throw new \Exception('Property ' . $name . ' does not exist.');
} }
} }
/** /**
@ -75,8 +76,8 @@ abstract class Message {
* @param $value * @param $value
* @throws \Exception * @throws \Exception
*/ */
public function __set($name, $value) { public function __set($name, $value)
{
switch ($name) { switch ($name) {
case 'body': case 'body':
$this->setBody($value); $this->setBody($value);
@ -90,7 +91,6 @@ abstract class Message {
default: default:
throw new \Exception('Property ' . $name . 'does not exist or is read-only.'); throw new \Exception('Property ' . $name . 'does not exist or is read-only.');
} }
} }
/** /**
@ -98,7 +98,8 @@ abstract class Message {
* *
* @return string * @return string
*/ */
public function getBody() { public function getBody()
{
return $this->body; return $this->body;
} }
@ -107,7 +108,8 @@ abstract class Message {
* *
* @param string $body * @param string $body
*/ */
public function setBody($body) { public function setBody($body)
{
$this->body = $body; $this->body = $body;
} }
@ -116,7 +118,8 @@ abstract class Message {
* *
* @return array * @return array
*/ */
public function getHeaders() { public function getHeaders()
{
return $this->headers; return $this->headers;
} }
@ -126,8 +129,8 @@ abstract class Message {
* @param string $name * @param string $name
* @return string|bool * @return string|bool
*/ */
public function getHeader($name) { public function getHeader($name)
{
$lowerName = strtolower($name); $lowerName = strtolower($name);
if (isset($this->headerLookup[$lowerName])) { if (isset($this->headerLookup[$lowerName])) {
@ -141,7 +144,6 @@ abstract class Message {
} }
return false; return false;
} }
/** /**
@ -151,17 +153,16 @@ abstract class Message {
* @param $value * @param $value
* @param string $value * @param string $value
*/ */
public function setHeader($name, $value) { public function setHeader($name, $value)
{
$lowerName = strtolower($name); $lowerName = strtolower($name);
// Check if a mapping already exists for this header. // Check if a mapping already exists for this header.
// Remove it, if needed. // Remove it, if needed.
if (isset($this->headerLookup[$lowerName]) if (isset($this->headerLookup[$lowerName])
&& $this->headerLookup[$lowerName] !== $name) { && $this->headerLookup[$lowerName] !== $name
) {
unset($this->headers[$this->headerLookup[$lowerName]]); unset($this->headers[$this->headerLookup[$lowerName]]);
} }
// Store the actual header. // Store the actual header.
@ -169,7 +170,6 @@ abstract class Message {
// Store a mapping to the user's prefered case. // Store a mapping to the user's prefered case.
$this->headerLookup[$lowerName] = $name; $this->headerLookup[$lowerName] = $name;
} }
/** /**
@ -178,7 +178,8 @@ abstract class Message {
* @param $name * @param $name
* @return bool * @return bool
*/ */
public function hasHeader($name) { public function hasHeader($name)
{
$lowerName = strtolower($name); $lowerName = strtolower($name);
return isset($this->headerLookup[$lowerName]); return isset($this->headerLookup[$lowerName]);
} }
@ -188,8 +189,8 @@ abstract class Message {
* *
* @param string $name * @param string $name
*/ */
public function unsetHeader($name) { public function unsetHeader($name)
{
$lowerName = strtolower($name); $lowerName = strtolower($name);
if (isset($this->headerLookup[$lowerName])) { if (isset($this->headerLookup[$lowerName])) {
@ -203,43 +204,42 @@ abstract class Message {
unset($this->headerLookup[$lowerName]); unset($this->headerLookup[$lowerName]);
} }
} }
/** /**
* @return string * @return string
*/ */
public function getProtocol() { public function getProtocol()
{
return $this->protocol; return $this->protocol;
} }
/** /**
* @param $protocol * @param $protocol
*/ */
public function setProtocol($protocol) { public function setProtocol($protocol)
{
if (strpos($protocol, '/') === false) { if (strpos($protocol, '/') === false) {
list($this->protocol, $this->protocolVersion) = explode('/', $protocol, 2); list($this->protocol, $this->protocolVersion) = explode('/', $protocol, 2);
} else { } else {
$this->protocol = $protocol; $this->protocol = $protocol;
} }
} }
/** /**
* @return string * @return string
*/ */
public function getProtocolVersion() { public function getProtocolVersion()
{
return $this->protocolVersion; return $this->protocolVersion;
} }
/** /**
* @param string $protocolVersion * @param string $protocolVersion
*/ */
public function setProtocolVersion($protocolVersion) { public function setProtocolVersion($protocolVersion)
{
$this->protocolVersion = $protocolVersion; $this->protocolVersion = $protocolVersion;
} }
} }
?>

View File

@ -2,10 +2,6 @@
namespace pjdietz\WellRESTed; namespace pjdietz\WellRESTed;
require_once(dirname(__FILE__) . '/Message.php');
require_once(dirname(__FILE__) . '/Response.php');
require_once(dirname(__FILE__) . '/exceptions/CurlException.php');
// TODO: Include port in the URI // TODO: Include port in the URI
/** /**
@ -27,8 +23,8 @@ require_once(dirname(__FILE__) . '/exceptions/CurlException.php');
* *
* @package WellRESTed * @package WellRESTed
*/ */
class Request extends Message { class Request extends Message
{
/** /**
* The Hostname for the request (e.g., www.google.com) * The Hostname for the request (e.g., www.google.com)
* *
@ -80,8 +76,8 @@ class Request extends Message {
* @return array|string * @return array|string
* @throws \Exception * @throws \Exception
*/ */
public function __get($name) { public function __get($name)
{
switch ($name) { switch ($name) {
case 'hostname': case 'hostname':
return $this->getHostname(); return $this->getHostname();
@ -98,7 +94,6 @@ class Request extends Message {
default: default:
return parent::__get($name); return parent::__get($name);
} }
} }
/** /**
@ -106,8 +101,8 @@ class Request extends Message {
* @param mixed $value * @param mixed $value
* @throws \Exception * @throws \Exception
*/ */
public function __set($name, $value) { public function __set($name, $value)
{
switch ($name) { switch ($name) {
case 'hostname': case 'hostname':
$this->setHostname($value); $this->setHostname($value);
@ -127,34 +122,37 @@ class Request extends Message {
default: default:
parent::__set($name, $value); parent::__set($name, $value);
} }
} }
/** /**
* @return string * @return string
*/ */
public function getHostname() { public function getHostname()
{
return $this->hostname; return $this->hostname;
} }
/** /**
* @param string $hostname * @param string $hostname
*/ */
public function setHostname($hostname) { public function setHostname($hostname)
{
$this->hostname = $hostname; $this->hostname = $hostname;
} }
/** /**
* @return string * @return string
*/ */
public function getMethod() { public function getMethod()
{
return $this->method; return $this->method;
} }
/** /**
* @param string $method * @param string $method
*/ */
public function setMethod($method) { public function setMethod($method)
{
$this->method = $method; $this->method = $method;
} }
@ -163,7 +161,8 @@ class Request extends Message {
* *
* @return string * @return string
*/ */
public function getPath() { public function getPath()
{
return $this->path; return $this->path;
} }
@ -172,7 +171,8 @@ class Request extends Message {
* *
* @param string $path * @param string $path
*/ */
public function setPath($path) { public function setPath($path)
{
$this->path = $path; $this->path = $path;
$this->pathParts = explode('/', substr($path, 1)); $this->pathParts = explode('/', substr($path, 1));
} }
@ -182,7 +182,8 @@ class Request extends Message {
* *
* @return array * @return array
*/ */
public function getPathParts() { public function getPathParts()
{
return $this->pathParts; return $this->pathParts;
} }
@ -191,7 +192,8 @@ class Request extends Message {
* *
* @return array * @return array
*/ */
public function getQuery() { public function getQuery()
{
return $this->query; return $this->query;
} }
@ -202,8 +204,8 @@ class Request extends Message {
* @param string|array $query * @param string|array $query
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
*/ */
public function setQuery($query) { public function setQuery($query)
{
if (is_string($query)) { if (is_string($query)) {
$qs = $query; $qs = $query;
parse_str($qs, $query); parse_str($qs, $query);
@ -214,7 +216,6 @@ class Request extends Message {
} else { } else {
throw new \InvalidArgumentException('Unable to parse query string.'); throw new \InvalidArgumentException('Unable to parse query string.');
} }
} }
/** /**
@ -222,8 +223,8 @@ class Request extends Message {
* *
* @return array * @return array
*/ */
public function getUri() { public function getUri()
{
$uri = strtolower($this->protocol) . '://' . $this->hostname . $this->path; $uri = strtolower($this->protocol) . '://' . $this->hostname . $this->path;
if ($this->query) { if ($this->query) {
@ -231,7 +232,6 @@ class Request extends Message {
} }
return $uri; return $uri;
} }
/** /**
@ -240,8 +240,8 @@ class Request extends Message {
* *
* @param string $uri * @param string $uri
*/ */
public function setUri($uri) { public function setUri($uri)
{
$parsed = parse_url($uri); $parsed = parse_url($uri);
$host = isset($parsed['host']) ? $parsed['host'] : ''; $host = isset($parsed['host']) ? $parsed['host'] : '';
@ -252,7 +252,6 @@ class Request extends Message {
$query = isset($parsed['query']) ? $parsed['query'] : ''; $query = isset($parsed['query']) ? $parsed['query'] : '';
$this->setQuery($query); $this->setQuery($query);
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@ -263,8 +262,8 @@ class Request extends Message {
* @return Response * @return Response
* @throws exceptions\CurlException * @throws exceptions\CurlException
*/ */
public function request() { public function request()
{
$ch = curl_init(); $ch = curl_init();
// Set the URL. // Set the URL.
@ -333,14 +332,13 @@ class Request extends Message {
curl_close($ch); curl_close($ch);
return $resp; return $resp;
} }
/** /**
* Set instance members based on the HTTP request sent to the server. * Set instance members based on the HTTP request sent to the server.
*/ */
public function readHttpRequest() { public function readHttpRequest()
{
$this->setBody(file_get_contents("php://input"), false); $this->setBody(file_get_contents("php://input"), false);
$this->headers = apache_request_headers(); $this->headers = apache_request_headers();
@ -352,7 +350,6 @@ class Request extends Message {
$this->method = $_SERVER['REQUEST_METHOD']; $this->method = $_SERVER['REQUEST_METHOD'];
$this->uri = $_SERVER['REQUEST_URI']; $this->uri = $_SERVER['REQUEST_URI'];
$this->hostname = $_SERVER['HTTP_HOST']; $this->hostname = $_SERVER['HTTP_HOST'];
} }
/** /**
@ -362,8 +359,8 @@ class Request extends Message {
* @return Request * @return Request
* @static * @static
*/ */
public static function getRequest() { public static function getRequest()
{
if (!isset(self::$theRequest)) { if (!isset(self::$theRequest)) {
$klass = __CLASS__; $klass = __CLASS__;
@ -375,9 +372,6 @@ class Request extends Message {
} }
return self::$theRequest; return self::$theRequest;
} }
} }
?>

View File

@ -2,8 +2,6 @@
namespace pjdietz\WellRESTed; namespace pjdietz\WellRESTed;
require_once(dirname(__FILE__) . '/Message.php');
/******************************************************************************* /*******************************************************************************
* Response * Response
* *
@ -19,7 +17,8 @@ require_once(dirname(__FILE__) . '/Message.php');
* @property int statusCode HTTP status code * @property int statusCode HTTP status code
* @property string statusLine HTTP status line, e.g. "HTTP/1.1 200 OK" * @property string statusLine HTTP status line, e.g. "HTTP/1.1 200 OK"
*/ */
class Response extends Message { class Response extends Message
{
/** /**
* Text explanation of the HTTP Status Code. You only need to set this if * Text explanation of the HTTP Status Code. You only need to set this if
@ -32,6 +31,7 @@ class Response extends Message {
/** /**
* HTTP status code * HTTP status code
*
* @var int * @var int
*/ */
protected $statusCode; protected $statusCode;
@ -46,14 +46,14 @@ class Response extends Message {
* @param string $body * @param string $body
* @param array $headers * @param array $headers
*/ */
public function __construct($statusCode=500, $body=null, $headers=null) { public function __construct($statusCode = 500, $body = null, $headers = null)
{
$this->statusCode = $statusCode; $this->statusCode = $statusCode;
if (is_array($headers)) { if (is_array($headers)) {
$this->headers = $headers; $this->headers = $headers;
} else { } else {
$this->headers = array(); $this->headers = array();
} }
if (!is_null($body)) { if (!is_null($body)) {
@ -76,8 +76,8 @@ class Response extends Message {
* @return array|string * @return array|string
* @throws \Exception * @throws \Exception
*/ */
public function __get($name) { public function __get($name)
{
switch ($name) { switch ($name) {
case 'reasonPhrase': case 'reasonPhrase':
return $this->getReasonPhrase(); return $this->getReasonPhrase();
@ -88,7 +88,6 @@ class Response extends Message {
default: default:
return parent::__get($name); return parent::__get($name);
} }
} }
/** /**
@ -96,8 +95,8 @@ class Response extends Message {
* @param mixed $value * @param mixed $value
* @throws \Exception * @throws \Exception
*/ */
public function __set($name, $value) { public function __set($name, $value)
{
switch ($name) { switch ($name) {
case 'reasonPhrase': case 'reasonPhrase':
$this->setReasonPhrase($value); $this->setReasonPhrase($value);
@ -108,7 +107,6 @@ class Response extends Message {
default: default:
parent::__set($name, $value); parent::__set($name, $value);
} }
} }
/** /**
@ -119,34 +117,36 @@ class Response extends Message {
* @param string $value * @param string $value
* @param bool $setContentLength Automatically add a Content-length header * @param bool $setContentLength Automatically add a Content-length header
*/ */
public function setBody($value, $setContentLength=true) { public function setBody($value, $setContentLength = true)
{
$this->body = $value; $this->body = $value;
if ($setContentLength === true) { if ($setContentLength === true) {
$this->setHeader('Content-Length', strlen($value)); $this->setHeader('Content-Length', strlen($value));
} }
} }
/** /**
* @return string * @return string
*/ */
public function getReasonPhrase() { public function getReasonPhrase()
{
return $this->reasonPhrase; return $this->reasonPhrase;
} }
/** /**
* @param string $statusCodeMessage * @param string $statusCodeMessage
*/ */
public function setReasonPhrase($statusCodeMessage) { public function setReasonPhrase($statusCodeMessage)
{
$this->reasonPhrase = $statusCodeMessage; $this->reasonPhrase = $statusCodeMessage;
} }
/** /**
* @return int * @return int
*/ */
public function getStatusCode() { public function getStatusCode()
{
return $this->statusCode; return $this->statusCode;
} }
@ -156,51 +156,127 @@ class Response extends Message {
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
* @return void * @return void
*/ */
public function setStatusCode($statusCode, $reasonPhrase=null) { public function setStatusCode($statusCode, $reasonPhrase = null)
{
$this->statusCode = (int) $statusCode; $this->statusCode = (int)$statusCode;
if (is_null($reasonPhrase)) { if (is_null($reasonPhrase)) {
switch ($this->statusCode) { switch ($this->statusCode) {
case 100: $text = 'Continue'; break; case 100:
case 101: $text = 'Switching Protocols'; break; $text = 'Continue';
case 200: $text = 'OK'; break; break;
case 201: $text = 'Created'; break; case 101:
case 202: $text = 'Accepted'; break; $text = 'Switching Protocols';
case 203: $text = 'Non-Authoritative Information'; break; break;
case 204: $text = 'No Content'; break; case 200:
case 205: $text = 'Reset Content'; break; $text = 'OK';
case 206: $text = 'Partial Content'; break; break;
case 300: $text = 'Multiple Choices'; break; case 201:
case 301: $text = 'Moved Permanently'; break; $text = 'Created';
case 302: $text = 'Moved Temporarily'; break; break;
case 303: $text = 'See Other'; break; case 202:
case 304: $text = 'Not Modified'; break; $text = 'Accepted';
case 305: $text = 'Use Proxy'; break; break;
case 400: $text = 'Bad Request'; break; case 203:
case 401: $text = 'Unauthorized'; break; $text = 'Non-Authoritative Information';
case 402: $text = 'Payment Required'; break; break;
case 403: $text = 'Forbidden'; break; case 204:
case 404: $text = 'Not Found'; break; $text = 'No Content';
case 405: $text = 'Method Not Allowed'; break; break;
case 406: $text = 'Not Acceptable'; break; case 205:
case 407: $text = 'Proxy Authentication Required'; break; $text = 'Reset Content';
case 408: $text = 'Request Time-out'; break; break;
case 409: $text = 'Conflict'; break; case 206:
case 410: $text = 'Gone'; break; $text = 'Partial Content';
case 411: $text = 'Length Required'; break; break;
case 412: $text = 'Precondition Failed'; break; case 300:
case 413: $text = 'Request Entity Too Large'; break; $text = 'Multiple Choices';
case 414: $text = 'Request-URI Too Large'; break; break;
case 415: $text = 'Unsupported Media Type'; break; case 301:
case 500: $text = 'Internal Server Error'; break; $text = 'Moved Permanently';
case 501: $text = 'Not Implemented'; break; break;
case 502: $text = 'Bad Gateway'; break; case 302:
case 503: $text = 'Service Unavailable'; break; $text = 'Moved Temporarily';
case 504: $text = 'Gateway Time-out'; break; break;
case 505: $text = 'HTTP Version not supported'; break; case 303:
default: $text = 'Nonstandard'; break; $text = 'See Other';
break;
case 304:
$text = 'Not Modified';
break;
case 305:
$text = 'Use Proxy';
break;
case 400:
$text = 'Bad Request';
break;
case 401:
$text = 'Unauthorized';
break;
case 402:
$text = 'Payment Required';
break;
case 403:
$text = 'Forbidden';
break;
case 404:
$text = 'Not Found';
break;
case 405:
$text = 'Method Not Allowed';
break;
case 406:
$text = 'Not Acceptable';
break;
case 407:
$text = 'Proxy Authentication Required';
break;
case 408:
$text = 'Request Time-out';
break;
case 409:
$text = 'Conflict';
break;
case 410:
$text = 'Gone';
break;
case 411:
$text = 'Length Required';
break;
case 412:
$text = 'Precondition Failed';
break;
case 413:
$text = 'Request Entity Too Large';
break;
case 414:
$text = 'Request-URI Too Large';
break;
case 415:
$text = 'Unsupported Media Type';
break;
case 500:
$text = 'Internal Server Error';
break;
case 501:
$text = 'Not Implemented';
break;
case 502:
$text = 'Bad Gateway';
break;
case 503:
$text = 'Service Unavailable';
break;
case 504:
$text = 'Gateway Time-out';
break;
case 505:
$text = 'HTTP Version not supported';
break;
default:
$text = 'Nonstandard';
break;
} }
$this->reasonPhrase = $text; $this->reasonPhrase = $text;
@ -222,12 +298,15 @@ class Response extends Message {
* *
* @return string * @return string
*/ */
protected function getStatusLine() { protected function getStatusLine()
return sprintf('%s/%s %s %s', {
strtoupper($this->protocol), return sprintf(
$this->protocolVersion, '%s/%s %s %s',
$this->statusCode, strtoupper($this->protocol),
$this->reasonPhrase); $this->protocolVersion,
$this->statusCode,
$this->reasonPhrase
);
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@ -237,8 +316,8 @@ class Response extends Message {
* *
* @param bool $headersOnly Do not include the body, only the headers. * @param bool $headersOnly Do not include the body, only the headers.
*/ */
public function respond($headersOnly=false) { public function respond($headersOnly = false)
{
// Output the HTTP status code. // Output the HTTP status code.
header($this->statusLine); header($this->statusLine);
@ -251,9 +330,6 @@ class Response extends Message {
if (!$headersOnly && isset($this->body)) { if (!$headersOnly && isset($this->body)) {
print $this->body; print $this->body;
} }
} }
} }
?>

View File

@ -9,8 +9,8 @@ namespace pjdietz\WellRESTed;
* *
******************************************************************************/ ******************************************************************************/
class Route { class Route
{
const RE_SLUG = '[0-9a-zA-Z\-_]+'; const RE_SLUG = '[0-9a-zA-Z\-_]+';
const RE_NUM = '[0-9]+'; const RE_NUM = '[0-9]+';
const RE_ALPHA = '[a-zA-Z]+'; const RE_ALPHA = '[a-zA-Z]+';
@ -20,24 +20,28 @@ class Route {
/** /**
* Regular Expression to use to validate a template variable. * Regular Expression to use to validate a template variable.
*
* @var string * @var string
*/ */
static public $defaultVariablePattern = self::RE_SLUG; static public $defaultVariablePattern = self::RE_SLUG;
/** /**
* Regular expression used to match a Request URI path component * Regular expression used to match a Request URI path component
*
* @var string * @var string
*/ */
public $pattern; public $pattern;
/** /**
* Name of the Handler class to use * Name of the Handler class to use
*
* @var string * @var string
*/ */
public $handler; public $handler;
/** /**
* The path to the source file defing the handler class. * The path to the source file defing the handler class.
*
* @var string * @var string
*/ */
public $handlerPath; public $handlerPath;
@ -47,13 +51,12 @@ class Route {
* @param $handler * @param $handler
* @param $handlerPath * @param $handlerPath
*/ */
public function __construct($pattern, $handler, $handlerPath=null) { public function __construct($pattern, $handler, $handlerPath = null)
{
$this->pattern = $pattern; $this->pattern = $pattern;
$this->handler = $handler; $this->handler = $handler;
$this->handlerPath = $handlerPath; $this->handlerPath = $handlerPath;
}
} // __construct
/** /**
* Create a new Route using a URI template to generate the pattern. * Create a new Route using a URI template to generate the pattern.
@ -65,9 +68,12 @@ class Route {
* @throws \Exception * @throws \Exception
* @return Route * @return Route
*/ */
static public function newFromUriTemplate($uriTemplate, $handler, static public function newFromUriTemplate(
$handlerPath=null, $uriTemplate,
$variables=null) { $handler,
$handlerPath = null,
$variables = null
) {
$pattern = ''; $pattern = '';
@ -83,8 +89,12 @@ class Route {
$pattern .= '\/'; $pattern .= '\/';
// Is this part an expression or a literal? // Is this part an expression or a literal?
if (preg_match(self::URI_TEMPLATE_EXPRESSION_RE, if (preg_match(
$part, $matches)) { self::URI_TEMPLATE_EXPRESSION_RE,
$part,
$matches
)
) {
// This part of the path is an expresion. // This part of the path is an expresion.
@ -102,8 +112,11 @@ class Route {
$variablePattern = self::$defaultVariablePattern; $variablePattern = self::$defaultVariablePattern;
} }
$pattern .= sprintf('(?<%s>%s)', $variableName, $pattern .= sprintf(
$variablePattern); '(?<%s>%s)',
$variableName,
$variablePattern
);
} else { } else {
// Not sure why this would happen. // Not sure why this would happen.
@ -126,5 +139,3 @@ class Route {
} }
} }
?>

View File

@ -2,10 +2,6 @@
namespace pjdietz\WellRESTed; namespace pjdietz\WellRESTed;
require_once(dirname(__FILE__) . '/Request.php');
require_once(dirname(__FILE__) . '/Response.php');
require_once(dirname(__FILE__) . '/Route.php');
/******************************************************************************* /*******************************************************************************
* Router * Router
* *
@ -16,31 +12,38 @@ require_once(dirname(__FILE__) . '/Route.php');
* *
******************************************************************************/ ******************************************************************************/
class Router { class Router
{
/**
* Array of \WellRESTed\Route objects
* @var array
*/
protected $routes; protected $routes;
/** /**
* Create a new Router. * Create a new Router.
*/ */
public function __construct() { public function __construct()
{
$this->routes = array(); $this->routes = array();
} }
/** /**
* Append a new Route instance to the Router's route table. * Append a new Route instance to the Router's route table.
*
* @param $route * @param $route
*/ */
public function addRoute(Route $route) { public function addRoute(Route $route)
{
$this->routes[] = $route; $this->routes[] = $route;
} // addRoute() }
/** /**
* @param Request $request * @param Request $request
* @return Response * @return Response
*/ */
public function getResponse($request=null) { public function getResponse($request = null)
{
if (is_null($request)) { if (is_null($request)) {
$request = Request::getRequest(); $request = Request::getRequest();
} }
@ -54,7 +57,7 @@ class Router {
$klass = $route->handler; $klass = $route->handler;
// Autoload, if needed. // Autoload, if needed.
if (!class_exists($klass) && is_string($route->handlerPath)) { if (is_string($route->handlerPath) && !class_exists($klass)) {
require_once($route->handlerPath); require_once($route->handlerPath);
} }
@ -66,21 +69,17 @@ class Router {
} }
return $this->getNoRouteResponse($request); return $this->getNoRouteResponse($request);
}
} // getRequestHandler()
/** /**
* @param Request $request * @param Request $request
* @return Response * @return Response
*/ */
protected function getNoRouteResponse(Request $request) { protected function getNoRouteResponse(Request $request)
{
$response = new Response(404); $response = new Response(404);
$response->body = 'No resource at ' . $request->uri; $response->body = 'No resource at ' . $request->uri;
return $response; return $response;
} }
} }
?>

View File

@ -1,8 +1,6 @@
<?php <?php
namespace pjdietz\WellRESTed\exceptions; namespace pjdietz\WellRESTed\Exceptions;
require_once(dirname(__FILE__) . '/WellrestedException.php');
/** /**
* Exception related to a cURL operation. The message and code should correspond * Exception related to a cURL operation. The message and code should correspond

View File

@ -1,6 +1,6 @@
<?php <?php
namespace pjdietz\WellRESTed\exceptions; namespace pjdietz\WellRESTed\Exceptions;
/** /**
* Top level class for custom exceptions thrown by Well RESTed. * Top level class for custom exceptions thrown by Well RESTed.