Core classes finally moved
git-svn-id: svn+ssh://code.netmonsters.ru/svn/majestic/trunk@14 4cb57b5f-5bbd-dd11-951b-001d605cbbc5
This commit is contained in:
108
classes/Action.class.php
Normal file
108
classes/Action.class.php
Normal file
@ -0,0 +1,108 @@
|
||||
<?php
|
||||
/**
|
||||
* Рутовый класс для любого действия.
|
||||
* Описывает основной функционал для работы с классами действий.
|
||||
*
|
||||
* @copyright
|
||||
* @link
|
||||
* @package Majestic
|
||||
* @subpackage Action
|
||||
* @since
|
||||
* @version SVN: $Id$
|
||||
* @filesource $URL$
|
||||
*/
|
||||
abstract class Action
|
||||
{
|
||||
public $template; //шаблон действия
|
||||
public $template_dir = '.'; //путь к шаблону действия
|
||||
public $class; //имя дочернего класса
|
||||
|
||||
protected $templater; //шаблонизатор
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->class = get_class($this);
|
||||
$this->template = substr($this->class, 0, -strlen(ACTION_POSTFIX));
|
||||
|
||||
if (CACHE_ENABLE && ($cache_name = $this->getCacheKey()) !== false) {
|
||||
$cache = new Cache($this->class.'_'.$cache_name, $this->getCacheTime());
|
||||
if ($cache->isCached()) {
|
||||
$this->restore($cache->load());
|
||||
} else {
|
||||
$this->init();
|
||||
$cache->save($this->store());
|
||||
}
|
||||
} else {
|
||||
$this->init();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Выдает результат действия.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function display()
|
||||
{
|
||||
$this->templater = Load::templater(ACTION_TPL_PATH.'/'.$this->template_dir);
|
||||
$this->prepare();
|
||||
return $this->templater->fetch($this->template.'.tpl');
|
||||
}
|
||||
|
||||
/**
|
||||
* Инициализация данных действия.
|
||||
* Тут должна быть ВСЯ работа с установкой данных,
|
||||
* дабы потом они нормально закешировались.
|
||||
* Этот метод НЕ исполняется при срабатывании кеша.
|
||||
*
|
||||
*/
|
||||
abstract protected function init();
|
||||
|
||||
/**
|
||||
* Подготовка данных для шаблона.
|
||||
* Этот метод выполняется ВСЕГДА
|
||||
*/
|
||||
protected function prepare() {}
|
||||
|
||||
/**
|
||||
* Возвращает имя файла для кеширования
|
||||
* Переопределяется в доченрих классах.
|
||||
*
|
||||
* @return false/string - имя файла кеша либо false если кеш запрещен
|
||||
*/
|
||||
protected function getCacheKey()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает время жизни кеша в секундах
|
||||
* При отрицательном значении кеш вечен.
|
||||
* Переопределяется в доченрих классах.
|
||||
*
|
||||
* @return false/integer - время жизни кеша либо false если кеш запрещен
|
||||
*/
|
||||
protected function getCacheTime()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Выдает строку для кеширования.
|
||||
*/
|
||||
protected function store()
|
||||
{
|
||||
return serialize(get_object_vars($this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Разбирает строку кеша, созданную методом store
|
||||
*/
|
||||
protected function restore($data)
|
||||
{
|
||||
foreach(unserialize($data) as $key => $val) {
|
||||
$this->$key = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
65
classes/Cache.class.php
Normal file
65
classes/Cache.class.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* Класс кеша.
|
||||
* Отвечает за кеширование результатов выполнения действий.
|
||||
*
|
||||
* @copyright
|
||||
* @link
|
||||
* @package Majestic
|
||||
* @subpackage Cache
|
||||
* @since
|
||||
* @version SVN: $Id$
|
||||
* @filesource $URL$
|
||||
*/
|
||||
final class Cache
|
||||
{
|
||||
private $cache_file;
|
||||
private $cache_time;
|
||||
|
||||
function __construct($cache_name, $cache_time)
|
||||
{
|
||||
$this->cache_time = (int) $cache_time;
|
||||
$this->cache_file = CACHE_PATH.'/'.$cache_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Сохраняет кэш в файл
|
||||
*
|
||||
* @return boolean - сохранил или нет
|
||||
*/
|
||||
function save($data)
|
||||
{
|
||||
if ($this->cache_time != 0) {
|
||||
return (bool) file_put_contents($this->cache_file, $data);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Достает кэш из файла
|
||||
*
|
||||
* @return string - содержимое кеша
|
||||
*/
|
||||
function load()
|
||||
{
|
||||
return file_get_contents($this->cache_file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, закешированы ли данные с таким именем
|
||||
*
|
||||
* @return boolean - закеширован или нет
|
||||
*/
|
||||
function isCached()
|
||||
{
|
||||
if (! file_exists($this->cache_file)) {
|
||||
return false;
|
||||
}
|
||||
if ($this->cache_time > 0 && $this->cache_time + filemtime($this->cache_file) < TIME_NOW) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
47
classes/DBConnector.class.php
Normal file
47
classes/DBConnector.class.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* Класс базы данных.
|
||||
* Возвращает идентификатор соединения
|
||||
*
|
||||
* @copyright
|
||||
* @link
|
||||
* @package Majestic
|
||||
* @subpackage DB
|
||||
* @since
|
||||
* @version SVN: $Id$
|
||||
* @filesource $URL$
|
||||
*/
|
||||
class DBConnector
|
||||
{
|
||||
static private $handlers = array();
|
||||
static public $queries = array();
|
||||
|
||||
/**
|
||||
* Получение соединения.
|
||||
* Если соединение с такими параметрами уже есть - новое не создается.
|
||||
*
|
||||
* @param array $db_settings - массив настроек
|
||||
* @return resource - идентификатор соединения
|
||||
*/
|
||||
static function getConnect($db_settings)
|
||||
{
|
||||
$handler_name = self::getConnectionName($db_settings);
|
||||
|
||||
if (isset(self::$handlers[$handler_name])) {
|
||||
return self::$handlers[$handler_name];
|
||||
}
|
||||
|
||||
if (!$handler = mysqli_connect($db_settings['host'], $db_settings['user'], $db_settings['password'], $db_settings['database'])) {
|
||||
throw new MJException('Can\'t connect to DB '.mysqli_connect_error(), 2);
|
||||
}
|
||||
|
||||
mysqli_query($handler, "SET NAMES 'utf8'"); //cheat!!!
|
||||
return self::$handlers[$handler_name] = $handler;
|
||||
}
|
||||
|
||||
static function getConnectionName($db_settings)
|
||||
{
|
||||
return $db_settings['host'].'-'.$db_settings['database'];
|
||||
}
|
||||
}
|
||||
?>
|
62
classes/Decorator.class.php
Normal file
62
classes/Decorator.class.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* Родительский класс для всех декораторов. Содержит основной функционал.
|
||||
*
|
||||
* @copyright
|
||||
* @link
|
||||
* @package Majestic
|
||||
* @subpackage Decorator
|
||||
* @since
|
||||
* @version SVN: $Id$
|
||||
* @filesource $URL$
|
||||
*/
|
||||
abstract class Decorator
|
||||
{
|
||||
protected $layout = false;
|
||||
protected $action = false;
|
||||
protected $action_name = 'Action';
|
||||
|
||||
protected $templater = false;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
if (!$this->layout) {
|
||||
throw new MJException('$layout not set in '.get_class($this));
|
||||
}
|
||||
$this->templater = Load::templater();
|
||||
}
|
||||
|
||||
/**
|
||||
* Основной метод вывода
|
||||
*
|
||||
*/
|
||||
function display(Action $action)
|
||||
{
|
||||
$this->action = $action;
|
||||
$this->templater->assign($this->action_name, $this->action->display(), $this->layout);
|
||||
|
||||
$this->exec();
|
||||
|
||||
$this->templater->setPath(WRAPPERS_TPL_PATH);
|
||||
return $this->templater->fetch($this->layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавить данные на вывод
|
||||
*
|
||||
* @param string $var_name - имя переменной, в которую будет осуществлен вывод
|
||||
* @param Action $action - действие
|
||||
* @param Decorator $decorator - декоратор, в котором должно выполнится действие.
|
||||
*/
|
||||
function addOutput($var_name, Action $action, Decorator $decorator = null)
|
||||
{
|
||||
$this->templater->assign($var_name, $decorator ? $decorator->display($action) : $action->display(), $this->layout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Основной метод для дочерних декораторов
|
||||
*
|
||||
*/
|
||||
abstract function exec();
|
||||
}
|
||||
?>
|
70
classes/Env.class.php
Normal file
70
classes/Env.class.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/**
|
||||
* Класс для работы с переменными окружения.
|
||||
*
|
||||
* @copyright
|
||||
* @link
|
||||
* @package Majestic
|
||||
* @subpackage Core
|
||||
* @since
|
||||
* @version SVN: $Id$
|
||||
* @filesource $URL$
|
||||
*/
|
||||
final class Env
|
||||
{
|
||||
static public $params = array();
|
||||
|
||||
static function Get($var, $default = false)
|
||||
{
|
||||
return isset($_GET[$var]) ? $_GET[$var] : $default;
|
||||
}
|
||||
|
||||
static function Post($var, $default = false)
|
||||
{
|
||||
return isset($_POST[$var]) ? $_POST[$var] : $default;
|
||||
}
|
||||
|
||||
static function Server($var, $default = false)
|
||||
{
|
||||
return isset($_SERVER[$var]) ? $_SERVER[$var] : $default;
|
||||
}
|
||||
|
||||
static function Session($var, $default = false)
|
||||
{
|
||||
return isset($_SESSION[$var]) ? $_SESSION[$var] : $default;
|
||||
}
|
||||
|
||||
static function getCookie($var, $default = false)
|
||||
{
|
||||
return isset($_COOKIE[$var]) ? $_COOKIE[$var] : $default;
|
||||
}
|
||||
|
||||
static function setCookie($var, $value, $time = 0, $path = '/')
|
||||
{
|
||||
return setcookie($var, $value, $time, $path);
|
||||
}
|
||||
|
||||
static function getParam($var, $default = false)
|
||||
{
|
||||
return isset(self::$params[$var]) ? self::$params[$var] : $default;
|
||||
}
|
||||
|
||||
static function setParam($var, $val)
|
||||
{
|
||||
self::$params[$var] = $val;
|
||||
}
|
||||
|
||||
static function setParams($params=array())
|
||||
{
|
||||
self::$params = self::$params + $params;
|
||||
}
|
||||
|
||||
static function parseTimer($time)
|
||||
{
|
||||
$hours = intval($time / 3600);
|
||||
$minutes = intval($time/60 - $hours*60);
|
||||
|
||||
return sprintf('%02d:%02d:%02d', $hours, $minutes, $time - $hours*3600 - $minutes*60);
|
||||
}
|
||||
}
|
||||
?>
|
45
classes/Load.class.php
Normal file
45
classes/Load.class.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @copyright
|
||||
* @link
|
||||
* @package Majestic
|
||||
* @subpackage Load
|
||||
* @since
|
||||
* @version SVN: $Id$
|
||||
* @filesource $URL$
|
||||
*/
|
||||
class Load
|
||||
{
|
||||
static $models = array();
|
||||
static $templater = false;
|
||||
static $router = false;
|
||||
|
||||
static function model($model_name)
|
||||
{
|
||||
if (isset(self::$models[$model_name])) {
|
||||
return self::$models[$model_name];
|
||||
}
|
||||
|
||||
$class_name = $model_name.MODEL_POSTFIX;
|
||||
return self::$models[$model_name] = new $class_name;
|
||||
}
|
||||
|
||||
static function templater($path = '')
|
||||
{
|
||||
if (self::$templater) {
|
||||
if ($path) {
|
||||
self::$templater->setPath($path);
|
||||
}
|
||||
return self::$templater;
|
||||
}
|
||||
return self::$templater = new Sublimer($path);
|
||||
}
|
||||
|
||||
static function router()
|
||||
{
|
||||
return self::$router ? self::$router : self::$router = new Router;
|
||||
}
|
||||
}
|
||||
?>
|
65
classes/MJException.class.php
Normal file
65
classes/MJException.class.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* Обработчик эксепшенов
|
||||
*
|
||||
* @copyright
|
||||
* @link
|
||||
* @package Majestic
|
||||
* @subpackage Core
|
||||
* @since
|
||||
* @version SVN: $Id$
|
||||
* @filesource $URL$
|
||||
*/
|
||||
class MJException extends Exception
|
||||
{
|
||||
private $line_range = 6;
|
||||
|
||||
public function terminate()
|
||||
{
|
||||
if (!DEBUG_ENABLE) {
|
||||
return "Sorry, server temporary unavaible";
|
||||
}
|
||||
|
||||
$return = "<b>MJ Error:</b> ";
|
||||
$return .= str_replace("\n", "<br/>\n", $this->getMessage())."<br>\n";
|
||||
|
||||
$trace = $this->getTrace();
|
||||
|
||||
$file = reset($trace);
|
||||
|
||||
//смещение в трейсе, указаное при вызове эксепшена (2й параметр). Нужно для более инофрмативного вывода
|
||||
if ($shift = abs($this->getCode())) {
|
||||
while($shift--) {
|
||||
$file = next($trace);
|
||||
}
|
||||
}
|
||||
|
||||
if ($fp = fopen($file['file'], 'r')) {
|
||||
$error_line = $file['line'];
|
||||
$start = $error_line - $this->line_range;
|
||||
$end = $error_line + $this->line_range;
|
||||
$i = 1;
|
||||
$return .= "<pre style=\"background-color:#e4e4e4\">";
|
||||
while ($line = fgets($fp, 4096) and $i<=$end) {
|
||||
$line = htmlspecialchars($line);
|
||||
if ($i >= $start && $i <= $end) {
|
||||
if ($i == $error_line) $return .= '<div style="background-color:#cccccc">'.$i.' '.$line.'</div>';
|
||||
else $return .= $i.' '.$line;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
$return .= "</pre>";
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
$return .= '<table border="1" cellpadding="2" cellspacing="0"> <caption><b>Backtrace</b></caption>';
|
||||
$return .= "\n<tr><td><b>".$this->getFile().'</b></td><td><b>'.$this->getLine().'</b></td></tr>';
|
||||
foreach($trace as $row) {
|
||||
if (isset($row['file'])) { //throwing exception from __call method will not return file and line
|
||||
$return .= "\n<tr".($file['file'] == $row['file'] ? ' style="background-color:#ffcccc"': '')."><td>".$row['file'].'</td><td>'.$row['line'].'</td></tr>';
|
||||
}
|
||||
}
|
||||
return $return . '</table>';
|
||||
}
|
||||
}
|
||||
?>
|
199
classes/Model.class.php
Normal file
199
classes/Model.class.php
Normal file
@ -0,0 +1,199 @@
|
||||
<?php
|
||||
/**
|
||||
* Класс модели данных
|
||||
*
|
||||
* @copyright
|
||||
* @link
|
||||
* @package Majestic
|
||||
* @subpackage DB
|
||||
* @since
|
||||
* @version SVN: $Id$
|
||||
* @filesource $URL$
|
||||
*/
|
||||
abstract class Model
|
||||
{
|
||||
private $handler;
|
||||
|
||||
protected $table = false;
|
||||
protected $primary_key = 'id';
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->handler = DBConnector::getConnect(Env::getParam('db_settings'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Выполняет запрос и возвращает сырой результат
|
||||
*
|
||||
* @param string $sql
|
||||
* @return resource
|
||||
*/
|
||||
function exec($sql)
|
||||
{
|
||||
$time = microtime(true);
|
||||
$res = mysqli_query($this->handler, $sql);
|
||||
if (mysqli_errno($this->handler)) {
|
||||
throw new MJException("<b>Query Error:</b>\n".$sql."\n<b>Error:</b>\n".mysqli_error($this->handler), 1);
|
||||
}
|
||||
|
||||
if (DEBUG_ENABLE) {
|
||||
DBConnector::$queries[] = $sql.'; ('.round((microtime(true)-$time)*1000, 1).'ms)';
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Выполняет запрос и возвращает объект результата
|
||||
*
|
||||
* @param string $sql
|
||||
* @return object
|
||||
*/
|
||||
function query($sql)
|
||||
{
|
||||
$res = $this->exec($sql);
|
||||
|
||||
switch (strtolower(substr($sql, 0, 6))) {
|
||||
case 'select':
|
||||
return new ModelSelectResult($res);
|
||||
case 'insert':
|
||||
return new ModelInsertResult($this->handler);
|
||||
default:
|
||||
return new ModelChangeResult($this->handler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Экранирует строку
|
||||
*
|
||||
* @param string $data - строка для экранирования
|
||||
* @return string
|
||||
*/
|
||||
function escape($data)
|
||||
{
|
||||
return mysqli_real_escape_string($this->handler, $data);
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
function update($id, $data)
|
||||
{
|
||||
$sql = '';
|
||||
foreach ($data as $key => $val) {
|
||||
$sql .= $key."='".$this->escape($val)."', ";
|
||||
}
|
||||
return $this->query('UPDATE '.$this->table.' SET '.rtrim($sql, ', ').' WHERE '.$this->primary_key.'='.(int) $id);
|
||||
}
|
||||
|
||||
function insert($data, $postfix = '')
|
||||
{
|
||||
$sql = '';
|
||||
foreach ($data as $key => $val) {
|
||||
$sql .= $key.'="'.$this->escape($val).'", ';
|
||||
}
|
||||
return $this->query('INSERT '.$this->table.' SET '.rtrim($sql, ', ').' '.$postfix);
|
||||
}
|
||||
|
||||
function delete($id)
|
||||
{
|
||||
return $this->query('DELETE FROM '.$this->table.' WHERE '.$this->primary_key.'='.(int) $id);
|
||||
}
|
||||
|
||||
function get($id)
|
||||
{
|
||||
return $this->query('SELECT * FROM '.$this->table.' WHERE '.$this->primary_key.'='.(int) $id);
|
||||
}
|
||||
|
||||
function getList($limit = false, $sort = 'ASC')
|
||||
{
|
||||
return $this->query('SELECT * FROM '.$this->table.' ORDER BY '.$this->primary_key.' '.($sort == 'ASC' ? 'ASC' : 'DESC').($limit === false ? ' LIMIT '.(int) $limit : ''));
|
||||
}
|
||||
}
|
||||
|
||||
class ModelResult
|
||||
{
|
||||
function __call($name, $args)
|
||||
{
|
||||
throw new MJException('Call undeclared method "'.$name.'" in "'.get_class($this).'" class', -1);
|
||||
}
|
||||
}
|
||||
|
||||
class ModelSelectResult extends ModelResult
|
||||
{
|
||||
public $result;
|
||||
|
||||
function __construct($res)
|
||||
{
|
||||
$this->result = $res;
|
||||
}
|
||||
|
||||
function fetch()
|
||||
{
|
||||
return mysqli_fetch_object($this->result);
|
||||
}
|
||||
|
||||
function fetchField($field, $default = false)
|
||||
{
|
||||
$row = $this->fetch();
|
||||
return isset($row->$field) ? $row->$field : $default;
|
||||
}
|
||||
|
||||
function fetchAll($key = false)
|
||||
{
|
||||
$array = array();
|
||||
if ($key) {
|
||||
while ($row = mysqli_fetch_object($this->result)) {
|
||||
$array[$row->$key] = $row;
|
||||
}
|
||||
} else {
|
||||
while ($row = mysqli_fetch_object($this->result)) {
|
||||
$array[] = $row;
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
function count()
|
||||
{
|
||||
return mysqli_num_rows($this->result);
|
||||
}
|
||||
|
||||
function free()
|
||||
{
|
||||
mysqli_free_result($this->result);
|
||||
}
|
||||
|
||||
function __destruct() {
|
||||
$this->free();
|
||||
}
|
||||
}
|
||||
|
||||
class ModelChangeResult extends ModelResult
|
||||
{
|
||||
public $affected;
|
||||
|
||||
function __construct($resource)
|
||||
{
|
||||
$this->affected = mysqli_affected_rows($resource);
|
||||
}
|
||||
|
||||
function count()
|
||||
{
|
||||
return $this->affected;
|
||||
}
|
||||
}
|
||||
|
||||
class ModelInsertResult extends ModelResult
|
||||
{
|
||||
public $id;
|
||||
|
||||
function __construct($resource)
|
||||
{
|
||||
$this->id = mysqli_insert_id($resource);
|
||||
}
|
||||
|
||||
function getId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
}
|
||||
?>
|
37
classes/PageController.class.php
Normal file
37
classes/PageController.class.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @copyright
|
||||
* @link
|
||||
* @package Majestic
|
||||
* @subpackage PageController
|
||||
* @since
|
||||
* @version SVN: $Id$
|
||||
* @filesource $URL$
|
||||
*/
|
||||
final class PageController
|
||||
{
|
||||
|
||||
/**
|
||||
* Вывод в браузер всего сайта.
|
||||
*
|
||||
*/
|
||||
public function display()
|
||||
{
|
||||
try {
|
||||
$this->route = Load::router()->proccess(MJ_PATH);
|
||||
$decorator = new $this->route->decorator;
|
||||
return $decorator->display(new $this->route->action);
|
||||
} catch (MJException $e) {
|
||||
return $e->terminate();
|
||||
} catch (Exception $e) {
|
||||
$decorator_name = DEFAULT_DECORATOR;
|
||||
$action_name = DEFAULT_ACTION;
|
||||
|
||||
$decorator = new $decorator_name;
|
||||
return $decorator->display(new $action_name($e->getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
113
classes/Router.class.php
Normal file
113
classes/Router.class.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/**
|
||||
* Класс для работы с роутерами
|
||||
*
|
||||
* @copyright
|
||||
* @link
|
||||
* @package Majestic
|
||||
* @subpackage Core
|
||||
* @since
|
||||
* @version SVN: $Id$
|
||||
* @filesource $URL$
|
||||
*/
|
||||
|
||||
final class Router
|
||||
{
|
||||
protected $routes = array();
|
||||
|
||||
/**
|
||||
* Добавить роутер
|
||||
*
|
||||
* @param string $name - имя роутера
|
||||
* @param string $path - путь
|
||||
* @param string $action - имя действия
|
||||
* @param array $params - массив параметров
|
||||
*/
|
||||
function add($name, $path, $action, $params = array())
|
||||
{
|
||||
$this->routes[$name] = new Route($path, $action, $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Установить декоратор для роута (действия), отличный от стандартного
|
||||
*
|
||||
* @param string $name - имя роута (действия)
|
||||
* @param string $decorator - имя декоратора
|
||||
*/
|
||||
function setDecorator($name, $decorator)
|
||||
{
|
||||
if (isset($this->routes[$name])) {
|
||||
$this->routes[$name]->decorator = $decorator.DECORATOR_POSTFIX;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Найти роутер соответствующий заданному пути
|
||||
*
|
||||
* @param stirng $path - путь
|
||||
* @return Route - роутер
|
||||
*/
|
||||
function proccess($path)
|
||||
{
|
||||
$path = explode('/', $path);
|
||||
|
||||
foreach ($this->routes as $name => $route) {
|
||||
if ($route->match($path)) {
|
||||
$route->action .= ACTION_POSTFIX;
|
||||
Env::setParams($route->params);
|
||||
return $route;
|
||||
}
|
||||
}
|
||||
throw new Exception(E_404);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Роутер
|
||||
*
|
||||
*/
|
||||
final class Route
|
||||
{
|
||||
const URL_VARIABLE = '&';
|
||||
|
||||
protected $path;
|
||||
|
||||
public $decorator = DEFAULT_DECORATOR;
|
||||
public $action;
|
||||
public $params;
|
||||
|
||||
function __construct($path, $action, $params=array())
|
||||
{
|
||||
$this->path = $path;
|
||||
$this->action = $action;
|
||||
$this->params = $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет соответствие роутера и пути
|
||||
*
|
||||
* @param string $path - путь для сравнения
|
||||
* @return boolean - соответствует или нет
|
||||
*/
|
||||
function match($path_arr)
|
||||
{
|
||||
$parts = explode('/', $this->path);
|
||||
$cnt = count($parts);
|
||||
if (end($parts) == self::URL_VARIABLE) {
|
||||
$cnt--;
|
||||
} elseif ($cnt != count($path_arr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for ($i=0; $i<$cnt; $i++) {
|
||||
if (substr($parts[$i], 0, 1) == self::URL_VARIABLE) {
|
||||
$this->params[substr($parts[$i], 1)] = $path_arr[$i];
|
||||
} elseif ($parts[$i] != $path_arr[$i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
?>
|
99
classes/Sublimer.class.php
Normal file
99
classes/Sublimer.class.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/**
|
||||
* Простейший шаблонизатор.
|
||||
* Зато быстрый.
|
||||
*
|
||||
* @copyright
|
||||
* @link
|
||||
* @package Majestic
|
||||
* @subpackage Decorator
|
||||
* @since
|
||||
* @version SVN: $Id$
|
||||
* @filesource $URL$
|
||||
*/
|
||||
final class Sublimer
|
||||
{
|
||||
const GLOBAL_KEY = 0;
|
||||
|
||||
public $vars = array();
|
||||
public $path = '';
|
||||
public $template = '';
|
||||
|
||||
protected $head_array = array();
|
||||
|
||||
/**
|
||||
* Конструктор
|
||||
*
|
||||
* @param string $path - путь до шаблонов
|
||||
*/
|
||||
public function __construct($path = '')
|
||||
{
|
||||
$this->setPath($path);
|
||||
$this->vars[self::GLOBAL_KEY] = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Присвоить переменную только
|
||||
*
|
||||
* @param string $name - имя переменной
|
||||
* @param mixed $value - значение переменной
|
||||
* @param string $template - шаблон, если не указан, то переменная глобальная
|
||||
*/
|
||||
public function assign($name, $value, $template = self::GLOBAL_KEY)
|
||||
{
|
||||
$this->vars[$template][$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Очистить стек переменных
|
||||
* @param boolean $with_local - включая локальные переменные
|
||||
*/
|
||||
public function clear($template = self::GLOBAL_KEY)
|
||||
{
|
||||
$this->vars[$template] = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Обработать шаблон
|
||||
*
|
||||
* @param string $template - относительный путь до шаблона
|
||||
* @return string - обработанное содержимое шаблона
|
||||
*/
|
||||
public function fetch($template)
|
||||
{
|
||||
$this->template = $template; //дабы экстракт не перезатер нам переменную. Это важно! $this то он не перезатрет :)
|
||||
extract($this->vars[self::GLOBAL_KEY]);
|
||||
if (isset($this->vars[$this->template])) {
|
||||
extract($this->vars[$this->template], EXTR_OVERWRITE);
|
||||
}
|
||||
ob_start();
|
||||
if (!(include $this->path.'/'.$this->template) == 'OK') {
|
||||
throw new MJException('Template '.$this->path.'/'.$this->template.' not found');
|
||||
}
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Установать путь до шаблонов
|
||||
*
|
||||
* @param string $path - путь до шаблонов
|
||||
*/
|
||||
public function setPath($path)
|
||||
{
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
//Функции для вызова из шаблонов.
|
||||
|
||||
protected function addHead($str)
|
||||
{
|
||||
$this->head_array[] = $str;
|
||||
}
|
||||
|
||||
protected function getHead()
|
||||
{
|
||||
return $this->head_array;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
101
classes/User.class.php
Normal file
101
classes/User.class.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
/**
|
||||
* Класс для работы с пользователями
|
||||
*
|
||||
* @copyright
|
||||
* @link
|
||||
* @package Majestic
|
||||
* @subpackage Decorator
|
||||
* @since
|
||||
* @version SVN: $Id$
|
||||
* @filesource $URL$
|
||||
*/
|
||||
class User
|
||||
{
|
||||
static private $user = false;
|
||||
|
||||
static function login($login, $password)
|
||||
{
|
||||
if (empty($login) || empty($password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!preg_match("/^[a-z0-9_-]{3,20}$/i", $login)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!self::$user = self::getByLogin(strtolower($login)) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self::$user->pass != $password) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self::setSession();
|
||||
return true;
|
||||
}
|
||||
|
||||
static function logout()
|
||||
{
|
||||
Env::setCookie(session_name(), '', 0);
|
||||
Env::setCookie('login', '', 0);
|
||||
Env::setCookie('login_hash', '', 0);
|
||||
if (session_id()) {
|
||||
session_destroy();
|
||||
}
|
||||
}
|
||||
|
||||
static function process()
|
||||
{
|
||||
if (Env::getCookie(session_name())) { //есть сессия
|
||||
session_start();
|
||||
} elseif (Env::getCookie('login') && Env::getCookie('login_hash')) {
|
||||
self::remember();
|
||||
}
|
||||
}
|
||||
|
||||
static function setSession()
|
||||
{
|
||||
Env::setCookie('login', self::$user->login, TIME_NOW + LOGIN_COOKIE_TTL);
|
||||
Env::setCookie('login_hash', self::getHash(), TIME_NOW + LOGIN_COOKIE_TTL);
|
||||
|
||||
session_start();
|
||||
|
||||
$_SESSION['user'] = self::$user;
|
||||
}
|
||||
|
||||
static function remember()
|
||||
{
|
||||
if (! self::$user = self::getByLogin(Env::getCookie('login'))) {
|
||||
self::logout();
|
||||
}
|
||||
|
||||
if (Env::getCookie('login_hash') == self::getHash()) {
|
||||
self::setSession();
|
||||
} else {
|
||||
self::logout();
|
||||
}
|
||||
}
|
||||
|
||||
static function getHash()
|
||||
{
|
||||
return md5(self::$user->id.'hckrz'.self::$user->login.'mst'.self::$user->pass.'dai');
|
||||
}
|
||||
|
||||
static function getInfo()
|
||||
{
|
||||
return Env::Session('user', self::$user);
|
||||
}
|
||||
|
||||
static function isGuest()
|
||||
{
|
||||
return ! (bool) Env::Session('user');
|
||||
}
|
||||
|
||||
static function getByLogin($login)
|
||||
{
|
||||
return Load::model('UserData')->getByLogin($login);
|
||||
}
|
||||
}
|
||||
?>
|
Reference in New Issue
Block a user