<?php
/**
* Chippino :: lightweight app framework
* Based on GROK by John Loehrer
* @author Jakob Heuser <jakob@felocity.org>
*/
define('CHIPPINO_LOCATION', dirname(__FILE__) . DIRECTORY_SEPARATOR);
define('CHIPPINO_LIBRARY_LOCATION', CHIPPINO_LOCATION . 'library' . DIRECTORY_SEPARATOR);
/**
* Chippino initiator. used to create the chain
* @return Chippino_Dispatcher
* @param $file a string representing the chippino/grok file to include
**/
function chip($file = NULL) {
$chip = new Chippino_Dispatcher();
$file = strtolower($file);
$chip->setPath($file);
$backtrace = debug_backtrace();
// find a valid file
foreach ($backtrace as $bk => $trace) {
$origin = $trace['file'];
if (strpos($origin, 'chippino.php') !== FALSE || strpos($origin, 'chippino_core.php') !== FALSE || strpos($origin, 'grok.php') !== FALSE) {
continue;
}
$chip->setOrigin($origin);
break;
}
// does file's last segment begin with _
if (strpos(substr($file, strrpos($file, '/') + 1), '_') !== 0) {
return $chip;
}
// check access, must be same dir. Start by removing all absolute path matches
// that could happen when people symlink. This shouldn't cause problems for
// anyone, but anything is possible.
$normalize = array(
CHIPPINO_LIBRARY_LOCATION,
strtolower(CHIPPINO_LIBRARY_LOCATION),
chippino_config()->base_path,
strtolower(chippino_config()->base_path),
);
$caller = dirname(str_replace($normalize, '', $chip->getFilePath()));
$callee = dirname(str_replace($normalize, '', $chip->getOrigin()));
if ($caller != $callee) {
throw new Chippino_Access_Exception($chip->getFilePath(), $chip->getOrigin());
}
return $chip;
}
/**
* variant of chip() returns a singleton instance as a convience method
* @see chip()
**/
function chipi($file = NULL, $namespace = NULL) {
$chip = chip($file);
$chip->asSingleton($namespace);
return $chip;
}
/**
* return a static grok object for the purposes of setting a config
* @return Chippino_Container
**/
function chippino_config() {
static $chip;
if (!isset($chip)) {
$chip = new Grok_Container();
}
return $chip;
}
/**
* Here is the actual Grok Class. Enjoy!
**/
class Chippino_Dispatcher {
private $as_singleton;
private $file_path;
private $origin_path;
public function __construct() {
$this->as_singleton = FALSE;
$this->file_path = NULL;
$this->origin_path = NULL;
}
/**
* says that the dispatch should behave as a singleton (use a single instance)
* @param String $namespace [optional] a unique namespace
* @return Chippino_Dispatcher
**/
public function asSingleton($namespace = NULL) {
$this->as_singleton = $namespace;
return $this;
}
public function getSingleton() {
return ($this->as_singleton) ? $this->as_singleton : FALSE;
}
public function setOrigin($path) {
$this->origin_path = $path;
}
public function getOrigin() {
return $this->origin_path;
}
public function setPath($file = NULL) {
$this->file_path = $file;
return $this;
}
public function getPath() {
return ($this->file_path) ? $this->file_path : NULL;
}
public function getFilePath() {
$file = $this->getPath();
// make sure we are using the correct filepath delimiter here
if ('/' != DIRECTORY_SEPARATOR) {
$file = str_replace('/', DIRECTORY_SEPARATOR, $file);
}
// add php suffix
$file = chippino_config()->base_path . $file . '.php';
return $file;
}
/**
* Dispatches a Chippino_Dispatcher with the supplied input parameters
* @param mixed the input, either an array or Chippino_Container
* @return mixed whatever the included file decides to return
**/
public function with($input = NULL) {
$grok = call_user_func_array(array(chippino_config()->chippino_class, 'retrieve'), array(
$this->getPath(),
$input,
$this->getSingleton()
));
return $grok->dispatch($this->getFilePath());
}
}
class Chippino_Factory {
/**
* gets an occurrence of a Chippino object
* the file creates a unique key to ID the grok. If it doesn't exist,
* then it is created. If $as_singleton is provided, it will look for
* and existing grok object in its data store
* This is called statically
* @param $file the filename to get
* @param $input an array of input to load into the object
* @param $singleton [optional] if the class should be retrieved from storage
* @return Chippino_Dispatcher
**/
public static function retrieve($file, $input, $singleton = FALSE) {
static $chips;
if (!$singleton) {
return new Grok($input);
}
if (!isset($chips)) {
$chips = array();
}
// unique namespace
$key = $singleton."#".$file;
if (!isset($chips[$key])) {
$chips[$key] = grok($file);
}
$chips[$key]->__construct($input);
return $chips[$key];
}
}
class Chippino_Access_Exception extends Exception {
public function __construct($caller, $callee) {
// strip base path from both
$caller = strtolower(str_replace(array(chippino_config()->base_path, '.php'), '', $caller));
$callee = strtolower(str_replace(array(chippino_config()->base_path, '.php'), '', $callee));
parent::__construct('Access error: Attempt to call '.$caller.' from '.$callee);
}
}
// default Chippino Config Values
chippino_config()->base_path = dirname(__FILE__) . DIRECTORY_SEPARATOR;
chippino_config()->chippino_class = 'Chippino_Factory';
// EOF