Skip to content

Instantly share code, notes, and snippets.

@vincent4vx
Last active December 16, 2015 11:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vincent4vx/5430739 to your computer and use it in GitHub Desktop.
Save vincent4vx/5430739 to your computer and use it in GitHub Desktop.
Single Framework
<?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