Last active
December 16, 2015 11:58
-
-
Save vincent4vx/5430739 to your computer and use it in GitHub Desktop.
Single 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 | |
if(!defined('BASE')){define('BASE', dirname(__FILE__).'/../');} | |
/** | |
* @property-read Single_Loader $loader | |
* @property Single_Output $output | |
* @property-read Single_Cache $cache | |
*/ | |
class Single{ | |
private static $instance=null; | |
private $vars=array(); | |
public $config=array(); | |
private function __construct(){ | |
self::$instance=$this; | |
$this->loader=new Single_Loader(); | |
} | |
public function __get($name){return isset($this->vars[$name])?$this->vars[$name]:null;} | |
public function __set($name,$value){$this->vars[$name]=$value;} | |
/** @return Single */ | |
public static function instance(){ | |
if(!self::$instance)new Single(); | |
return self::$instance; | |
} | |
public function loadWebApp(){ | |
$params=explode('/',isset($_SERVER['PATH_INFO'])?substr($_SERVER['PATH_INFO'],1):''); | |
$this->controller=trim(array_shift($params)); | |
if($this->controller==='')$this->controller='home'; | |
$this->method=trim(array_shift($params)); | |
if($this->method==='')$this->method='index'; | |
$this->call_params=(array)$params; | |
$this->loader->controller(ucfirst(trim(strtolower($this->controller))).'Controller',trim(strtolower($this->method)).'Action',$this->call_params); | |
} | |
public function __destruct(){$this->output->flush();} | |
} | |
abstract class Single_Component{ | |
private $_instance; | |
public function __construct(){$this->_instance=Single::instance();} | |
public function __get($name){return $this->_instance->$name;} | |
public function __set($name, $value){return $this->_instance->$name=$value;} | |
} | |
class Single_Loader extends Single_Component{ | |
public function __construct(){ | |
parent::__construct(); | |
$this->output=new Single_Output(); | |
$this->cache=new Single_Cache(); | |
} | |
public function load($class,$file,array $param=array()){ | |
if(!class_exists($class))require $file; | |
if($this->$class!==null)throw new Exception('Class "'.$class.'" already loaded !'); | |
if($param===array())return $this->$class=new $class(); | |
$r=new ReflectionClass($class); | |
return $this->$class=$r->newInstanceArgs($param); | |
} | |
public function alias($var,$alias){ | |
if($this->$var===null){ | |
throw new Exception('The class "'.$var.'" do not exists !'); | |
exit; | |
} | |
if($this->$alias!==null){ | |
throw new Exception('The alias "'.$alias.'" is already used !'); | |
exit; | |
} | |
$this->$alias=$this->$var; | |
} | |
public function controller($name,$method=null,array $param=array()){ | |
$file=BASE.(empty($this->config['controllers_path'])?'controllers':$this->config['controllers_path']).DIRECTORY_SEPARATOR.$name.'.php'; | |
if(!file_exists($file))$this->output->error(404,'Cannot find the controller !', true); | |
require $file; | |
if(class_exists($name)){ | |
$controller=new $name; | |
if(!method_exists($controller, $method)) $this->output->error(404,'Cannot find the method "'.$method.'" !',true); | |
echo call_user_func_array(array($controller,$method),$param); | |
}elseif($method!==null){ | |
if(!is_callable($method)) $this->output->error(404,'Cannot find the function "'.$method.'" !',true); | |
echo call_user_func_array($method, $param); | |
} | |
} | |
public function model($name){ | |
$file=BASE.(empty($this->config['models_path'])?'models':$this->config['models_path']).DIRECTORY_SEPARATOR.$name.'.php'; | |
if(!file_exists($file))throw new Exception('The model "'.$name.'" do not exists !'); | |
require $file; | |
if(!class_exists($name))return; | |
return $this->$name=new $name; | |
} | |
} | |
class Single_Output{ | |
private $contents='',$cache=false,$vars=array(); | |
public $layout=null; | |
public function __construct(){ob_start();} | |
public function __get($name){return isset($this->vars[$name])?$this->vars[$name]:null;} | |
public function __set($name,$value){ | |
$this->vars[$name]=$value; | |
if($this->cache!==false)$this->cache['vars'][$name]=$value; | |
} | |
public function startCache($key){ | |
if(($data=Single::instance()->cache->get($key))!==false){ | |
$this->vars+=$data['vars']; | |
echo $data['contents']; | |
return false; | |
} | |
$this->contents.=ob_get_clean(); | |
$this->cache=array('key'=>$key,'vars'=>array()); | |
ob_start(); | |
return true; | |
} | |
public function endCache($time=60){ | |
$this->cache['contents']=ob_get_clean(); | |
$this->contents.=$this->cache['contents']; | |
Single::instance()->cache->set($this->cache['key'], $this->cache, $time); | |
$this->cache=false; | |
ob_start(); | |
} | |
public function flush(){ | |
$this->contents.=ob_get_clean(); | |
if(!empty($this->layout)&&$this->contents!==''){ | |
require BASE.(empty(Single::instance()->config['views_path'])?'views':Single::instance()->config['views_path']).DIRECTORY_SEPARATOR.$this->layout; | |
}else echo $this->contents; | |
$this->contents=''; | |
} | |
public function view($file, array $vars=array()){ | |
extract($vars); | |
include BASE.(empty(Single::instance()->config['views_path'])?'views':Single::instance()->config['views_path']).DIRECTORY_SEPARATOR.$file; | |
} | |
public function error($errno=404,$msg='An error was encountered',$fatal=false){ | |
if(!empty(Single::instance()->config['error_'.$errno])) include BASE.(empty(Single::instance()->config['views_path'])?'views':Single::instance()->config['views_path']).DIRECTORY_SEPARATOR.Single::instance()->config['error_'.$errno]; | |
else echo '<h1>Error '.$errno.'</h1><br/>'.$msg; | |
if($fatal)exit; | |
} | |
} | |
class Single_Cache{ | |
public function get($key, $deleteAfter=false){ | |
$file=$this->getFile($key); | |
if(!file_exists($file))return false; | |
$data=unserialize(file_get_contents($file)); | |
if($data['deletion_time']<time()){ | |
unlink($file); | |
return false; | |
} | |
if($deleteAfter)unlink($file); | |
return $data['content']; | |
} | |
public function set($key,$value,$time=60){ | |
$file=$this->getFile($key); | |
if(!is_dir(dirname($file)))mkdir(dirname($file),0777,true); | |
$data=array('content'=>$value,'deletion_time'=>time()+$time); | |
return file_put_contents($file, serialize($data)); | |
} | |
public function delete($key){return unlink($this->getFile($key));} | |
private function getFile($key){return BASE.'cache'.DIRECTORY_SEPARATOR.str_replace('.', DIRECTORY_SEPARATOR, $key).'.cache';} | |
} | |
/** | |
* @property-read Single_Output $output | |
* @property-read Single_Cache $cache | |
* @property-read Single_Loader $loader | |
*/ | |
abstract class Single_Controller extends Single_Component{} | |
class Single_Database extends PDO{ | |
public function __construct(){ | |
$config=empty(Single::instance()->config['database'])?array():Single::instance()->config['database']; | |
$opt=(empty($config['options'])?array():(array)$config['options']) + array(PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_STATEMENT_CLASS=>array('Single_Statement')); | |
try{parent::__construct(empty($config['dsn'])?'mysql:host=127.0.0.1;dbname=single':$config['dsn'], empty($config['user'])?'root':$config['user'], empty($config['pass'])?'':$config['pass'],$opt);} | |
catch(Exception $e){echo '<pre>'.$e.'</pre>';exit;} | |
} | |
/** @return Single_Database */ | |
public static function instance(){ | |
if(Single::instance()->database===null)Single::instance()->database=new self; | |
return Single::instance()->database; | |
} | |
} | |
class Single_Statement extends PDOStatement{ | |
public function fetch($fetch_style=null,$cursor_orientation=PDO::FETCH_ORI_NEXT,$cursor_offset=0){ | |
if($fetch_style===null)$this->setFetchMode(PDO::FETCH_CLASS, 'Single_ActiveRecord',array(false)); | |
return parent::fetch($fetch_style, $cursor_orientation, $cursor_offset); | |
} | |
public function fetchAll($fetch_style=PDO::FETCH_CLASS,$fetch_argument='Single_ActiveRecord',$ctor_args=array(false)){return parent::fetchAll($fetch_style, $fetch_argument, $ctor_args);} | |
} | |
class Single_ActiveRecord implements Iterator{ | |
private $vars=array(),$old_vars=array(),$is_new; | |
public function __construct($is_new=true){$this->is_new=$is_new;} | |
public function __get($name){return isset($this->vars[$name])?$this->vars[$name]:null;} | |
public function __set($name,$value){ | |
if(!isset($this->vars[$name]))$this->old_vars[$name]=$value; | |
$this->vars[$name]=$value; | |
} | |
public function __sleep(){return array_keys($this->vars);} | |
public function current(){return current($this->vars);} | |
public function next(){return next($this->vars);} | |
public function rewind(){return reset($this->vars);} | |
public function key(){return key($this->vars);} | |
public function valid(){return isset($this->vars[$this->key()]);} | |
public function save($table){ | |
if($this->is_new)return Single_Database::instance()->prepare('INSERT INTO '.addslashes($table).'('.implode(', ', array_keys($this->vars)).') VALUES(:'.implode(',:',array_keys($this->vars)).')')->execute($this->vars); | |
$tmp1=$tmp2=$tmp3=array(); | |
foreach($this->vars as $col=>$value){$tmp1[]=$col.'= :'.$col;} | |
foreach($this->old_vars as $col=>$value){ | |
$tmp2[]=$col.'=:old_'.$col; | |
$tmp3['old_'.$col]=$value; | |
} | |
$this->old_vars=$this->vars; | |
return Single_Database::instance()->prepare('UPDATE '.addslashes($table).' SET '.implode(', ', $tmp1).' WHERE '.implode(' AND ',$tmp2))->execute($this->vars+$tmp3); | |
} | |
public function delete($table){ | |
$tmp=array(); | |
foreach($this->vars as $col=>$value)$tmp[]=$col.'= :'.$col; | |
return Single_Database::instance()->prepare('DELETE FROM '.addslashes($table).' WHERE '.implode(' AND ', $tmp))->execute($this->vars); | |
} | |
} | |
/** @property-read Single_Database $database */ | |
abstract class Single_Model extends Single_Component{ | |
public function __construct() { | |
parent::__construct(); | |
$this->database=Single_Database::instance(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment