Skip to content
This repository has been archived by the owner on Nov 2, 2018. It is now read-only.

Commit

Permalink
Zepto\Router now uses Response objects to return data to the clie…
Browse files Browse the repository at this point in the history
…nt, added HTTP methods as class constants, general code restructuring
  • Loading branch information
hassankhan committed Jan 29, 2014
1 parent b61f706 commit 266730e
Showing 1 changed file with 135 additions and 45 deletions.
180 changes: 135 additions & 45 deletions library/Zepto/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,30 @@
class Router
{

/**
* Supported HTTP Methods
*/
const METHOD_HEAD = 'HEAD';
const METHOD_GET = 'GET';
const METHOD_POST = 'POST';
const METHOD_PUT = 'PUT';
const METHOD_PATCH = 'PATCH';
const METHOD_DELETE = 'DELETE';
const METHOD_OPTIONS = 'OPTIONS';

/**
* Request object
*
* @var Symfony\Component\HttpFoundation\Request
*/
protected $request;

/**
* Response object
* @var Symfony\Component\HttpFoundation\Response
*/
protected $response;

/**
* Currently matched route, if one has been set
*
Expand Down Expand Up @@ -105,11 +122,18 @@ class Router
* @param string $url
* @codeCoverageIgnore
*/
public function __construct(\Symfony\Component\HttpFoundation\Request $request)
{
$this->request = $request;
public function __construct(
\Symfony\Component\HttpFoundation\Request $request,
\Symfony\Component\HttpFoundation\Response $response
) {
$this->request = $request;
$this->response = $response;
}

/**
* ROUTING
*/

/**
* Add HTTP GET route
*
Expand All @@ -133,7 +157,7 @@ public function get($route, \Closure $callback)
*/
public function post($route, \Closure $callback)
{
$this->route(new Route($route, $callback), 'POST');
$this->route(new Route($route, $callback), self::METHOD_POST);
}

/**
Expand All @@ -143,7 +167,7 @@ public function post($route, \Closure $callback)
* @param string $url
* @return Zepto\Route|null
*/
public function match($http_method = 'GET', $url)
public function match($http_method = self::METHOD_GET, $url)
{
// Make sure there is a trailing slash
$url = rtrim($url, '/') . '/';
Expand All @@ -157,8 +181,32 @@ public function match($http_method = 'GET', $url)
}

/**
* Tries to match one of the URL routes to the current URL, otherwise
* execute the not found handler
* Adds a new URL routing rule to the routing table, after converting any of
* our special tokens into proper regular expressions.
*
* @param Route $route
* @param string $http_method
* @throws Exception If the route already exists in the routing table
*/
protected function route(Route $route, $http_method = self::METHOD_GET)
{
// Does this URL already exist in the routing table?
if (isset($this->routes[$http_method][$route->get_pattern()])) {
// Trigger a new error and exception if errors are on
throw new \Exception('The URI {htmlspecialchars($route->get_url())} already exists in the routing table');
}

// Add the route to the routing table
$this->routes[$http_method][$route->get_pattern()] = $route;
}

/**
* ROUTE EXECUTION
*/

/**
* Runs the router matching engine and then calls the matching route's
* callback. otherwise execute the not found handler
*
* @return
*/
Expand All @@ -183,30 +231,38 @@ public function run()
// Get parameters from request
$params = $this->parse_parameters($route);

// Execute callback
call_user_func_array($route->get_callback(), $params);
// Execute callback, and set returned string as response content
$this->response->setContent(call_user_func_array($route->get_callback(), $params));

// Send response
$this->response->send();
}
}

/**
* Runs the router matching engine and then calls the matching route's callback.
* If no matching route is found, then returns false
* Tries to run the routing engine and generate a response, if any exceptions
* are thrown then it executes the error handler
*
* @uses Router::run()
* @return mixed
* @return
*/
public function execute()
{
try{
$this->run();
}
catch (Exception $e) {
echo $e->getMessage();

$this->error($e->getMessage());
// Add logging stuff here - maybe?
// Maybe make it do a HTTP 500 error?
}
}

/**
* ACCESSORS
*/

/**
* Returns all routes mapped on the routing table.
*
Expand All @@ -227,44 +283,90 @@ public function get_current_route()
return $this->current_route;
}

public function not_found($callback = null)
/**
* ERROR HANDLING
*/

/**
* This method can either set the callback to execute on a 'Server error' (50x)
* error, or it invokes the callback
* To set the callback, provide a function to the method
* To invoke the callback, call the method with a string detailing the error
* as a parameter
*
* @param Closure|string $arg
* @return
*/
public function error($arg = null)
{
if (is_callable($callback)) {
$this->not_found_handler = $callback;
if (is_callable($arg)) {
// Set provided callback function as error handler
$this->error_handler = $arg;
}
else {
if (is_callable($this->not_found_handler)) {
call_user_func(array($this, 'not_found_handler'));
// Execute error handler and set result as response content
if (is_callable($this->error_handler)) {
$this->response->setContent(call_user_func(array($this, 'error_handler'), $arg));
}
else {
call_user_func(array($this, 'default_not_found_handler'));
$this->response->setContent(call_user_func(array($this, 'default_error_handler'), $arg));
}

// Set response's status code
$this->response->setStatusCode(\Symfony\Component\HttpFoundation\Response::HTTP_INTERNAL_SERVER_ERROR);

// Send response
$this->response->send();
}
}

/**
* Adds a new URL routing rule to the routing table, after converting any of
* our special tokens into proper regular expressions.
* This method can either set the callback to execute on a 'Page not found' (404)
* error, or it invokes the callback
* To set the callback, provide a function to the method
* To invoke the callback, call the method without any parameters
*
* @param Route $route
* @param string $request_method
* @return boolean
* @throws Exception If the route already exists in the routing table
* @param Closure $callback
* @return
*/
protected function route(Route $route, $http_method = 'GET')
public function not_found($callback = null)
{
// Does this URL already exist in the routing table?
if (isset($this->routes[$http_method][$route->get_pattern()])) {
// Trigger a new error and exception if errors are on
throw new \Exception('The URI {htmlspecialchars($route->get_url())} already exists in the routing table');
if (is_callable($callback)) {
// Set provided callback function as not found handler
$this->not_found_handler = $callback;
}
else {
// Execute not found handler and set result as response content
if (is_callable($this->not_found_handler)) {
$this->response->setContent(call_user_func(array($this, 'not_found_handler')));
}
else {
$this->response->setContent(call_user_func(array($this, 'default_not_found_handler')));
}
// Set response's status code
$this->response->setStatusCode(\Symfony\Component\HttpFoundation\Response::HTTP_NOT_FOUND);

// Add the route to the routing array
$this->routes[$http_method][$route->get_pattern()] = $route;
// Send response
$this->response->send();
}
}

protected function default_not_found_handler()
{
// Use Twig to do something nice
// Generate a response
return "Didn't find anything";
}

return true;
protected function default_error_handler($error = '')
{
return 'Server error: ' . $error;
}

/**
* HELPER FUNCTIONS
*/

/**
* Parses parameters from URI as per the given route's pattern
*
Expand All @@ -288,16 +390,4 @@ protected function parse_parameters(Route $route)
return $params;
}

protected function default_not_found_handler()
{
// Use Twig to do something nice
// Generate a response
echo 'Didn\'t find anything';
}

protected function default_error_handler($error = '')
{
echo 'Server error';
}

}

0 comments on commit 266730e

Please sign in to comment.