Created
July 8, 2010 07:03
-
-
Save jdp/467722 to your computer and use it in GitHub Desktop.
BlebCT's PHP framework
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* The Bleb PHP Framework | |
* | |
* @author Justin Poliey <jdp34@njit.edu> | |
* @copyright BlebCT 2010 | |
* @package bleb | |
*/ | |
namespace Bleb { | |
/** | |
* Creates a single path string from individual arguments. | |
* Uses the DIRECTORY_SEPARATOR constant to ensure it works cross-platform. | |
*/ | |
function path_join() { | |
return implode(DIRECTORY_SEPARATOR, func_get_args()); | |
} | |
class Exception extends \Exception { | |
function __construct($message, $status_code = 200) { | |
parent::__construct($message); | |
$this->status_code = $status_code; | |
} | |
} | |
/** | |
* Views are the what the user sees when they make a request. | |
* | |
* Views act as templates for actions, and are what the user sees when | |
* he makes a request. They can be used as layouts or partials, depending | |
* on how the <code>render</code> method is called. | |
*/ | |
class View { | |
/** | |
* The filename of the view | |
* @var string | |
* @access private | |
*/ | |
private $filename; | |
/** | |
* Locals are an array of values that will be treated as variables inside of the view. | |
* @var array | |
* @access private | |
*/ | |
private $locals = array(); | |
/** | |
* Flag indicating whether or not <code>render()</code> method has been called. | |
* @var boolean | |
* @access public | |
*/ | |
public $rendered = FALSE; | |
/** | |
* The <code>$content</code> parameter of <code>render()</code> is passed into this | |
* @var string | |
* @access public | |
*/ | |
public $content; | |
function __construct($name, $locals = array()) { | |
$this->filename = path_join('.', 'views', $name.'.php'); | |
$this->locals = array(); | |
} | |
function render($content = NULL, $locals = array(), $return = FALSE) { | |
if (!is_readable($this->filename)) { | |
throw new Exception("Could not load view {$this->filename}"); | |
} | |
$this->locals = array_merge($this->locals, $locals); | |
if ($return) { | |
ob_start(); | |
} | |
$this->content = $content; | |
extract($this->locals); | |
include $this->filename; | |
$this->rendered = TRUE; | |
if ($return) { | |
return ob_get_clean(); | |
} | |
return TRUE; | |
} | |
} | |
class Controller { | |
protected $bleb = NULL; | |
protected $name; | |
protected $isAjax = FALSE; | |
protected $headers = array(); | |
function __construct($bleb, $name, $action) { | |
$this->bleb = $bleb; | |
$this->name = $name; | |
$this->action = $action; | |
$this->isAjax = (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && | |
(strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')); | |
} | |
function __before() { | |
if ($this->isAjax) { | |
$this->headers['Content-Type'] = 'application/json'; | |
$this->view = new View('json'); | |
} | |
else { | |
$this->layout = new View('layout'); | |
$this->view = new View(path_join($this->name, $this->action)); | |
} | |
} | |
function __after() { | |
} | |
function __render($locals = array()) { | |
foreach ($this->headers as $header => $value) { | |
header(sprintf('%s: %s', $header, $value)); | |
} | |
if ($this->isAjax) { | |
$this->view->render(NULL, $locals); | |
} | |
else { | |
$content = $this->view->rendered? NULL: $this->view->render(NULL, $locals, TRUE); | |
$this->layout->render($content, $locals); | |
} | |
} | |
} | |
class Engine { | |
private $config = array(); | |
public $controller; | |
public $action; | |
public $params; | |
function __construct($config) { | |
$this->config = array_merge($this->config, $config); | |
} | |
static function load($name) { | |
$load_path = 'include'; | |
$matches = array(); | |
$file_name = $name; | |
// class is a controller, load from controllers | |
if (preg_match('/^([A-Z][A-Za-z]*)Controller$/', $name, &$matches)) { | |
$load_path = 'controllers'; | |
$file_name = $matches[1]; | |
} | |
$class_file = path_join('.', $load_path, strtolower($file_name).'.php'); | |
if (!is_readable($class_file)) { | |
throw new Exception("Unable to load class file {$class_file} for {$name}"); | |
return FALSE; | |
} | |
require $class_file; | |
if (!class_exists($name)) { | |
throw new Exception("Class {$name} not found in {$class_file}"); | |
return FALSE; | |
} | |
return TRUE; | |
} | |
function route($uri) { | |
$uri_parts = explode('/', $uri); | |
$params = array(); | |
// load up controller class | |
$controller_name = array_shift($uri_parts); | |
$controller_name = (($controller_name === NULL)? 'default': $controller_name); | |
// get the name of the action | |
$action_name = array_shift($uri_parts); | |
$action_name == (($action_name === NULL)? 'index': $action_name); | |
// leftovers from URI pieces are treated as params to the action | |
$params = $uri_parts; | |
return array( | |
'controller' => $controller_name, | |
'action' => $action_name, | |
'params' => $params | |
); | |
} | |
function respond($controller, $action, $params) { | |
$controller_class = ucwords($controller).'Controller'; | |
$this->controller = new $controller_class($this, $controller, $action); | |
$this->action = $action; | |
$this->params = $params; | |
if (is_callable(array($this->controller, $this->action))) { | |
$class_reflector = new \ReflectionObject($this->controller); | |
if (!$class_reflector->isSubclassOf('Bleb\Controller')) { | |
throw new Exception("{$controller_class} must be a subclass of Bleb\Controller"); | |
} | |
$method_reflector = $class_reflector->getMethod($this->action); | |
$required_params = $method_reflector->getNumberOfRequiredParameters(); | |
if (count($this->params) < $required_params) { | |
throw new Exception("Not enough parameters passed to {$controller}#{$action} (needs {$required_params})"); | |
} | |
} | |
else { | |
throw new Exception("No handler for {$controller}#{$action}"); | |
} | |
if (is_callable(array($this->controller, '__before'))) { | |
call_user_func(array($this->controller, '__before')); | |
} | |
$locals = call_user_func_array(array($this->controller, $this->action), $this->params); | |
$this->controller->__render($locals); | |
if (is_callable(array($this->controller, '__after'))) { | |
call_user_func(array($this->controller, '__after')); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment