Major refactoring, implemented namespaces

pull/11/head
Mike Cao 13 years ago
parent 8af17f2215
commit e2f1dc99bb

@ -5,48 +5,36 @@
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com> * @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
class Flight {
/**
* Stored variables.
*
* @var array
*/
protected static $vars = array();
/** include __DIR__.'/core/Loader.php';
* Registered classes. include __DIR__.'/core/Dispatcher.php';
*
* @var array
*/
protected static $classes = array();
/** /**
* Mapped methods. * The Flight class represents the framework itself. It is responsible
* * loading an HTTP request, running the assigned services, and generating
* @var array * an HTTP response.
*/ */
protected static $methods = array(); class Flight {
/** /**
* Method filters. * Stored variables.
* *
* @var array * @var array
*/ */
protected static $filters = array(); protected static $vars = array();
/** /**
* Class instances. * Class loader.
* *
* @var array * @var object
*/ */
protected static $instances = array(); protected static $loader;
/** /**
* Autoload directories. * Event dispatcher.
* *
* @var array * @var object
*/ */
protected static $dirs = array(); protected static $dispatcher;
// Don't allow object instantiation // Don't allow object instantiation
private function __construct() {} private function __construct() {}
@ -60,28 +48,15 @@ class Flight {
* @param array $args Method parameters * @param array $args Method parameters
*/ */
public static function __callStatic($name, $params) { public static function __callStatic($name, $params) {
// Check if call is mapped to a method $callback = self::$dispatcher->get($name);
if (isset(self::$methods[$name]) || method_exists(__CLASS__, '_'.$name)) {
$method = self::$methods[$name] ?: array(__CLASS__, '_'.$name);
// Run pre-filters if (is_callable($callback)) {
if (!empty(self::$filters['before'][$name])) { return self::$dispatcher->run($name, $params);
self::filter(self::$filters['before'][$name], $params);
} }
// Run requested method $shared = (!empty($params)) ? (bool)$params[0] : true;
$output = self::execute($method, $params);
// Run post-filters
if (!empty(self::$filters['after'][$name])) {
self::filter(self::$filters['after'][$name], $output);
}
return $output; return self::$loader->load($name, $shared);
}
// Otherwise try to autoload class
return self::load($name, (!empty($params)) ? (bool)$params[0] : true);
} }
/** /**
@ -95,7 +70,7 @@ class Flight {
throw new Exception('Cannot override an existing framework method.'); throw new Exception('Cannot override an existing framework method.');
} }
self::$methods[$name] = $callback; self::$dispatcher->set($name, $callback);
} }
/** /**
@ -111,40 +86,7 @@ class Flight {
throw new Exception('Cannot override an existing framework method.'); throw new Exception('Cannot override an existing framework method.');
} }
unset(self::$instances[$class]); self::$loader->register($name, $class, $params, $callback);
self::$classes[$name] = array($class, $params, $callback);
}
/**
* Loads a registered class.
*
* @param string $name Method name
* @param bool $shared Shared instance
*/
public static function load($name, $shared = true) {
if (isset(self::$classes[$name])) {
list($class, $params, $callback) = self::$classes[$name];
$do_callback = ($callback && (!$shared || !isset(self::$instances[$class])));
$obj = ($shared) ?
self::getInstance($class, $params) :
self::getClass($class, $params);
if ($do_callback) {
$ref = array(&$obj);
self::execute($callback, $ref);
}
return $obj;
}
$class = ucfirst($name);
return ($shared) ?
self::getInstance($class) :
self::getClass($class);
} }
/** /**
@ -154,7 +96,7 @@ class Flight {
* @param callback $callback Callback function * @param callback $callback Callback function
*/ */
public static function before($name, $callback) { public static function before($name, $callback) {
self::$filters['before'][$name][] = $callback; self::$dispatcher->hook($name, 'before', $callback);
} }
/** /**
@ -164,128 +106,16 @@ class Flight {
* @param callback $callback Callback function * @param callback $callback Callback function
*/ */
public static function after($name, $callback) { public static function after($name, $callback) {
self::$filters['after'][$name][] = $callback; self::$dispatcher->hook($name, 'after', $callback);
} }
/** /**
* Executes a callback function. * Adds a path for class autoloading.
* *
* @param callback $callback Callback function * @param string $dir Directory path
* @param array $params Function parameters
* @return mixed Function results
*/ */
public static function execute($callback, array &$params = array()) { public static function path($dir) {
if (is_callable($callback)) { self::$loader->addDirectory($dir);
return is_array($callback) ?
self::invokeMethod($callback, $params) :
self::callFunction($callback, $params);
}
}
/**
* Executes a chain of method filters.
*
* @param array $filters Chain of filters
* @param reference $data Method parameters or method output
*/
public static function filter($filters, &$data) {
$params = array(&$data);
foreach ($filters as $callback) {
$continue = self::execute($callback, $params);
if ($continue === false) break;
}
}
/**
* Calls a function.
*
* @param string $func Name of function to call
* @param array $params Function parameters
*/
public static function callFunction($func, array &$params = array()) {
switch (count($params)) {
case 0:
return $func();
case 1:
return $func($params[0]);
case 2:
return $func($params[0], $params[1]);
case 3:
return $func($params[0], $params[1], $params[2]);
case 4:
return $func($params[0], $params[1], $params[2], $params[3]);
case 5:
return $func($params[0], $params[1], $params[2], $params[3], $params[4]);
default:
return call_user_func_array($func, $params);
}
}
/**
* Invokes a method.
*
* @param mixed $func Class method
* @param array $params Class method parameters
*/
public static function invokeMethod($func, array &$params = array()) {
list($class, $method) = $func;
switch (count($params)) {
case 0:
return $class::$method();
case 1:
return $class::$method($params[0]);
case 2:
return $class::$method($params[0], $params[1]);
case 3:
return $class::$method($params[0], $params[1], $params[2]);
case 4:
return $class::$method($params[0], $params[1], $params[2], $params[3]);
case 5:
return $class::$method($params[0], $params[1], $params[2], $params[3], $params[4]);
default:
return call_user_func_array($func, $params);
}
}
/**
* Gets a single instance of a class.
*
* @param string $class Class name
* @param array $params Class initialization parameters
*/
public static function getInstance($class, array $params = array()) {
if (!isset(self::$instances[$class])) {
self::$instances[$class] = self::getClass($class, $params);
}
return self::$instances[$class];
}
/**
* Gets a class object.
*
* @param string $class Class name
* @param array $params Class initialization parameters
*/
public static function getClass($class, array $params = array()) {
switch (count($params)) {
case 0:
return new $class();
case 1:
return new $class($params[0]);
case 2:
return new $class($params[0], $params[1]);
case 3:
return new $class($params[0], $params[1], $params[2]);
case 4:
return new $class($params[0], $params[1], $params[2], $params[3]);
case 5:
return new $class($params[0], $params[1], $params[2], $params[3], $params[4]);
default:
$refClass = new ReflectionClass($class);
return $refClass->newInstanceArgs($params);
}
} }
/** /**
@ -317,12 +147,12 @@ class Flight {
} }
/** /**
* Checks if a variable exists. * Checks if a variable has been set.
* *
* @param string $key Key * @param string $key Key
* @return bool Variable status * @return bool Variable status
*/ */
public static function exists($key) { public static function has($key) {
return isset(self::$vars[$key]); return isset(self::$vars[$key]);
} }
@ -347,9 +177,6 @@ class Flight {
static $initialized = false; static $initialized = false;
if (!$initialized) { if (!$initialized) {
// Register autoloader
spl_autoload_register(array(__CLASS__, 'autoload'));
// Handle errors internally // Handle errors internally
set_error_handler(array(__CLASS__, 'handleError')); set_error_handler(array(__CLASS__, 'handleError'));
@ -369,31 +196,33 @@ class Flight {
$_COOKIE = array_map($func, $_COOKIE); $_COOKIE = array_map($func, $_COOKIE);
} }
// Enable output buffering // Load core components
ob_start(); self::$loader = new \flight\core\Loader();
self::$dispatcher = new \flight\core\Dispatcher();
$initialized = true; // Register default components
} self::$loader->addDirectory(dirname(__DIR__));
} self::$loader->register('request', '\flight\net\Request');
self::$loader->register('response', '\flight\net\Response');
self::$loader->register('router', '\flight\net\Router');
self::$loader->register('view', '\flight\template\View', array(), function($view){
$view->path = Flight::get('flight.views.path') ?: './views';
});
/** // Register framework methods
* Autoloads classes. $methods = array(
* 'start','stop','route','halt','error','notFound',
* @param string $class Class name 'render','redirect','etag','lastModified','json'
*/ );
public static function autoload($class) {
$file = str_replace('\\', '/', str_replace('_', '/', $class)).'.php';
$base = (strpos($file, '/') === false) ? __DIR__ : (self::get('flight.lib.path') ?: '.');
if (file_exists($base.'/'.$file)) { foreach ($methods as $name) {
require $base.'/'.$file; self::$dispatcher->set($name, array(__CLASS__, '_'.$name));
}
else {
$loaders = spl_autoload_functions();
$last = array_pop($loaders);
if (is_array($last) && $last[0] == __CLASS__ && $last[1] == __FUNCTION__) {
throw new Exception('Unable to load file: '.$base.'/'.$file);
} }
// Enable output buffering
ob_start();
$initialized = true;
} }
} }
@ -414,7 +243,6 @@ class Flight {
static::error($e); static::error($e);
} }
catch (Exception $ex) { catch (Exception $ex) {
error_log($ex->getMessage());
exit( exit(
'<h1>500 Internal Server Error</h1>'. '<h1>500 Internal Server Error</h1>'.
'<h3>'.$ex->getMessage().'</h3>'. '<h3>'.$ex->getMessage().'</h3>'.
@ -424,26 +252,17 @@ class Flight {
} }
/** /**
* Routes a URL to a callback function. * Starts the framework.
*
* @param string $pattern URL pattern to match
* @param callback $callback Callback function
*/
public static function _route($pattern, $callback) {
self::router()->map($pattern, $callback);
}
/**
* Start the framework.
*/ */
public static function _start() { public static function _start() {
// Route the request // Route the request
$result = self::router()->route(self::request()); $callback = self::router()->route(self::request());
if ($result !== false) { if ($callback !== false) {
list($callback, $params) = $result; self::$dispatcher->execute(
$callback,
self::execute($callback, array_values($params)); array_values(self::request()->params)
);
} }
else { else {
self::notFound(); self::notFound();
@ -467,6 +286,16 @@ class Flight {
->send(); ->send();
} }
/**
* Routes a URL to a callback function.
*
* @param string $pattern URL pattern to match
* @param callback $callback Callback function
*/
public static function _route($pattern, $callback) {
self::router()->map($pattern, $callback);
}
/** /**
* Stops processing and returns a given response. * Stops processing and returns a given response.
* *
@ -487,7 +316,6 @@ class Flight {
* @param object $ex Exception * @param object $ex Exception
*/ */
public static function _error(Exception $e) { public static function _error(Exception $e) {
error_log($e->getMessage());
self::response(false) self::response(false)
->status(500) ->status(500)
->write( ->write(
@ -584,6 +412,6 @@ class Flight {
} }
} }
// Initialize framework on include // Initialize the framework on include
Flight::init(); Flight::init();
?> ?>

@ -0,0 +1,171 @@
<?php
/**
* Flight: An extensible micro-framework.
*
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @license http://www.opensource.org/licenses/mit-license.php
*/
namespace flight\core;
/**
* The Dispatcher class is responsible for dispatching events. Events
* are simply aliases for class methods or functions. The Dispatcher
* allows you to hook other function to an event that can modify the
* input parameters and/or the output.
*/
class Dispatcher {
/**
* Mapped events.
*
* @var array
*/
protected $events = array();
/**
* Method filters.
*
* @var array
*/
protected $filters = array();
public function __construct() {}
/**
* Dispatches an event.
*
* @param string $name Event name
* @param array $params Callback parameters
*/
public function run($name, $params) {
$output = '';
// Run pre-filters
if (!empty($this->filters[$name]['before'])) {
$this->filter($this->filters[$name]['before'], $params, $output);
}
// Run requested method
$output = $this->execute($this->get($name), $params);
// Run post-filters
if (!empty($this->filters[$name]['after'])) {
$this->filter($this->filters[$name]['after'], $params, $output);
}
return $output;
}
/**
* Assigns a callback to an event.
*
* @param string $name Event name
* @param callback $callback Callback function
*/
public function set($name, $callback) {
$this->events[$name] = $callback;
}
/**
* Gets an assigned callback.
*
* @param string $name Event name
* @param callback $callback Callback function
*/
public function get($name) {
return $this->events[$name];
}
/**
* Hooks a callback to an event.
*
* @param string $event Event name
* @param string $type Filter type
* @param callback $callback Callback function
*/
public function hook($name, $type, $callback) {
$this->filters[$name][$type][] = $callback;
}
/**
* Executes a chain of method filters.
*
* @param array $filters Chain of filters
* @param reference $data Method parameters or method output
*/
public function filter($filters, &$params, &$output) {
$args = array(&$params, &$output);
foreach ($filters as $callback) {
$continue = $this->execute($callback, $args);
if ($continue === false) break;
}
}
/**
* Executes a callback function.
*
* @param callback $callback Callback function
* @param array $params Function parameters
* @return mixed Function results
*/
public static function execute($callback, array &$params = array()) {
if (is_callable($callback)) {
return is_array($callback) ?
self::invokeMethod($callback, $params) :
self::callFunction($callback, $params);
}
}
/**
* Calls a function.
*
* @param string $func Name of function to call
* @param array $params Function parameters
*/
public static function callFunction($func, array &$params = array()) {
switch (count($params)) {
case 0:
return $func();
case 1:
return $func($params[0]);
case 2:
return $func($params[0], $params[1]);
case 3:
return $func($params[0], $params[1], $params[2]);
case 4:
return $func($params[0], $params[1], $params[2], $params[3]);
case 5:
return $func($params[0], $params[1], $params[2], $params[3], $params[4]);
default:
return call_user_func_array($func, $params);
}
}
/**
* Invokes a method.
*
* @param mixed $func Class method
* @param array $params Class method parameters
*/
public static function invokeMethod($func, array &$params = array()) {
list($class, $method) = $func;
switch (count($params)) {
case 0:
return $class::$method();
case 1:
return $class::$method($params[0]);
case 2:
return $class::$method($params[0], $params[1]);
case 3:
return $class::$method($params[0], $params[1], $params[2]);
case 4:
return $class::$method($params[0], $params[1], $params[2], $params[3]);
case 5:
return $class::$method($params[0], $params[1], $params[2], $params[3], $params[4]);
default:
return call_user_func_array($func, $params);
}
}
}
?>

@ -0,0 +1,173 @@
<?php
/**
* Flight: An extensible micro-framework.
*
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @license http://www.opensource.org/licenses/mit-license.php
*/
namespace flight\core;
/**
* The Loader class is resonsible for loading objects. It maintains
* a list of reusable class instances and can generate a new class
* instances with custom initialization parameters. It also performs
* class autoloading.
*/
class Loader {
/**
* Registered classes.
*
* @var array
*/
protected $classes = array();
/**
* Class instances.
*
* @var array
*/
protected $instances = array();
/**
* Autoload directories.
*
* @var array
*/
protected $dirs = array();
/**
* Constructor. Enables autoloading.
*/
public function __construct() {
spl_autoload_register(array(__CLASS__, 'autoload'));
}
/**
* Registers a class.
*
* @param string $name Registry name
* @param string $class Class name
* @param array $params Class initialization parameters
* @param callback $callback Function to call after object instantiation
*/
public function register($name, $class, array $params = array(), $callback = null) {
unset($this->instances[$class]);
$this->classes[$name] = array($class, $params, $callback);
}
/**
* Unregisters a class.
*
* @param string $name Registry name
*/
public function unregister($name) {
unset($this->classes[$name]);
}
/**
* Loads a registered class.
*
* @param string $name Method name
* @param bool $shared Shared instance
*/
public function load($name, $shared = true) {
if (isset($this->classes[$name])) {
list($class, $params, $callback) = $this->classes[$name];
$do_callback = ($callback && (!$shared || !isset($this->instances[$class])));
$obj = ($shared) ?
$this->getInstance($class, $params) :
$this->newInstance($class, $params);
if ($do_callback) {
$ref = array(&$obj);
call_user_func_array($callback, $ref);
}
return $obj;
}
$class = ucfirst($name);
return ($shared) ?
$this->getInstance($class) :
$this->newInstance($class);
}
/**
* Gets a single instance of a class.
*
* @param string $class Class name
* @param array $params Class initialization parameters
*/
public function getInstance($class, array $params = array()) {
if (!isset($this->instances[$class])) {
$this->instances[$class] = $this->newInstance($class, $params);
}
return $this->instances[$class];
}
/**
* Gets a new instance of a class.
*
* @param string $class Class name
* @param array $params Class initialization parameters
*/
public function newInstance($class, array $params = array()) {
switch (count($params)) {
case 0:
return new $class();
case 1:
return new $class($params[0]);
case 2:
return new $class($params[0], $params[1]);
case 3:
return new $class($params[0], $params[1], $params[2]);
case 4:
return new $class($params[0], $params[1], $params[2], $params[3]);
case 5:
return new $class($params[0], $params[1], $params[2], $params[3], $params[4]);
default:
$refClass = new ReflectionClass($class);
return $refClass->newInstanceArgs($params);
}
}
/**
* Adds a directory for autoloading classes.
*
* @param string $dir Directory path
*/
public function addDirectory($dir) {
$this->dirs[] = $dir;
}
/**
* Autoloads classes.
*
* @param string $class Class name
*/
public function autoload($class) {
$class_file = str_replace('\\', '/', str_replace('_', '/', $class)).'.php';
$dirs = array_merge($this->dirs, array(__DIR__, '.'));
foreach ($dirs as $dir) {
$file = $dir.'/'.$class_file;
if (file_exists($file)) {
require $file;
return;
}
}
// Allow other autoloaders to run before raising an error
$loader = array_pop(spl_autoload_functions());
if (is_array($loader) && $loader[0] == __CLASS__ && $loader[1] == __FUNCTION__) {
throw new Exception('Unable to load file: '.$class_file);
}
}
}
?>

@ -5,6 +5,33 @@
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com> * @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
namespace flight\net;
/**
* The Request class represents an HTTP request. Data from
* all the super globals $_GET, $_POST, $_COOKIE, and $_FILES
* are stored and accessible via the Request object.
*
* The default request properties are:
* url - The URL being requested
* base - The parent subdirectory of the URL
* method - The request method (GET, POST, PUT, DELETE)
* referrer - The referrer URL
* ip - IP address of the client
* ajax - Whether the request is an AJAX request
* scheme - The server protocol (http, https)
* user_agent - Browser information
* body - Raw data from the request body
* type - The content type
* length - The content length
* query - Query string parameters
* data - Post parameters
* cookies - Cookie parameters
* files - Uploaded files
* params - Matched URL parameters from the router
* matched - Matched URL patter from the router
*/
class Request { class Request {
/** /**
* Constructor. * Constructor.
@ -26,14 +53,16 @@ class Request {
'body' => file_get_contents('php://input'), 'body' => file_get_contents('php://input'),
'type' => $_SERVER['CONTENT_TYPE'], 'type' => $_SERVER['CONTENT_TYPE'],
'length' => $_SERVER['CONTENT_LENGTH'], 'length' => $_SERVER['CONTENT_LENGTH'],
'query' => array(), 'query' => (object)$_GET,
'data' => $_POST, 'data' => (object)$_POST,
'cookies' => $_COOKIE, 'cookies' => (object)$_COOKIE,
'files' => $_FILES 'files' => (object)$_FILES,
'params' => array(),
'matched' => null
); );
} }
self::init($config); $this->init($config);
} }
/** /**
@ -43,7 +72,7 @@ class Request {
*/ */
public function init($properties) { public function init($properties) {
foreach ($properties as $name => $value) { foreach ($properties as $name => $value) {
$this->{$name} = $value; $this->$name = $value;
} }
if ($this->base != '/' && strpos($this->url, $this->base) === 0) { if ($this->base != '/' && strpos($this->url, $this->base) === 0) {
@ -54,14 +83,19 @@ class Request {
$this->url = '/'; $this->url = '/';
} }
else { else {
$this->query = self::parseQuery($this->url); $query = self::parseQuery($this->url);
$this->query = (object)$query;
$_GET = $query;
} }
} }
/** /**
* Parse query parameters from a URL. * Parse query parameters from a URL.
*
* @param string $url URL string
* @return array Query parameters
*/ */
public function parseQuery($url) { public static function parseQuery($url) {
$params = array(); $params = array();
$args = parse_url($url); $args = parse_url($url);

@ -5,6 +5,14 @@
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com> * @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
namespace flight\net;
/**
* The Response class represents an HTTP response. The object
* contains the response headers, HTTP status code, and response
* body.
*/
class Response { class Response {
protected $headers = array(); protected $headers = array();
protected $status = 200; protected $status = 200;
@ -68,7 +76,7 @@ class Response {
} }
} }
else { else {
throw new Exception('Invalid status code.'); throw new \Exception('Invalid status code.');
} }
return $this; return $this;

@ -5,6 +5,14 @@
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com> * @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
namespace flight\net;
/**
* The Router class is responsible for routing an HTTP request to
* an assigned callback function. The Router tries to match the
* requested URL against a series of URL patterns.
*/
class Router { class Router {
/** /**
* Mapped routes. * Mapped routes.
@ -13,6 +21,22 @@ class Router {
*/ */
protected $routes = array(); protected $routes = array();
/**
* Gets mapped routes.
*
* @return array Array of routes
*/
public function getRoutes() {
return $this->routes;
}
/**
* Resets the router.
*/
public function clear() {
$this->routes = array();
}
/** /**
* Maps a URL pattern to a callback function. * Maps a URL pattern to a callback function.
* *
@ -36,10 +60,9 @@ class Router {
* Tries to match a requst to a route. Also parses named parameters in the url. * Tries to match a requst to a route. Also parses named parameters in the url.
* *
* @param string $pattern URL pattern * @param string $pattern URL pattern
* @param string $url Request URL * @param object $request Request object
* @param array $params Named URL parameters
*/ */
public function match($pattern, $url, array &$params = array()) { public function match($pattern, $request) {
$ids = array(); $ids = array();
// Build the regex for matching // Build the regex for matching
@ -60,10 +83,13 @@ class Router {
)).'\/?(?:\?.*)?$/i'; )).'\/?(?:\?.*)?$/i';
// Attempt to match route and named parameters // Attempt to match route and named parameters
if (preg_match($regex, $url, $matches)) { if (preg_match($regex, $request->url, $matches)) {
if (!empty($ids)) { if (!empty($ids)) {
$params = array_intersect_key($matches, $ids); $request->params = array_intersect_key($matches, $ids);
} }
$request->matched = $pattern;
return true; return true;
} }
@ -74,35 +100,21 @@ class Router {
* Routes the current request. * Routes the current request.
* *
* @param object $request Request object * @param object $request Request object
* @return callable Matched callback function
*/ */
public function route(&$request) { public function route(Request $request) {
$params = array(); $request->matched = null;
$request->params = array();
$routes = ($this->routes[$request->method] ?: array()) + ($this->routes['*'] ?: array()); $routes = ($this->routes[$request->method] ?: array()) + ($this->routes['*'] ?: array());
foreach ($routes as $pattern => $callback) { foreach ($routes as $pattern => $callback) {
if ($pattern === '*' || $request->url === $pattern || self::match($pattern, $request->url, $params)) { if ($pattern === '*' || $request->url === $pattern || self::match($pattern, $request)) {
$request->matched = $pattern; return $callback;
return array($callback, $params);
} }
} }
return false; return false;
} }
/**
* Gets mapped routes.
*
* @return array Array of routes
*/
public function getRoutes() {
return $this->routes;
}
/**
* Resets the router.
*/
public function clear() {
$this->routes = array();
}
} }
?> ?>

@ -5,18 +5,36 @@
* @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com> * @copyright Copyright (c) 2011, Mike Cao <mike@mikecao.com>
* @license http://www.opensource.org/licenses/mit-license.php * @license http://www.opensource.org/licenses/mit-license.php
*/ */
namespace flight\template;
/**
* The View class represents output to be displayed. It provides
* methods for managing view data and inserts the data into
* view templates upon rendering.
*/
class View { class View {
/**
* Locaton of view templates.
*
* @var string
*/
public $path; public $path;
public $template;
public $data = array(); /**
* View variables.
*
* @var array
*/
protected $data = array();
/** /**
* Constructor. * Constructor.
* *
* @param string $path Path to templates directory * @param string $path Path to templates directory
*/ */
public function __construct($path = null) { public function __construct($path = '.') {
$this->path = $path ?: (Flight::get('flight.views.path') ?: './views'); $this->path = $path;
} }
/** /**
@ -53,7 +71,7 @@ class View {
* @param string $key Key * @param string $key Key
*/ */
public function has($key) { public function has($key) {
return !empty($this->data[$key]); return !isset($this->data[$key]);
} }
/** /**
@ -77,7 +95,7 @@ class View {
* @param array $data Template data * @param array $data Template data
*/ */
public function render($file, $data = null) { public function render($file, $data = null) {
$this->template = (substr($file, -4) == '.php') ? $file : $file.'.php'; $template = $this->getTemplate($file);
if (is_array($data)) { if (is_array($data)) {
$this->data = array_merge($this->data, $data); $this->data = array_merge($this->data, $data);
@ -85,13 +103,11 @@ class View {
extract($this->data); extract($this->data);
$file = $this->path.'/'.$this->template; if (!file_exists($template)) {
throw new \Exception("Template file not found: $template.");
if (!file_exists($file)) {
throw new Exception("Template file not found: $file.");
} }
include $file; include $template;
} }
/** /**
@ -111,16 +127,6 @@ class View {
return $output; return $output;
} }
/**
* Displays escaped output.
*
* @param string $str String to escape
* @return string Escaped string
*/
public function e($str) {
echo htmlentities($str);
}
/** /**
* Checks if a template file exists. * Checks if a template file exists.
* *
@ -128,27 +134,27 @@ class View {
* @return bool Template file exists * @return bool Template file exists
*/ */
public function exists($file) { public function exists($file) {
return file_exists($this->path.'/'.((substr($file, -4) == '.php') ? $file : $file.'.php')); return file_exists($this->getTemplate($file));
} }
/** /**
* Loads and executes view helper functions. * Gets the full path to a template file.
* *
* @param string $name Function name * @param string $file Template file
* @param array $params Function parameters * @return string Template file location
*/ */
public function __call($name, $params) { public function getTemplate($file) {
return Flight::invokeMethod(array('Flight', $name), $params); return $this->path.'/'.((substr($file, -4) == '.php') ? $file : $file.'.php');
} }
/** /**
* Loads view helper classes. * Displays escaped output.
* *
* @param string $name Class name * @param string $str String to escape
* @return object Class instance * @return string Escaped string
*/ */
public function __get($name) { public function e($str) {
return Flight::load($name); echo htmlentities($str);
} }
} }
?> ?>
Loading…
Cancel
Save