diff --git a/Config.php b/Config.php index acd76ea..9dd45f6 100644 --- a/Config.php +++ b/Config.php @@ -14,18 +14,19 @@ class Config extends ArrayObject private static $_instance = null; - public function __construct($config = array()) { parent::__construct($config, ArrayObject::ARRAY_AS_PROPS); } + private function __clone(){} + /** * @return Config */ static public function getInstance() { - if (is_null(self::$_instance)) { + if (! isset(self::$_instance)) { self::$_instance = new Config(); } return self::$_instance; @@ -47,7 +48,6 @@ class Config extends ArrayObject } self::getInstance()->offsetSet($name, $value); } - } class ConfigArray extends ArrayObject diff --git a/Load.php b/Load.php new file mode 100644 index 0000000..070c72c --- /dev/null +++ b/Load.php @@ -0,0 +1,37 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage Load + * @since 2010-02-24 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +class Load +{ + + static protected $autoload; + + static public function autoload($class) + { + if (! isset(self::$autoload[$class])) { + throw new MJException('There is no such class "' . $class . '" in autoload.'); + } + require(PATH . self::$autoload[$class]); + } + + static public function setAutoloadFrom($file) + { + if (! file_exists($file)) { + throw new MJException('Autoload source doesn\'t exists! Try to generate it!'); + } + self::$autoload = require($file); + } + + static public function getFilePath($class) + { + return self::$autoload[$class]; + } +} \ No newline at end of file diff --git a/app/Action.php b/app/Action.php new file mode 100644 index 0000000..1e734d9 --- /dev/null +++ b/app/Action.php @@ -0,0 +1,51 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage app + * @since 2010-02-25 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +abstract class Action +{ + + public function __construct() + { + $this->extractParams(); + $this->execute(); + } + + protected function extractParams() + { + $params = FrontController::getInstance()->getRouter()->getRoute()->getParams(); + if ($params) { + foreach ($params as $name => $value) { + if (is_string($name)) { + $this->$name = $value; + } + } + } + } + + abstract protected function execute(); + + /** + * Redirect + * + * @param mixed $url + * @param mixed $relative Default to true + */ + protected function redirect($url = null, $relative = true) + { + $url = ($url) ? $url : Env::getRequestUri(); + + if ($relative) { + $url = FrontController::getInstance()->getBaseUrl() . $url; + } + header('Location: ' . $url); + exit(); + } +} \ No newline at end of file diff --git a/app/FrontController.php b/app/FrontController.php new file mode 100644 index 0000000..465f3c8 --- /dev/null +++ b/app/FrontController.php @@ -0,0 +1,127 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage app + * @since 2010-02-24 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +class FrontController +{ + /** + * @var Router + */ + protected $router; + + /** + * @var string + */ + protected $view = 'PHPView'; + + /** + * @var string + */ + protected $view_path; + + protected $base_url = ''; + + /** + * @var FrontController + */ + protected static $instance; + + + private function __construct() + { + $this->router = new Router(); + } + + private function __clone(){} + + /** + * @return FrontController + */ + static public function getInstance() + { + if (! isset(self::$instance)) { + self::$instance = new self(); + } + return self::$instance; + } + + /** + * @param string $path + * @return FrontController + */ + public function setViewPath($path) + { + $this->view_path = $path; + return $this; + } + + /** + * @param string $view + * @return FrontController + */ + public function setView($view) + { + $this->view = $view; + return $this; + } + + /** + * + * @return iView + */ + public function getView($view = null) + { + $view = ($view) ? $view : $this->view; + return new $view($this->view_path); + } + + /** + * @param string $url + */ + public function setBaseUrl($url) + { + $this->base_url = rtrim($url, '/'); + return $this; + } + + public function getBaseUrl() + { + return $this->base_url; + } + + /** + * @return Router + */ + public function getRouter() + { + return $this->router; + } + + + public function execute() + { + + try { + $request = Env::getRequestUri(); + $route = $this->getRouter()->route($request); + if (! $route) { + throw new Exception('Route "' . $request . '" not found'); + } + + $action_class = $route->getAction(); + $action = new $action_class(); + $layout_class = $route->getLayout(); + $layout = new $layout_class(); + return $layout->fetch($action); + } catch (Exception $e) { + throw $e; + } + } +} \ No newline at end of file diff --git a/app/StaticViewAction.php b/app/StaticViewAction.php new file mode 100644 index 0000000..768f1cd --- /dev/null +++ b/app/StaticViewAction.php @@ -0,0 +1,25 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage app + * @since 2010-02-25 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +abstract class StaticViewAction extends ViewAction +{ + + protected function getTemplate() + { + $template = ($this->template) ? $this->template : substr(get_class($this), 0, -6/*strlen('Action')*/); + return '/static/' . $template; + } + + public function fetch() + { + return $this->view->fetch($this->getTemplate()); + } +} \ No newline at end of file diff --git a/app/ViewAction.php b/app/ViewAction.php new file mode 100644 index 0000000..a86c0a2 --- /dev/null +++ b/app/ViewAction.php @@ -0,0 +1,41 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage app + * @since 2010-02-25 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +abstract class ViewAction extends Action +{ + + protected $template; + + /** + * @var PHPView + */ + protected $view; + + public function __construct() + { + $this->view = FrontController::getInstance()->getView(); + parent::__construct(); + } + + protected function getTemplate() + { + $class = get_class($this); + $template = ($this->template) ? $this->template : substr($class, 0, -6/*strlen('Action')*/); + $dir = array_slice(explode('/', Load::getFilePath($class)), -2, 1); + return '/actions/' . array_pop($dir) . '/' . $template; + } + + public function fetch() + { + $this->view->assignObject($this); + return $this->view->fetch($this->getTemplate()); + } +} \ No newline at end of file diff --git a/app/router/Route.php b/app/router/Route.php new file mode 100644 index 0000000..fffecab --- /dev/null +++ b/app/router/Route.php @@ -0,0 +1,72 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage app + * @since 2010-02-25 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +class Route +{ + + protected $route; + protected $action; + protected $params; + protected $layout; + + public function __construct($route, $action, $params = null, $layout = null) + { + $this->route = $route; + $this->action = $action; + $this->params = $params; + $this->layout = $layout; + } + + /** + * @param array $request + */ + public function match($request) + { + $parts = explode('/', $this->route); + $cnt = count($parts); + + if(count($request) != $cnt) { + return false; + } + + for ($i = 0; $i < $cnt; $i++) { + if (substr($parts[$i], 0, 1) == ':') { + $this->params[substr($parts[$i], 1)] = $request[$i]; + } elseif (substr($parts[$i], 0, 2) == '(?') { + $match = array(); + if (!preg_match('#^' . $parts[$i] . '$#iu', $request[$i], $match)) { + return false; + } + $start = strpos($parts[$i], '<') + 1; + $key = substr($parts[$i], $start, strpos($parts[$i], '>', $start) - $start); + $this->params[$key] = $match[$key]; + } elseif ($parts[$i] != $request[$i]) { + return false; + } + } + return true; + } + + public function getAction() + { + return $this->action . 'Action'; + } + + public function getLayout() + { + return $this->layout . 'Layout'; + } + + public function getParams() + { + return $this->params; + } +} diff --git a/app/router/Router.php b/app/router/Router.php new file mode 100644 index 0000000..44ce240 --- /dev/null +++ b/app/router/Router.php @@ -0,0 +1,65 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage app + * @since 2010-02-25 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +class Router +{ + + protected $routes = array(); + + protected $route_name; + + protected $default_layout = 'Default'; + + /** + * @var Route + */ + protected $route; + + public function add($name, $route, $action, $params = null, $layout = null) + { + if (! $layout) { + $layout = $this->default_layout; + } + $this->routes[$name] = new Route($route, $action, $params, $layout); + } + + public function route($request) + { + $req = explode('/', trim($request, '/')); + + foreach ($this->routes as $name => $route) { + if ($route->match($req)) { + $this->route_name = $route; + $this->route = $route; + return $this->route; + } + } + return false; + } + + public function setDefaultLayout($layout = 'Default') + { + $this->default_layout = $layout; + } + + public function getRouteName() + { + return $this->route_name; + } + + /** + * @return Route + */ + public function getRoute() + { + return $this->route; + } +} \ No newline at end of file diff --git a/classes/Action.class.php b/classes/Action.class.php deleted file mode 100644 index 55da923..0000000 --- a/classes/Action.class.php +++ /dev/null @@ -1,109 +0,0 @@ - - * @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(); - $this->prepare(); - $this->templater->setPath(ACTION_TPL_PATH.'/'.$this->template_dir); - 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; - } - } -} -?> \ No newline at end of file diff --git a/classes/DBConnector.class.php b/classes/DBConnector.class.php deleted file mode 100644 index b670c24..0000000 --- a/classes/DBConnector.class.php +++ /dev/null @@ -1,159 +0,0 @@ - - * @link - * @package Majestic - * @subpackage DB - * @since - * @version SVN: $Id$ - * @filesource $URL$ - */ -class DBConnector -{ - - /** - * PDO constant values. - */ - const FETCH_ASSOC = 2; - const FETCH_BOTH = 4; - const FETCH_NUM = 3; - const FETCH_OBJ = 5; - - static private $handlers = array(); - static public $queries = array(); - - /** - * Запрещаем new и клонирование - */ - private function __construct(){} - - private function __clone(){} - - /** - * Получение соединения. - * Если соединение с такими параметрами уже есть - новое не создается. - * - * @param array $db_settings - массив настроек - * @return resource - идентификатор соединения - */ - static public 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); - } - - self::query($handler, "SET NAMES 'utf8'"); //cheat!!! - return self::$handlers[$handler_name] = $handler; - } - - static protected function getConnectionName($db_settings) - { - return $db_settings['host'] . '-' . $db_settings['database']; - } - -///////// - - static public function query($handler, $sql) - { - return mysqli_query($handler, $sql); - } - - static public function escape($handler, $str) - { - return mysqli_real_escape_string($handler, $str); - } - - static public function error($handler) - { - return mysqli_error($handler); - } - - static public function free($result) - { - return mysqli_free_result($result); - } - - static public function fetchObject($result, $class_name = false) - { - return $class_name ? mysqli_fetch_object($result, $class_name) : mysqli_fetch_object($result); - } - - /** - * Fetches a row from the result set. - * - * @param mysqli_result $result - * @param int $style OPTIONAL Fetch mode for this fetch operation. - * @return mixed Array, object, or scalar depending on fetch mode. - * @throws Exception - */ - static public function fetchArray($result, $style = null) - { - if (!$result) { - return false; - } - - if ($style === null) { - $style = self::FETCH_ASSOC; - } - - $row = false; - switch ($style) { - case self::FETCH_NUM: - $row = mysqli_fetch_array($result, MYSQLI_NUM); - break; - case self::FETCH_ASSOC: - $row = mysqli_fetch_array($result, MYSQLI_ASSOC); - break; - case self::FETCH_BOTH: - $row = mysqli_fetch_array($result, MYSQLI_BOTH); - break; - case self::FETCH_OBJ: - $row = mysqli_fetch_object($result, MYSQLI_BOTH); - break; - default: - throw new Exception('Invalid fetch mode "' . $style . '" specified'); - break; - } - return $row; - } - - static public function numRows($result) - { - return mysqli_num_rows($result); - } - - static public function affectedRows($handler, $result) - { - return mysqli_affected_rows($handler); - } - - static public function getId($handler) - { - return mysqli_insert_id($handler); - } - - static public function autocommit($handler, $switch) - { - return mysqli_autocommit($handler, (bool) $switch); - } - - static public function commit($handler) - { - return mysqli_commit($handler); - } - - static public function rollback($handler) - { - return mysqli_rollback($handler); - } -} -?> \ No newline at end of file diff --git a/classes/Decorator.class.php b/classes/Decorator.class.php deleted file mode 100644 index 0f0707c..0000000 --- a/classes/Decorator.class.php +++ /dev/null @@ -1,62 +0,0 @@ - - * @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(); -} -?> \ No newline at end of file diff --git a/classes/DynamicPageException.class.php b/classes/DynamicPageException.class.php deleted file mode 100644 index f551267..0000000 --- a/classes/DynamicPageException.class.php +++ /dev/null @@ -1,16 +0,0 @@ - - * @link - * @package Majestic - * @subpackage Core - * @since - * @version SVN: $Id$ - * @filesource $URL$ - */ -class DynamicPageException extends Exception -{} -?> \ No newline at end of file diff --git a/classes/Env.class.php b/classes/Env.class.php index aa3b9cb..db72236 100644 --- a/classes/Env.class.php +++ b/classes/Env.class.php @@ -3,38 +3,54 @@ * Класс для работы с переменными окружения. * * @copyright NetMonsters - * @link + * @link http://netmonsters.ru * @package Majestic - * @subpackage Core + * @subpackage env * @since * @version SVN: $Id$ * @filesource $URL$ */ -final class Env -{ - static public $params = array(); - static function Get($var, $default = false) +class Env +{ + + static protected $request = null; + + static public function getRequestUri() + { + if (self::$request === null) { + // removes get params + list(self::$request, ) = explode('?', Env::Server('REQUEST_URI')); + // removes base url + $base = FrontController::getInstance()->getBaseUrl(); + if (($length = strlen($base)) > 0 && strpos(self::$request, $base) === 0) { + self::$request = (string) substr(self::$request, $length); + } + } + return self::$request; + } + + static public function Get($var, $default = false) { return isset($_GET[$var]) ? $_GET[$var] : $default; } - static function Post($var, $default = false) + static public function Post($var, $default = false) { return isset($_POST[$var]) ? $_POST[$var] : $default; } - static function Server($var, $default = false) + static public function Server($var, $default = false) { return isset($_SERVER[$var]) ? $_SERVER[$var] : $default; } - static function Session($var, $default = false) + static public function Session($var, $default = false) { return isset($_SESSION[$var]) ? $_SESSION[$var] : $default; } - static function setSession($var, $value) + static public function setSession($var, $value) { $_SESSION[$var] = $value; } @@ -44,48 +60,32 @@ final class Env * * @param string $var */ - static function unsetSession($var) + static public function unsetSession($var) { if (isset($_SESSION[$var])) { unset($_SESSION[$var]); } } - static function getCookie($var, $default = false) + static public function getCookie($var, $default = false) { return isset($_COOKIE[$var]) ? $_COOKIE[$var] : $default; } - static function setCookie($var, $value, $time = 0, $path = '/') + static public 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 public function Files($name = '', $default = array(), $param = false) { - if(!isset($_FILES)){ + if (!isset($_FILES)) { return $default; } - if(empty($name)){ + if (empty($name)) { return $_FILES; } $res = isset($_FILES[$name]) ? $_FILES[$name] : $default; return $param ? $res[$param] : $res; } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/classes/Load.class.php b/classes/Load.class.php deleted file mode 100644 index d05e1e5..0000000 --- a/classes/Load.class.php +++ /dev/null @@ -1,45 +0,0 @@ - - * @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; - } -} -?> \ No newline at end of file diff --git a/classes/Model.class.php b/classes/Model.class.php deleted file mode 100644 index 3623cdb..0000000 --- a/classes/Model.class.php +++ /dev/null @@ -1,262 +0,0 @@ - - * @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) - { - if (DEBUG_ENABLE) { - $time = microtime(true); - } - $res = DBConnector::query($this->handler, $sql); - if ($error = DBConnector::error($this->handler)) { - throw new MJException("Query Error:\n".$sql."\nError:\n".$error, 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': - case '(selec': - return new ModelSelectResult($res); - case 'insert': - case 'replac': - return new ModelInsertResult($this->handler, $res); //$res for postgreSQL - default: - return new ModelChangeResult($this->handler, $res); //$res for postgreSQL - } - } - - /** - * Экранирует строку - * - * @param mixed $data - строка для экранирования - * @return mixed - */ - function escape($data) - { - if(is_array($data)){ - foreach($data as $id => $val){ - $data[$id] = DBConnector::escape($this->handler, $val); - } - return $data; - } - return DBConnector::escape($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 = '') - { - $keys = array(); - $values = array(); - - foreach ($data as $key => $val) { - $keys[] = $key; - $values[] = $this->escape($val); - } - return $this->query('INSERT INTO '.$this->table.' ('.implode(',', $keys).") VALUES('".implode("','", $values)."') ".$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 : ''))->fetchAll(); - } - - function setAutocommit($set) - { - return DBConnector::autocommit($this->handler, (bool) $set); - } - - function commit() - { - return DBConnector::commit($this->handler); - } - - function rollback() - { - return DBConnector::rollback($this->handler); - } - - /** - * Возвращает значение поля $table - * @return string - */ - function getTableName() - { - return $this->table; - } -} - -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($class_name = false) - { - return DBConnector::fetchObject($this->result, $class_name); - } - - 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 = DBConnector::fetchObject($this->result)) { - $array[$row->$key] = $row; - } - } else { - while ($row = DBConnector::fetchObject($this->result)) { - $array[] = $row; - } - } - return $array; - } - - /** - * Fetches all SQL result rows as an array of key-value pairs. - * - * The first column is the key, the second column is the - * value. - * - * @return array - */ - public function fetchPairs() - { - if (!method_exists('DBConnector', 'fetchArray')) { - throw new Exception('Method not implemented yet.'); - } - - $data = array(); - while ($row = DBConnector::fetchArray($this->result, DBConnector::FETCH_NUM)) { - $data[$row[0]] = $row[1]; - } - return $data; - } - - - function count() - { - return DBConnector::numRows($this->result); - } - - function free() - { - DBConnector::free($this->result); - } - - function __destruct() { - $this->free(); - } -} - -class ModelChangeResult extends ModelResult -{ - public $affected; - - function __construct($resource, $result) - { - $this->affected = DBConnector::affectedRows($resource, $result); - } - - function count() - { - return $this->affected; - } -} - -class ModelInsertResult extends ModelChangeResult -{ - public $id; - - function __construct($resource, $result) - { - parent::__construct($resource, $result); - $this->id = DBConnector::getId($resource); - } - - function getId() - { - return $this->id; - } -} -?> \ No newline at end of file diff --git a/classes/PageController.class.php b/classes/PageController.class.php deleted file mode 100644 index 1e2d752..0000000 --- a/classes/PageController.class.php +++ /dev/null @@ -1,60 +0,0 @@ - - * @link - * @package Majestic - * @subpackage PageController - * @since - * @version SVN: $Id$ - * @filesource $URL$ - */ -class PageController -{ - - /** - * Действия на инициализацию. - * - */ - protected function init() {} - - /** - * Действия после разбора роута. - * - */ - protected function onDispatch() {} - - /** - * Вывод в браузер всего сайта. - * - */ - public function display() - { - try { - $this->init(); - try{ - $this->route = Load::router()->proccess(MJ_PATH); - $this->onDispatch(); - $action = new $this->route->action; - $decorator = new $this->route->decorator; - return $decorator->display($action); - } catch (MJException $e) { - return $e->terminate(); - } - } catch (DynamicPageException $e) { - $decorator_name = DEFAULT_DECORATOR; - $decorator = new $decorator_name; - $action_name = $e->getMessage(); - return $decorator->display(new $action_name); - } catch (StaticPageException $e) { - $decorator_name = DEFAULT_DECORATOR; - $decorator = new $decorator_name; - $action_name = DEFAULT_ACTION; - return $decorator->display(new $action_name($e->getMessage())); - } catch (Exception $e) { - return $e->getMessage(); - } - } -} -?> \ No newline at end of file diff --git a/classes/Router.class.php b/classes/Router.class.php deleted file mode 100644 index fba9096..0000000 --- a/classes/Router.class.php +++ /dev/null @@ -1,131 +0,0 @@ - - * @link - * @package Majestic - * @subpackage Core - * @since - * @version SVN: $Id$ - * @filesource $URL$ - */ - -final class Router -{ - - protected $routes = array(); - - static protected $rewrite_base = ''; - static protected $decorator = DEFAULT_DECORATOR; - static protected $route_name = ''; - - - /** - * Добавить роутер - * - * @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); - $this->routes[$name]->decorator = self::$decorator; - } - - /** - * Установить декоратор для роута (действия), отличный от стандартного - * - * @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); - self::$route_name = $name; - return $route; - } - } - throw new StaticPageException(E_404); - } - - static public function setDefaultDecorator($decorator) - { - self::$decorator = $decorator.DECORATOR_POSTFIX; - } - - static public function getRouteName() - { - return self::$route_name; - } -} - -/** - * Роутер - * - */ -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; - } -} -?> \ No newline at end of file diff --git a/classes/StaticPageException.class.php b/classes/StaticPageException.class.php deleted file mode 100644 index 23b3427..0000000 --- a/classes/StaticPageException.class.php +++ /dev/null @@ -1,18 +0,0 @@ - - * @link - * @package Majestic - * @subpackage Core - * @since - * @version SVN: $Id$ - * @filesource $URL$ - */ -class StaticPageException extends Exception -{ - -} -?> \ No newline at end of file diff --git a/classes/Sublimer.class.php b/classes/Sublimer.class.php deleted file mode 100644 index 02a933d..0000000 --- a/classes/Sublimer.class.php +++ /dev/null @@ -1,175 +0,0 @@ - - * @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; - } - - /** - * обрезает текст до заданной длинны - * - * @param string $text - * @param int $count - * @param string $postfix - */ - protected function trimString($text, $count = 15, $postfix = "...") - { - return (mb_strlen($text) > $count) ? mb_substr($text, 0, $count).$postfix : $text; - } - - - /** - * Выполняет разрыв строки на данное количество символов с использованием символа разрыва (wordwrap для utf) - * - * @param string $text - * @param int $width - * @param string $break - * @return string - */ - protected function wrapString($text, $width = 15, $break = " ") - { - $words = explode(' ', $text); - for ($i = 0; $i < count($words); $i++) { - if (mb_strlen($words[$i]) > $width) { - for ($j = $width; $j < mb_strlen($words[$i]); $j += $width + (mb_strlen($break))) { - $words[$i] = mb_substr($words[$i], 0, $j) . $break . mb_substr($words[$i], $j); - } - } - } - return implode(' ', $words); - } - - /** - * Формирует get-строку для запроса - * - * @param array/string $replace - Имя переменной для замены (либо массив ключ=значение) В случае false вернет весь get - * @param mixed $value - значение переменной для замены, если $replace - массив, то не играет роли. В случае false переменная удаляется из get - * @return string - */ - function formGet($replace = false, $value = false) - { - $chunk = true; //обрезать последний & (или ?) - $get = $_GET; //дабы не менять дефолтный массив - if (is_array($replace)) { - foreach($replace as $key => $val) { - if($val === false) { - unset($get[$key]); - $chunk = false; - } else { - $get[$key] = $val; - } - } - } else if ($replace !== false) { - if ($value === false) { //для получения строки БЕЗ параметра с именем $replace - unset($get[$replace]); - $chunk = false; - } else { - $get[$replace] = $value; - } - } - - $str = '?'; - foreach($get as $key => $val) { - $str .= $key.'='.$val.'&'; - } - - if ($chunk) { - $str = mb_substr($str, 0, -1); - } - - return htmlspecialchars($str); - } - -} - -?> \ No newline at end of file diff --git a/classes/pg_DBConnector.class.php b/classes/pg_DBConnector.class.php deleted file mode 100644 index 7de1963..0000000 --- a/classes/pg_DBConnector.class.php +++ /dev/null @@ -1,110 +0,0 @@ - - * @link - * @package Majestic - * @subpackage DB - * @since - * @version SVN: $Id$ - * @filesource $URL$ - */ -class DBConnector -{ - static private $handlers = array(); - static public $queries = array(); - - /** - * Запрещаем new и клонирование - */ - private function __construct(){} - - private function __clone(){} - - /** - * Получение соединения. - * Если соединение с такими параметрами уже есть - новое не создается. - * - * @param array $db_settings - массив настроек - * @return resource - идентификатор соединения - */ - static public function getConnect($db_settings) - { - $handler_name = self::getConnectionName($db_settings); - - if (isset(self::$handlers[$handler_name])) { - return self::$handlers[$handler_name]; - } - - if (!$handler = pg_connect("host='".$db_settings['host']."' dbname='".$db_settings['database']."' user='".$db_settings['user']."' password='".$db_settings['password']."'")) { - throw new MJException('Can\'t connect to DB '.pg_last_error(), 2); - } - - return self::$handlers[$handler_name] = $handler; - } - - static protected function getConnectionName($db_settings) - { - return $db_settings['host'] . '-' . $db_settings['database']; - } - -///////// - - static public function query($handler, $sql) - { - return pg_query($handler, $sql); - } - - static public function escape($handler, $str) - { - return pg_escape_string($str); - } - - static public function error($handler) - { - return pg_last_error($handler); - } - - static public function free($result) - { - return pg_free_result($result); - } - - static public function fetchObject($result, $class_name = false) - { - return $class_name ? pg_fetch_object($result, null, $class_name) : pg_fetch_object($result); - } - - static public function numRows($result) - { - return pg_num_rows($result); - } - - static public function affectedRows($handler, $result) - { - return pg_affected_rows($result); - } - - static public function getId($handler) - { - return -1; //DISABLED FORM postgreSQL - } - - static public function autocommit($handler, $switch) - { - throw new MJException('Autocommit disabled for postgreSQL Connector' ,1); - } - - static public function commit($handler) - { - throw new MJException('Commit disabled for postgreSQL Connector' ,1); - } - - static public function rollback($handler) - { - throw new MJException('Rollback disabled for postgreSQL Connector' ,1); - } -} -?> \ No newline at end of file diff --git a/init/init.inc.php b/init/init.inc.php deleted file mode 100644 index f1a50a5..0000000 --- a/init/init.inc.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @link - * @package Nakon - * @subpackage Config - * @since - * @version SVN: $Id$ - * @filesource $URL$ - */ - -require('sys.inc.php'); -$path = explode('?', Env::Server('REQUEST_URI')); -$path = trim($path[0], '/'); -define('MJ_URL', '/'.$path.'/'); -if (defined('PATH_TRIM') && PATH_TRIM != '' && strpos($path, PATH_TRIM) === 0) { - $path = substr($path, strlen(PATH_TRIM) + 1); -} -define('MJ_PATH', $path); -unset($path); - -require(CONFIG_PATH.'/routers.inc.php'); - -define('E_404', 404); -define('E_403', 403); -?> \ No newline at end of file diff --git a/init/sys.inc.php b/init/sys.inc.php deleted file mode 100644 index 88cb8c7..0000000 --- a/init/sys.inc.php +++ /dev/null @@ -1,100 +0,0 @@ - - * @link - * @package Nakon - * @subpackage System - * @since - * @version SVN: $Id$ - * @filesource $URL$ - */ -/** -* Пути к файлам системы. -*/ -$a = realpath(dirname(__FILE__).'/../..').'/'; -define('INIT_PATH', $a.'config'); -define('CORE_PATH', $a.'core/classes'); -define('LIB_PATH', $a.'lib'); -define('MODEL_PATH', $a.'lib/models'); - -define('CACHE_PATH', $a.'cache'); - - -if (!defined('SITE_PART')) { - define('SITE_PART', 'admin'); -} - -define('HTDOCS_PATH', $a.SITE_PART.'/htdocs'); -define('DECORATOR_PATH', $a.SITE_PART.'/decorators'); -define('ACTION_PATH', $a.SITE_PART.'/actions'); -define('TPL_PATH', $a.SITE_PART.'/templates'); -define('CONFIG_PATH', $a.SITE_PART.'/config'); -unset($a); - -define('WRAPPERS_TPL_PATH', TPL_PATH.'/wrappers'); -define('ACTION_TPL_PATH', TPL_PATH.'/actions'); -define('STATIC_TPL_PATH', TPL_PATH.'/static'); - -define('DECORATOR_POSTFIX', 'Decorator'); -define('MODEL_POSTFIX', 'Model'); -define('ACTION_POSTFIX', 'Action'); -define('EXCEPTION_POSTFIX', 'Exception'); - -define('TIME_NOW', time()); - -/** -* Основные файлы системы. -* Эти файлы загружаются всегда, т.к. без них работа системы невозможна -*/ -require(CORE_PATH.'/Env.class.php'); -require(CORE_PATH.'/Load.class.php'); -require(CORE_PATH.'/Router.class.php'); -require(CORE_PATH.'/PageController.class.php'); -require(CORE_PATH.'/Decorator.class.php'); -require(CORE_PATH.'/Action.class.php'); - -/** -* Файлы конфигурации. -*/ -if (file_exists(INIT_PATH.'/local.inc.php')) { - require(INIT_PATH.'/local.inc.php'); -} else { - require(INIT_PATH.'/global.inc.php'); -} -Env::setParams($CONFIG); -require(CONFIG_PATH.'/config.inc.php'); -Env::setParams($CONFIG); - -function __autoload($name) -{ - preg_match_all('/[A-Z]+[^A-Z]+/', $name, $match); - $type = end($match[0]); - - $class_name = substr($name, 0, -strlen($type)); - - switch ($type) { - case 'DBConnector': - require(CORE_PATH.'/'.(defined('CUSTOM_DBCONNECTOR') ? CUSTOM_DBCONNECTOR.'_' : '').'DBConnector.class.php'); - break; - case $name: - case EXCEPTION_POSTFIX: - require(CORE_PATH.'/'.$name.'.class.php'); - break; - case ACTION_POSTFIX: - require(ACTION_PATH.'/'.strtolower($match[0][0]).'/'.$class_name.'.action.php'); - break; - case DECORATOR_POSTFIX: - require(DECORATOR_PATH.'/'.$class_name.'.decorator.php'); - break; - case MODEL_POSTFIX: - require(MODEL_PATH.'/'.$class_name.'.model.php'); - break; - default: - require(LIB_PATH.'/'.$name.'.lib.php'); - } -} -?> \ No newline at end of file diff --git a/layout/Layout.php b/layout/Layout.php new file mode 100644 index 0000000..3d291d8 --- /dev/null +++ b/layout/Layout.php @@ -0,0 +1,53 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage Layout + * @since 2010-02-25 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +abstract class Layout +{ + + protected $template; + + /** + * @var PHPView + */ + protected $view; + + public function __construct() + { + $this->view = FrontController::getInstance()->getView(); + } + + /** + * @param string $name + * @param ViewAction $action + */ + protected function assign($name, $action) + { + $this->view->assign($name, $action->fetch()); + } + + abstract protected function execute(); + + /** + * @param ViewAction $action + */ + public function fetch($action) + { + $this->view->assign('content', $action->fetch()); + $this->execute(); + return $this->view->fetch($this->getTemplate()); + } + + protected function getTemplate() + { + $template = ($this->template) ? $this->template : substr(get_class($this), 0, -6/*strlen('Layout')*/); + return '/layouts/' . $template; + } +} \ No newline at end of file diff --git a/util/AutoloadBuilder.php b/util/AutoloadBuilder.php new file mode 100644 index 0000000..82e0d26 --- /dev/null +++ b/util/AutoloadBuilder.php @@ -0,0 +1,94 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage util + * @since 2010-02-24 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +class AutoloadBuilder +{ + protected $autoload; + protected $dirs; + protected $handler; + protected $regex = '/(class|interface) ([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)/'; + + public function __construct($autoload, $dirs = array()) + { + $this->autoload = $autoload; + $this->dirs = $dirs; + } + + public function build() + { + $this->openAutoload(); + echo "parsing started...\n"; + // for dublicates check + $classes = array(); + foreach ($this->dirs as $dir) { + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($dir), + RecursiveIteratorIterator::LEAVES_ONLY + ); + + foreach ($iterator as $file) { + // skip non php files + $e = explode('.', $file->getFileName()); + if ((end($e) !== 'php') || strstr((string)$file, 'test')) { + continue; + } + + $content = file_get_contents($file->getRealPath()); + $matches = array(); + + $relative_path = substr($file->getRealPath(), strlen(PATH)); + + if (preg_match_all($this->regex, $content, $matches, PREG_SET_ORDER)) { + foreach ($matches as $match) { + echo "found {$match[0]}..."; + if (array_key_exists($match[2], $classes)) { + echo " FAULT\n{$match[0]} also found in ". + $file->getRealPath(). ", skipped.\n"; + continue; + } + echo " OK\n"; + $string = "'{$match[2]}'=>'" . $relative_path . "',\n"; + $this->write($string); + $classes[$match[2]] = $file->getRealPath(); + } + } + } + } + echo "done.\n"; + $this->closeAutoload(); + } + + protected function openAutoload() + { + $this->write("write(");\n")) { + fclose($this->handler); + } + } + + protected function write($string) + { + if (! $this->handler) { + if (! $this->handler = fopen($this->autoload, 'w')) { + echo "{$this->autoload} is not writable\n"; + die; + } + } + return (bool) fwrite($this->handler, $string); + } +} + \ No newline at end of file diff --git a/view/PHPView.php b/view/PHPView.php new file mode 100644 index 0000000..b2ac3a1 --- /dev/null +++ b/view/PHPView.php @@ -0,0 +1,72 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage View + * @since 2010-02-25 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +class PHPView implements iView +{ + + protected $path = ''; + protected $variables = array(); + protected $extension = '.phtml'; + protected $template = ''; + + public function __construct($path) + { + $this->setPath($path); + } + + public function getPath() + { + return $this->path; + } + + public function setPath($path) + { + $this->path = $path; + } + + /** + * @param ViewAction $object + */ + public function assignObject($object) + { + foreach (get_object_vars($object) as $name => $value) { + $this->assign($name, $value); + } + } + + public function assign($name, $value = null) + { + $this->variables[$name] = $value; + } + + public function fetch($template) + { + $this->template = $this->getTemplatePath($template); + unset($template); + extract($this->variables); + ob_start(); + if (!(include($this->template)) == 'OK') { + ob_clean(); + throw new Exception('Template "' . $this->template .'" not found.'); + } + return ob_get_clean(); + } + + public function escape($var) + { + return htmlentities($var, ENT_QUOTES, 'UTF-8'); + } + + protected function getTemplatePath($template) + { + return $this->path . $template . $this->extension; + } +} \ No newline at end of file diff --git a/view/iView.php b/view/iView.php new file mode 100644 index 0000000..38f5467 --- /dev/null +++ b/view/iView.php @@ -0,0 +1,16 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage View + * @since 2010-02-25 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +interface iView +{ + public function assign($name, $value = null); + public function fetch($template); +} \ No newline at end of file