* @copyright creative commons attribution-shareAlike 3.0 unported * @license http://creativecommons.org/licenses/by-sa/3.0/ * @version 2.0057 */ class qoob { /** * split * seperate a comma, semi-colon, or pipe delimited string * @param string $str * @param array $strs */ function split($str) { return array_map('trim', preg_split('/[,;|]/',$str,0,PREG_SPLIT_NO_EMPTY)); } /** * route * add a route pattern * @param string $pattern route * @param mixed $handler closure function or class->method reference */ function route($pattern, $handler) { if(empty($handler)) { die('missing callback'); } $parts = explode(' ', trim($pattern)); foreach ($this->split($parts[0]) as $verb) { if (!preg_match('/GET|HEAD|POST|PUT|PATCH|DELETE|CONNECT/', strtoupper($verb))) { die(sprintf('not implemented: %s', $verb)); } if(!isset($parts[1])) { die(sprintf('invalid routing pattern: %s', $pattern)); } $type = isset($parts[2])?str_replace(array('[',']'), '', strtoupper($parts[2])):'SYNC'; if (!preg_match('/SYNC|AJAX/', $type)) { die(sprintf('invalid request type: %s', $type)); } library::set( 'routes', array( 'verb' => strtoupper($verb), 'type' => $type, 'handler' => $handler, 'pattern' => rtrim($parts[1], '/') ) ); } } /** * parse routes * mine the current request against the routes in the library */ function parseRoutes() { $this->benchmark->mark('parseStart'); $verb = $_SERVER['REQUEST_METHOD']; library::set('url', 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']); library::set('domain', 'http://'.dirname($_SERVER["HTTP_HOST"].$_SERVER["SCRIPT_NAME"])); library::set('uri', rtrim(str_replace(library::get('domain'), '', library::get('url')), '/')); library::set('ajax', (!empty($_SERVER['HTTP_X_REQUESTED_WITH'])&&strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])=='xmlhttprequest')?'AJAX':'SYNC'); $found = false; foreach(library::get('routes') as $route) { // convert uris like '/users/:uid/posts/:pid' to regular expression $pattern = "@^".preg_replace('/\\\:[a-zA-Z0-9\_\-]+/', '([a-zA-Z0-9\-\_]+)', preg_quote($route['pattern']))."$@D"; $args = array(); // check if the current request matches the expression if($verb == $route['verb'] && preg_match($pattern, library::get('uri'), $matches)) { if($route['type'] == library::get('ajax')) { // remove the first match array_shift($matches); $found = true; // correlate route regex with uri parameters preg_match_all('/\\\:[a-zA-Z0-9\_\-]+/', preg_quote($route['pattern']), $names); for($i=0;$ibenchmark->mark('parseEnd'); if(!$found) { die('404 file not found'); } else { $this->call($route, $args); } } /** * call * execute a route handler * @param array $route route information * @param array $args url arguments */ function call($route, $args) { $this->benchmark->mark('callStart'); //closure style if(is_callable($route['handler'])) { call_user_func_array($route['handler'], array($args)); } //class creation if(is_string($route['handler']) && preg_match('/(.+)\h*(->|::)\h*(.+)/s', $route['handler'], $parts)) { if (!class_exists($parts[1]) || !method_exists($parts[1], $parts[3])) { die('404 file not found'); } call_user_func_array(array(new $parts[1], $parts[3]), array($args)); } $this->benchmark->mark('callEnd'); } /** * load * load namespace aware classes into the framework * @param string $class class name */ function load($class) { if(class_exists($class)) { // remove namespace from class name $name = explode('\\', $class); $name = $name[count($name)-1]; if(!library::get($name)) { // create class and set a reference to it library::set($name, new $class); $this->$name = library::get($name); } } } /** * open qoob * get the singleton reference to the open qoob framework * @return class qoob */ static function open() { if (!library::exists($class=__CLASS__)) { library::set($class, new $class); } return library::get($class); } /** * clone * disabled * @deprecated */ private function __clone() {} /** * constructor * bootstraps the framework. initializes autoloading classes. */ private function __construct() { set_include_path( implode( PATH_SEPARATOR, array( get_include_path(), basename(__DIR__).DIRECTORY_SEPARATOR.'utils', basename(__DIR__).DIRECTORY_SEPARATOR.'core', basename(__DIR__).DIRECTORY_SEPARATOR.'api' ) ) ); spl_autoload_register(); $this->load('qoob\utils\benchmark'); $this->benchmark->mark('appStart'); } /** * destructor * displays the benchmarks */ public function __destruct() { foreach ($this->benchmark->markers as $key => $value) { if(strpos($key, 'Start')>0) { $mark = substr($key, 0, strpos($key, 'Start')); $markers[$mark] = ($x=$this->benchmark->diff($mark.'Start', $mark.'End'))==false?('did not run'):($x.' seconds'); } } echo str_replace('Array', 'benchmarks', '
'.print_r($markers, true).'
'); } } //_________________________________________________________________________ // object library /** * library * singleton object library * * @author xero harrison * @copyright creative commons attribution-shareAlike 3.0 unported * @license http://creativecommons.org/licenses/by-sa/3.0/ * @version 2.22 */ final class library { private static $catalog; static function exists($key) { return isset(self::$catalog[$key]); } static function get($key) { return self::$catalog[$key]; } static function set($key, $value) { is_array($value) ? self::$catalog[$key][]=$value : self::$catalog[$key]=$value; } static function clear($key) { unset(self::$catalog[$key]); } function __construct() {} function __clone() {} } //_________________________________________________________________________ // open the qoob /** * @return class qoob instance */ return qoob::open(); ?>