Skip to content

Instantly share code, notes, and snippets.

@jdp
Created July 8, 2010 07:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jdp/467722 to your computer and use it in GitHub Desktop.
Save jdp/467722 to your computer and use it in GitHub Desktop.
BlebCT's PHP framework
<?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