From 8fc917dca278b00afdfcdbf22342893c29a097f2 Mon Sep 17 00:00:00 2001 From: pzinovkin Date: Sat, 13 Mar 2010 23:33:46 +0000 Subject: [PATCH] Memcache, refactoring, View helpers, #16 git-svn-id: svn+ssh://code.netmonsters.ru/svn/majestic/branches/evo@124 4cb57b5f-5bbd-dd11-951b-001d605cbbc5 --- app/ErrorAction.php | 39 ++++++++++-- app/FrontController.php | 10 ++- app/PagerAction.php | 66 ++++++++++++++++++++ cache/CacheKey.php | 72 ++++++++++++++++++++++ cache/CacheKeySet.php | 48 +++++++++++++++ cache/MemcacheCache.php | 54 ++++++++++++++--- cache/iCacheable.php | 24 ++++++++ classes/Pager.class.php | 78 ------------------------ exception/ErrorHandler.php | 4 ++ model/DbDriver.php | 3 +- model/DbStatement.php | 50 +++++++-------- model/Model.php | 135 +++++++++++++++++++++++++++++++++-------- model/MySQLiDriver.php | 23 ++++++- model/MySQLiStatement.php | 16 ++++- util/Profiler.php | 82 +++++++++++++++++++++++++ util/QueryProfiler.php | 39 ++++++++++++ view/PHPView.php | 29 +++++++++ view/helpers/ViewHelper.php | 24 ++++++++ view/helpers/ViewHelperGet.php | 57 +++++++++++++++++ 19 files changed, 706 insertions(+), 147 deletions(-) create mode 100644 app/PagerAction.php create mode 100644 cache/CacheKey.php create mode 100644 cache/CacheKeySet.php create mode 100644 cache/iCacheable.php delete mode 100644 classes/Pager.class.php create mode 100644 util/Profiler.php create mode 100644 util/QueryProfiler.php create mode 100644 view/helpers/ViewHelper.php create mode 100644 view/helpers/ViewHelperGet.php diff --git a/app/ErrorAction.php b/app/ErrorAction.php index d6370b0..d71d8f9 100644 --- a/app/ErrorAction.php +++ b/app/ErrorAction.php @@ -13,7 +13,7 @@ class ErrorAction extends ViewAction { /** - * @var Exception + * @var ErrorException */ protected $exception; @@ -36,12 +36,12 @@ class ErrorAction extends ViewAction return '/static/' . $this->template; } - protected function sendHttpCode($code) + protected function sendHttpCode() { if (headers_sent()) { return; } - switch ($code) { + switch ($this->template) { case 404: header('HTTP/1.0 404 Not Found'); break; @@ -50,9 +50,40 @@ class ErrorAction extends ViewAction } } + protected function logError() + { + if ($this->template = 500) { + + $error = 0; + $ex = $this->exception; + if ($ex instanceof ErrorException) { + $error = $ex->getSeverity(); + } + + switch ($error) { + case E_NOTICE: + $error = 'Notice'; + break; + case E_WARNING: + $error = 'Warning'; + break; + case E_ERROR: + $error = 'Fatal Error'; + break; + default: + $error = 'Unknown Error'; + break; + } + $message = 'PHP ' . $error . ': ' . $ex->getMessage() . ' in ' . $ex->getFile() + . ' on line ' . $ex->getLine(); + error_log($message); + } + } + public function fetch() { - $this->sendHTTPCode($this->template); + $this->logError(); + $this->sendHTTPCode(); return $this->view->fetch($this->getTemplate()); } } \ No newline at end of file diff --git a/app/FrontController.php b/app/FrontController.php index 2ea3154..1cc33e7 100644 --- a/app/FrontController.php +++ b/app/FrontController.php @@ -32,6 +32,9 @@ class FrontController private function __construct() { ErrorHandler::init(); + if (DEBUG == true) { + Profiler::getInstance()->start(); + } $this->router = new Router(); } @@ -96,7 +99,6 @@ class FrontController public function execute() { try { - $request = Env::getRequestUri(); $route = $this->getRouter()->route($request); if (!$route) { @@ -107,14 +109,16 @@ class FrontController if (!class_exists($action_class)) { throw new GeneralException('Action class "' . $action_class . '" not found.'); } + $action = new $action_class(); $layout_class = $route->getLayout(); if (!class_exists($layout_class)) { throw new GeneralException('Layout class "' . $layout_class . '" not found.'); } - $layout = new $layout_class(); - return $layout->fetch($action); + $layout = new $layout_class(); + $html = $layout->fetch($action); + return (!DEBUG) ? $html : Profiler::getInstance()->end($html); } catch(Exception $e) { if (DEBUG == true) { return ErrorHandler::showDebug($e); diff --git a/app/PagerAction.php b/app/PagerAction.php new file mode 100644 index 0000000..44bf076 --- /dev/null +++ b/app/PagerAction.php @@ -0,0 +1,66 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage app + * @since 2010-03-07 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +class PagerAction extends ViewAction +{ + public $page; + public $last_page; + + //protected $num_rows; + + protected $offset = 0; + protected $count = 0; + protected $limit; + + public function __construct($count, $limit = 20) + { + $this->count = $count; + $this->limit = $limit; + parent::__construct(); + } + + protected function execute() + { + $page = (int) Env::Get('p'); + $this->last_page = ceil($this->count/$this->limit); + $this->page = ($page <= $this->last_page && $page > 0) ? $page : 1; + $this->offset = $this->limit * ($this->page - 1); + //$this->num_rows = ($this->limit + $this->offset) <= $this->count ? ($this->limit + $this->offset) : $this->count; + } + + public function getOffset() + { + return $this->offset; + } + + public function getLimit() + { + return $this->limit; + } + + protected function getTemplate() + { + $template = ($this->template) ? $this->template : substr(get_class($this), 0, -6/*strlen('Action')*/); + return '/actions/' . $template; + } + + +/* public function setNumRows($num_rows) + { + $this->num_rows = $num_rows; + } +*/ + /*function prepare() + { + $this->templater->assign('page', $this->page); + $this->templater->assign('page_max', $this->max_page_num); + }*/ +} \ No newline at end of file diff --git a/cache/CacheKey.php b/cache/CacheKey.php new file mode 100644 index 0000000..9271208 --- /dev/null +++ b/cache/CacheKey.php @@ -0,0 +1,72 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage Cache + * @since 2010-03-10 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +class CacheKey +{ + + protected $key; + protected $params = ''; + protected $expire = 0; + + /** + * @param string $key + * @param mixed $params + * @param iCacheable $cacheable + * @return CacheKey + */ + public function __construct($key, $params = array(), $cacheable) + { + $this->key = $key; + if (!$cacheable instanceof iCacheable) { + throw new GeneralException('CacheKey depends on iCacheable instance'); + } + $this->cache = $cacheable->getCache(); + $this->expire = $cacheable->getKeyExpire($this->key); + $this->params = (is_array($params)) ? implode('', $params) : $params; + } + + protected function getCacheKey() + { + $params = ($this->params) ? ('_' . $this->params) : ''; + return $this->key . $params; + } + + protected function getExpire() + { + return $this->expire; + } + + /** + * @param int $expire + */ + public function setExpire($expire) + { + $this->expire = $expire; + } + + public function get() + { + return $this->cache->get($this->getCacheKey()); + } + + /** + * @param mixed $value + */ + public function set($value) + { + return $this->cache->set($this->getCacheKey(), $value, $this->expire); + } + + public function del() + { + return $this->cache->del($this->getCacheKey()); + } +} \ No newline at end of file diff --git a/cache/CacheKeySet.php b/cache/CacheKeySet.php new file mode 100644 index 0000000..c470f78 --- /dev/null +++ b/cache/CacheKeySet.php @@ -0,0 +1,48 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage Cache + * @since 2010-03-10 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +class CacheKeySet extends CacheKey +{ + public function get() + { + $set = $this->cache->get($this->key); + $item_key = $this->getCacheKey(); + + if (!is_array($set) || !array_key_exists($item_key, $set)) { + return false; + } + return $this->cache->get($item_key); + } + + /** + * @param mixed $value + */ + public function set($value) + { + $set = $this->cache->get($this->key); + if (!is_array($set)) { + $set = array(); + } + + $item_key = $this->getCacheKey(); + if (!$this->cache->set($item_key, $value, $this->expire)) { + return false; + } + + $set[$item_key] = $this->cache->getExpire($this->expire); + return $this->cache->set($this->key, $set, $this->expire); + } + + public function del() + { + return $this->cache->del($this->key); + } +} \ No newline at end of file diff --git a/cache/MemcacheCache.php b/cache/MemcacheCache.php index 2dda1a1..8daabf2 100644 --- a/cache/MemcacheCache.php +++ b/cache/MemcacheCache.php @@ -17,10 +17,26 @@ class MemcacheCache extends Cache */ protected $connection = null; + protected $key_salt = null; + + /** + * One hour to live default + * + * @var int + */ + protected $expire = 3600; + + protected $keys = array(); + public function __construct($config) { $this->connection = new Memcache(); + if (isset($config['key_salt'])) { + $this->key_salt = $config['key_salt']; + unset($config['key_salt']); + } + $required = array('hostname', 'port'); foreach ($config as $c) { foreach ($required as $option) { @@ -42,7 +58,7 @@ class MemcacheCache extends Cache */ public function add($key, $value, $expire = 0) { - return $this->connection->add($key, $value, null, $expire); + return $this->connection->add($this->getKey($key), $value, null, $this->getExpire($expire)); } /** @@ -54,7 +70,7 @@ class MemcacheCache extends Cache */ public function decrement($key, $decrement = 1) { - return $this->connection->decrement($key, $decrement); + return $this->connection->decrement($this->getKey($key), $decrement); } /** @@ -66,7 +82,7 @@ class MemcacheCache extends Cache */ public function del($key) { - return $this->connection->delete($key); + return $this->connection->delete($this->getKey($key)); } /** @@ -82,12 +98,12 @@ class MemcacheCache extends Cache /** * Retrieve item from the cache * - * @param mixed $key + * @param string $key * @return mixed */ public function get($key) { - return $this->connection->get($key); + return $this->connection->get($this->getKey($key)); } /** @@ -99,7 +115,7 @@ class MemcacheCache extends Cache */ public function increment($key, $increment = 1) { - return $this->connection->increment($key, $increment); + return $this->connection->increment($this->getKey($key), $increment); } /** @@ -112,7 +128,7 @@ class MemcacheCache extends Cache */ public function replace($key, $value, $expire = 0) { - return $this->connection->replace($key, $value, null, $expire); + return $this->connection->replace($this->getKey($key), $value, null, $this->getExpire($expire)); } /** @@ -125,6 +141,28 @@ class MemcacheCache extends Cache */ public function set($key, $value, $expire = 0) { - return $this->connection->set($key, $value, null, $expire); + return $this->connection->set($this->getKey($key), $value, null, $this->getExpire($expire)); + } + + /** + * @param string $key + * @return string + */ + protected function getKey($key) + { + if (!isset($this->keys[$key])) { + $this->keys[$key] = md5($this->key_salt . $key); + } + return $this->keys[$key]; + } + + public function getExpire($expire) + { + return ($expire > 0) ? $expire : $this->expire; + } + + public function cleanKeys() + { + $this->keys = array(); } } \ No newline at end of file diff --git a/cache/iCacheable.php b/cache/iCacheable.php new file mode 100644 index 0000000..4f6b48b --- /dev/null +++ b/cache/iCacheable.php @@ -0,0 +1,24 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage cache + * @since 2010-03-12 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +interface iCacheable +{ + /** + * @return Cache + */ + public function getCache(); + + /** + * @param string $key + * @return Expiration time in seconds + */ + public function getKeyExpire($key); +} \ No newline at end of file diff --git a/classes/Pager.class.php b/classes/Pager.class.php deleted file mode 100644 index d6f227b..0000000 --- a/classes/Pager.class.php +++ /dev/null @@ -1,78 +0,0 @@ - - * @link - * @package Nakon - * @subpackage face - * @since 04.02.2008 - * @version SVN$ - * @filesource $URL$ - */ - - -class Pager extends Action -{ - public $template_dir = '.'; - - protected $current_page = 1; - protected $max_page_num; - protected $num_rows; - protected $limit; - protected $start_offset = 0; - protected $count = 0; - - public function __construct($count, $current_page = 1, $records_limit = 20) - { - parent::__construct(); - - $this->count = $count; - $this->limit = $records_limit; - - $this->max_page_num = ceil($this->count/$this->limit); - $this->current_page = ((int)$current_page <= $this->max_page_num && (int)$current_page > 0) ? (int)$current_page : 1; - - $this->start_offset = $this->limit * ($this->current_page - 1); - $this->num_rows = ($this->limit + $this->start_offset) <= $this->count ? ($this->limit + $this->start_offset) : $this->count; - } - - /** - * Возвращает текущую страницу - * - * @return int - */ - public function getPage() - { - return $this->current_page; - } - - public function startOffset() - { - return $this->start_offset; - } - - public function limit() - { - return $this->limit; - } - - public function setNumRows($num_rows) - { - $this->num_rows = $num_rows; - } - - function init() - { - $this->template = "Pager"; - } - - function prepare() - { - $this->templater->assign('page', $this->current_page); - $this->templater->assign('page_max', $this->max_page_num); - $this->templater->assign('limit', $this->limit); - $this->templater->assign('count', $this->count); - } -} -?> \ No newline at end of file diff --git a/exception/ErrorHandler.php b/exception/ErrorHandler.php index 1bd7fc7..69dd8ad 100644 --- a/exception/ErrorHandler.php +++ b/exception/ErrorHandler.php @@ -51,6 +51,9 @@ class ErrorHandler } $text = ''; foreach ($array as $key => $value) { + if (is_array($value)) { + $value = print_r($value, true); + } $value = ($value) ? htmlentities($value, ENT_QUOTES, 'UTF-8') : ' '; $text .= ''; } @@ -68,6 +71,7 @@ class ErrorHandler */ static public function showDebug($exception) { + ob_clean(); $class = get_class($exception); $method = Env::Server('REQUEST_METHOD', ''); diff --git a/model/DbDriver.php b/model/DbDriver.php index 850537c..5b878e6 100644 --- a/model/DbDriver.php +++ b/model/DbDriver.php @@ -91,9 +91,10 @@ abstract class DbDriver /** * @param string $table * @param mixed $bind + * @param mixed $on_duplicate * @return int Affected rows count */ - public function insert($table, $bind) + public function insert($table, $bind, $on_duplicate = array()) { $columns = array(); foreach ($bind as $col => $val) { diff --git a/model/DbStatement.php b/model/DbStatement.php index 72621e0..30e1142 100644 --- a/model/DbStatement.php +++ b/model/DbStatement.php @@ -34,31 +34,6 @@ abstract class DbStatement $this->sql = $sql; } - /** - * @param mixed $style - * @return array - */ - public function fetchAll($style = Db::FETCH_OBJ) - { - $data = array(); - while ($row = $this->fetch($style)) { - $data[] = $row; - } - return $data; - } - - /** - * @param string $field - */ - public function fetchField($field) - { - $row = $this->fetch(Db::FETCH_ASSOC); - if (isset($row[$field])) { - return $row[$field]; - } - return false; - } - public function bindParam($param, &$value) { if ($this->map === null) { @@ -138,6 +113,31 @@ abstract class DbStatement { $this->close(); } + + /** + * @param mixed $style + * @return array + */ + public function fetchAll($style = Db::FETCH_OBJ) + { + $data = array(); + while ($row = $this->fetch($style)) { + $data[] = $row; + } + return $data; + } + + /** + * @param string $field + */ + public function fetchField($field) + { + $row = $this->fetch(Db::FETCH_ASSOC); + if (isset($row[$field])) { + return $row[$field]; + } + return false; + } /* Abstract methods */ diff --git a/model/Model.php b/model/Model.php index 51fdb18..7be95a8 100644 --- a/model/Model.php +++ b/model/Model.php @@ -12,7 +12,7 @@ * @filesource $URL$ */ -abstract class Model +abstract class Model implements iCacheable { /** @@ -28,6 +28,20 @@ abstract class Model * @var Cache */ protected $cache; + + /** + * Custom expiration time for keys + * + * @var mixed + */ + protected $cache_keys = array(); + + /** + * Caches to clean. + * + * @var mixed + */ + protected $caches_clean = array(); protected $table; @@ -35,7 +49,6 @@ abstract class Model protected $key = 'id'; - public function __construct() { $this->db = Db::connect($this->connection); @@ -73,37 +86,21 @@ abstract class Model */ public function get($id) { - $sql = 'SELECT * FROM ' . $this->table() . ' WHERE ' . $this->identify($this->key) . '=' . (int) $id; - return $this->db->query($sql)->fetch(); - } - - /** - * @param array $data - * @return int Affect row or id of inserted field. - */ - public function save($data) - { - $key = isset($data[$this->key]) ? $data[$this->key] : false; - $result = false; - if ($key) { - unset($data[$this->key]); - $result = $this->update($data, $this->identify($this->key) . '=' . (int) $id); - } else { - $result = $this->insert($data); - } - return $result; + $sql = 'SELECT * FROM ' . $this->table() . ' WHERE ' . $this->identify($this->key) . '=?'; + return $this->fetch($sql, $id); } /** * @param array $data + * @param array $on_duplicate * @return int Id of inserted row */ - public function insert($data) + public function insert($data, $on_duplicate = array()) { - if (!$this->db->insert($this->table(false), $data)) { + if (!$res = $this->db->insert($this->table(false), $data, $on_duplicate)) { return false; } - return $this->getInsertId(); + return ($on_duplicate) ? $res : $this->getInsertId(); } /** @@ -146,11 +143,99 @@ abstract class Model /** * @return Cache */ - protected function cache() + public function getCache() { if (!$this->cache) { $this->cache = Cacher::get(Config::get(__CLASS__, 'MemcacheCache')); } return $this->cache; } + + /** + * @param string $key + * @return int + */ + public function getKeyExpire($key) + { + return (isset($this->cache_keys[$key])) ? ($this->cache_keys[$key] * 60) : 0; + } + + /** + * @param string $name + * @param array $params + * @return CacheKey + */ + protected function cacheKey($name, $params = array()) + { + if (substr(strtolower($name), -3, 3) == 'set') { + return new CacheKeySet($name, $params, $this); + } + return new CacheKey($name, $params, $this); + } + + /** + * @param CacheKey | CacheKeySet $cache + */ + protected function addCleanCache($cache) + { + $this->caches_clean[] = $cache; + } + + protected function cleanCaches() + { + // cleaning caches + foreach ($this->caches_clean as $cache) { + $cache->del(); + } + $this->caches_clean = array(); + } + + /** + * @param string $sql + * @param array $params + * @param string $field + * @param CacheKey | CacheKeySet $cache_key + */ + protected function fetchField($sql, $params = array(), $field, $cache_key = null) + { + if (!$cache_key || !$result = $cache_key->get()) { + $result = $this->db->query($sql, $params)->fetchField($field); + if ($cache_key) { + $cache_key->set($result); + } + } + return $result; + } + + /** + * @param string $sql + * @param array $params + * @param CacheKey | CacheKeySet $cache_key + */ + protected function fetch($sql, $params = array(), $cache_key = null) + { + if (!$cache_key || !$result = $cache_key->get()) { + $result = $this->db->query($sql, $params)->fetch(); + if ($cache_key) { + $cache_key->set($result); + } + } + return $result; + } + + /** + * @param string $sql + * @param array $params + * @param CacheKey | CacheKeySet $cache_key + */ + protected function fetchAll($sql, $params = array(), $cache_key = null) + { + if (!$cache_key || !$result = $cache_key->get()) { + $result = $this->db->query($sql, $params)->fetchAll(); + if ($cache_key) { + $cache_key->set($result); + } + } + return $result; + } } \ No newline at end of file diff --git a/model/MySQLiDriver.php b/model/MySQLiDriver.php index 413b29e..565c588 100644 --- a/model/MySQLiDriver.php +++ b/model/MySQLiDriver.php @@ -15,6 +15,28 @@ class MySQLiDriver extends DbDriver { + public function insert($table, $bind, $on_duplicate = array()) + { + $columns = array(); + foreach ($bind as $col => $val) { + $columns[] = $this->quoteIdentifier($col); + } + $values = array_values($bind); + + if ($on_duplicate) { + $update = array(); + foreach ($on_duplicate as $col => $val) { + $update[] = $this->quoteIdentifier($col) . '=' . $this->quote($val); + } + $on_duplicate = ' ON DUPLICATE KEY UPDATE ' . implode(', ', $update); + } + + $sql = 'INSERT INTO ' . $this->quoteIdentifier($table) + . ' (' . implode(', ', $columns) . ') VALUES (' . $this->quote($values) . ')' + . (($on_duplicate) ? $on_duplicate : ''); + return $this->query($sql)->affectedRows(); + } + /** * @param mixed $sql * @return DbStatement @@ -72,7 +94,6 @@ class MySQLiDriver extends DbDriver } if (is_bool($value)) { - var_dump($value); return (int) $value; } diff --git a/model/MySQLiStatement.php b/model/MySQLiStatement.php index 2fc651d..183d3a4 100644 --- a/model/MySQLiStatement.php +++ b/model/MySQLiStatement.php @@ -16,9 +16,15 @@ class MySQLiStatement extends DbStatement { + /** + * Fetches single row + * + * @param mixed $style + * @return mixed + */ public function fetch($style = Db::FETCH_OBJ) { - if (! $this->result) { + if (!$this->result) { return false; } @@ -77,7 +83,13 @@ class MySQLiStatement extends DbStatement * @var MySQLi */ $mysqli = $this->driver->getConnection(); - $result = $mysqli->query($sql); + if (DEBUG) { + $profiler = Profiler::getInstance()->profilerQuery($sql); + $result = $mysqli->query($sql); + $profiler->end(); + } else { + $result = $mysqli->query($sql); + } if ($result === false) { throw new Exception($mysqli->error, $mysqli->errno); } diff --git a/util/Profiler.php b/util/Profiler.php new file mode 100644 index 0000000..bd1a6ad --- /dev/null +++ b/util/Profiler.php @@ -0,0 +1,82 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage util + * @since 2010-03-09 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +class Profiler +{ + + protected $start = null; + protected $end = null; + + protected $queries = array(); + + static protected $instance = null; + + private function __construct() + { + if (DEBUG == false) { + throw new GeneralException('Need to turn on DEBUG before use.'); + } + } + + /** + * Refuse cloning + */ + private function __clone(){} + + /** + * @return Profiler + */ + static public function getInstance() + { + if (!isset(self::$instance)) { + self::$instance = new self(); + } + return self::$instance; + } + + /** + * @param string $query + * @return QueryProfiler + */ + public function profilerQuery($query) + { + $profiler = new QueryProfiler($query); + $this->queries[] = $profiler; + return $profiler; + } + + public function start() + { + $this->start = microtime(true); + } + + public function end($html) + { + $this->end = microtime(true); + if (stripos($html, '') == False) { + return $html; + } + return str_ireplace('', $this->getOutput() . '', $html); + } + + protected function getOutput() + { + $html = '
' + . 'Elapsed time: ' . round(($this->end- $this->start) * 1000) . 'ms.
' + . 'Queries: ' . count($this->queries) . '
'; + + foreach ($this->queries as $query) { + $html .= '[' . round($query->getElapsed() * 1000) . 'ms] ' . $query->getQuery() . '
'; + } + $html .= '
'; + return $html; + } +} \ No newline at end of file diff --git a/util/QueryProfiler.php b/util/QueryProfiler.php new file mode 100644 index 0000000..d697d73 --- /dev/null +++ b/util/QueryProfiler.php @@ -0,0 +1,39 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage util + * @since 2010-03-09 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +class QueryProfiler +{ + + protected $query = ''; + protected $start = null; + protected $end = null; + + public function __construct($query) + { + $this->query = $query; + $this->start = microtime(true); + } + + public function end() + { + $this->end = microtime(true); + } + + public function getQuery() + { + return $this->query; + } + + public function getElapsed() + { + return $this->end - $this->start; + } +} \ No newline at end of file diff --git a/view/PHPView.php b/view/PHPView.php index dc77d9d..815c5ff 100644 --- a/view/PHPView.php +++ b/view/PHPView.php @@ -9,11 +9,15 @@ * @filesource $URL$ */ +/** + * @method ViewHelperGet get() + */ class PHPView implements iView { protected $path = ''; protected $variables = array(); + protected $helpers = array(); protected $extension = '.phtml'; protected $template = ''; @@ -69,6 +73,31 @@ class PHPView implements iView return htmlentities($var, ENT_QUOTES, 'UTF-8'); } + /** + * Helpers call + * + * @param mixed $name + * @param mixed $args + * @return ViewHelper + */ + public function __call($name, $args) + { + $helper = $this->getHelper($name); + return call_user_func_array(array($helper, $name), $args); + } + + protected function getHelper($name) + { + if (!isset($this->helpers[$name])) { + $class = 'ViewHelper' . ucfirst($name); + if (!class_exists($class)) { + throw new GeneralException('View helper "' . $class . '" not found.'); + } + $this->helpers[$name] = new $class($this); + } + return $this->helpers[$name]; + } + protected function getTemplatePath($template) { return $this->path . $template . $this->extension; diff --git a/view/helpers/ViewHelper.php b/view/helpers/ViewHelper.php new file mode 100644 index 0000000..177666d --- /dev/null +++ b/view/helpers/ViewHelper.php @@ -0,0 +1,24 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage View + * @since 2010-03-09 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +abstract class ViewHelper +{ + + /** + * @var PHPView + */ + protected $view = null; + + public function __construct($view) + { + $this->view = $view; + } +} \ No newline at end of file diff --git a/view/helpers/ViewHelperGet.php b/view/helpers/ViewHelperGet.php new file mode 100644 index 0000000..ece3e1d --- /dev/null +++ b/view/helpers/ViewHelperGet.php @@ -0,0 +1,57 @@ + + * @link http://netmonsters.ru + * @package Majestic + * @subpackage View + * @since 2010-03-09 + * @version SVN: $Id$ + * @filesource $URL$ + */ + +class ViewHelperGet extends ViewHelper +{ + + protected $get; + + public function get($replace) + { + $get = $this->getSanitizedRequest(); + if (!is_array($replace)) { + $replace = array($replace); + } + foreach ($replace as $key => $value) { + if (is_int($key)) { + unset($get[$value]); + } else { + $get[$key] = $this->impl($key, $value); + } + } + return '?' . $this->view->escape(implode('&', $get)); + } + + protected function getSanitizedRequest() + { + if ($this->get === null) { + $get = Env::Get(); + foreach ($get as $key => $value) { + $this->get[$key] = $this->impl($key, $value); + } + } + return $this->get; + } + + protected function impl($name, $value) + { + if (is_array($value)){ + $result = array(); + foreach ($value as $key => $val) { + $result[] = $name . '[' . $key . ']=' . $val; + } + $result = implode('&', $result); + } else { + $result = $name . '=' . $value; + } + return $result; + } +} \ No newline at end of file
VariableValue
' . $key . '
' . $value . '