xser php5 framework v0.11 测试版 新增的功能
对于视图缓存控制的处理,轻松设置就能实现功能强大的缓存功能.
颗粒度细分到action,对不同的udi资源[命名空间::控制器/action@模块] 能自定义缓存文件路径信息设置
1. config/html-cache-rules.php
// 缓存策略设置文件 遵循udi_string格式
return array(
//=> welcome.html , welcome.html.asc
'default::application/index@default' => 'default/welcome.html' ,
'default::application/show@default' => 'default/application/show/{name}-{book_id}.html' ,
);
其中 花括号包含的是 可变量,他们由前端$_GET数组中的值来替换.缓存文件对应到 cache/_app/ 这个目录
比如:
index.php?e=show&name=xx&book_id=112 对应于 cache/_app/default/application/show/xx-112.html
2. 控制器设置,要启用缓存功能,不用担心要写很多辅助代码,只需重写以下方法
protected function _before_execute($action_method){
$this->enable_cache = true ; // 将这行加入其中即可
}
例如: application 控制器为默认控制器,
在 config/boot.php中进行了设置: 'default_controller' => 'application',
class application_controller extends xser_controller {
function actionIndex(){
$this->_view['current_uri'] = 'index.php?q=application&e=index' ;
}
function actionShow(){
$this->_view['name'] = $_GET['name'] ;
$this->_view['book_id'] = $_GET['book_id'] ;
$this->_view['current_uri'] = 'index.php?q=application&e=show' ;
}
protected function _before_execute($action_method){
$this->enable_cache = true ;
}
}
default::application/index@default 对应的视图文件如下: view/default/application/index.rhtml
<?php $this->_block('contents'); ?>
<h3><?php echo $current_uri ;?></h3>
<?php $this->_endblock(); ?>
<?php $this->_element('test'); ?>
default::application/show@default 对应的视图文件如下: view/default/application/show.rhtml
<?php $this->_block('contents'); ?>
<h3><?php echo $name . ' -- ' . $book_id;?></h3>
<?php $this->_endblock(); ?>
<?php $this->_element('test'); ?>
default::application@default 对应的元素 test的内容如下: view/default/_elements/test.rhtml
<h2>This is a element file2 !</h2>
index.php?e=show&name=xx&book_id=112 生成的缓存文件如下: cache/_app/default/application/show/xx-112.html
<h3>xx -- 112</h3>
<h2>This is a element file2 !</h2>
index.php 生成的缓存文件如下: cache/_app/default/welcome.html
<h3>index.php?q=application&e=index</h3>
<h2>This is a element file2 !</h2>
3. 缓存更新的策略: 大家应该知道缓存文件的更新很多框架并没有具体实现,像smarty虽然提供了,但是对于局部更新
似乎并不简单,这里色色基本实现了缓存自动更新的一种简单方式...
/**
* 缓存更新的条件:
* 1. 模板文件发生了改变: 里面引用的模板文件发生变化
* [布局模板文件,视图模板文件,元素模板文件]被更新
*
* 2. 内容发生了更新
* [修改对应的数据缓存属性文件的时间戳]
*
* 每个缓存对应着两个文件: 数据缓存文件[xx.html],数据缓存属性文件[xx.html.asc]
*
* 缓存文件名模板: ns/mod/q/e/{name}.html => /admin/sys/user/show/lily.html
*/
class xser_html_cache
缓存具体都由这个类来处理,提供了三个公共方法
public function get_cache_content($udi_string,$cache_tplname_vars)
public function cache_had_expired($udi_string,$cache_tplname_vars)
public function put_cache_content($udi_string,$cache_tplname_vars,$cache_prop,$cache_content)
此类在框架中是一个单态形式的,使用前必须定义缓存策略设置文件config/html-cache-rules.php
这 三个方法 除了 cache_had_expired 这个提供给用户使用外,其它2个均由框架自身使用.
cache_had_expired 方法用于应对第二个缓存更新的条件: 内容发生了更新
比如 咱在后台更新了 index.php?e=show&name=xx&book_id=112 它对应的数据内容,简单调用此方法即可,例如:
在 上文中提到的 application_controller
protected function actionq(){
// 数据更新操作
// 设置缓存过期
xser::singleton('xser_html_cache')
->cache_had_expired('default::application/show@default',array(
'name' => 'xx' ,
'book_id' => '112' ,
));
}
4. 对控制器的缓存功能的扩展,比如定义 控制器中 某些action才享有缓存功能,可以如下设置
protected function _before_execute($action_method){
$enable_cache_actions = array('index','show');
if (in_array($action_method,$enable_cache_actions))
$this->enable_cache = true ;
}
5. 所有这一切都是在xser_controller这个控制器的基类中实现的,代码并未加多少,整个类的代码才136行,包含空行和注释
protected $enable_cache = false ; //新增变量
public function execute($action_name,xser_udi_object $udi){
$action_method = "action{$action_name}";
if ($this->method_exists($action_method)){
$this->udi = $udi ;
// 调用 _before_execute() 方法
$this->_before_execute($action_method);
// 缓存存在,直接取出缓存
if ($this->enable_cache){
$cache_content = $this->get_cache_content();
if ($cache_content != false ){
return $cache_content ;
}
// xser::dump($cache_content,'why?');
unset($cache_content);
xser::replaceIni('__html_cache_tplname_vars#'.$udi->to_string(),$_GET);
}
// 执行 action 方法
$ret = $this->{$action_method}();
// 调用 _after_execute() 方法
$this->_after_execute($ret);
if ($this->is_render()){
// 加载视图组件,进行渲染操作
xser::loadlibrary($this->_view_engine,'xser');
$view_class = "xser_{$this->_view_engine}" ;
$view_render = new $view_class($this->udi);
$view_render->assign($this->_view);
//渲染之前执行
$this->_before_render($view_render);
// 启用缓存,但缓存不存在,在视图组件中生成缓存
return $view_render->execute($this->enable_cache);
}
}else {
$notice = sprintf('Action "%s" not defined in "%s".',
$action_name,$udi['mapping_info']['controller_file'].'#'.get_class($this));
echo $notice ;
Xser::log_provider()->exception($notice);
// throw new Exception($notice);
}
return null;
}
// 缓存扩展
protected function get_cache_content(){
xser::loadlibrary('html_cache','xser');
return xser::singleton('xser_html_cache')->get_cache_content(
$this->udi->to_string(),$_GET ) ;
}
6. 视图引擎组件也相应的做了些改变 class xser_view
// 新增变量
protected $_enable_cache = false ; //启用缓存
protected $udi_string = null ;
protected function reinit(xser_udi_object $udi){
$this->udi_mapping_info = $udi->mapping_info() ;
$this->udi_string = $udi->to_string();
$this->_vars = array(
'base_uri' => xser::ini('base_uri'),
);
}
public function execute($enable_cache=false){
$this->_enable_cache = $enable_cache ;
$this->display();
}
function fetch()
{
$this->_before_render();
$filename = Xser::ini('application_dir') ."/{$this->udi_mapping_info['view_action_file']}";
if (file_exists($filename))
{
$view_parse = new xser_view_parse($this->_vars);
$output = $view_parse->reset_ref_tpls()->parse($this->udi_mapping_info['view_action_file']);
if ($this->_enable_cache){ // 新增代码
//引用的模板列表属性设置
$ref_tpls_prop = $view_parse->get_ref_tpls();
if (!empty($ref_tpls_prop)){
if (!class_exists('xser_html_cache'))
xser::loadlibrary('html_cache','xser');
$cache_tplname_vars = xser::ini("__html_cache_tplname_vars#{$this->udi_string}",$_GET);
xser::cleanIni("__html_cache_tplname_vars#{$this->udi_string}");
xser::singleton('xser_html_cache')
->put_cache_content($this->udi_string,$cache_tplname_vars,$ref_tpls_prop,$output);
}
}
}
else
{
$notice = "view file not exist: [{$this->udi_mapping_info['view_action_file']}]" ;
echo $notice ;
Xser::log_provider()->exception($notice);
return ;
// throw new Exception($notice);
$output = '';
}
$this->_after_render($output);
return $output;
}
7. class xser_view_parse 的变化
protected $_ref_tpls = array() ;
public function get_ref_tpls(){ // 获取引用的模板文件
return $this->_ref_tpls ;
}
/**
* @return xser_view_parse
*/
public function reset_ref_tpls(){
$this->_ref_tpls = array();
return $this ;
}
/**
* 载入视图文件
*/
protected function _include($___tpl, array $___vars = null)
{
$file = Xser::ini('application_dir') . "/{$___tpl}" ;
if (!file_exists($file)){
$notice = "view file1 not exist: [{$___tpl}]" ;
Xser::log_provider()->exception($notice);
echo $notice ; return ;
// throw new Exception($notice);
}
$this->_ref_tpls[$___tpl] = filemtime($file) ;
extract($this->_vars);
if (is_array($___vars)) extract($___vars);
include $file;
}