超级无敌牛X之CI钩子
本帖最后由 ares333 于 2010-3-12 11:08 编辑最近研究CI的Session无意中发现CI的钩子非常强劲和灵活。
之前学习Zend Framework感觉嵌入视图非常不错,今天就用CI的钩子实现一个
准备工作,个人建议最好看一下CI的大体运行流程,打开config.php修改$config['log_threshold'] = 2;这样在system/logs生成记录debug信息的日志文件,打开一个页面,日志文件如下(如果没有生成日志文件,尝试修改$config['base_url']为正确的值):
DEBUG - 2010-03-12 02:10:23 --> Config Class Initialized
DEBUG - 2010-03-12 02:10:23 --> Hooks Class Initialized
DEBUG - 2010-03-12 02:10:23 --> URI Class Initialized
DEBUG - 2010-03-12 02:10:23 --> No URI present. Default controller set.
DEBUG - 2010-03-12 02:10:23 --> Router Class Initialized
DEBUG - 2010-03-12 02:10:23 --> Output Class Initialized
DEBUG - 2010-03-12 02:10:23 --> Input Class Initialized
DEBUG - 2010-03-12 02:10:23 --> Global POST and COOKIE data sanitized
DEBUG - 2010-03-12 02:10:23 --> Language Class Initialized
DEBUG - 2010-03-12 02:10:23 --> Loader Class Initialized
DEBUG - 2010-03-12 02:10:23 --> Controller Class Initialized
DEBUG - 2010-03-12 02:10:23 --> Session Class Initialized
DEBUG - 2010-03-12 02:10:23 --> Helper loaded: string_helper
DEBUG - 2010-03-12 02:10:23 --> Session routines successfully run
DEBUG - 2010-03-12 02:10:23 --> File loaded: E:\websites\ci/system/application/views/welcome_message.php
DEBUG - 2010-03-12 02:10:23 --> Final output sent to browser
DEBUG - 2010-03-12 02:10:23 --> Total execution time: 0.0534
正式开始
1.启用钩子
$config['enable_hooks'] = TRUE;
启用钩子之后还必须注意,本例使用了模板解析类(非常好用的类),在autoload.php中加载了
2.修改application/config/hooks.php,这里定义钩子
$hook['post_controller'][] = array(
'class' => 'Layout',
'function' => 'render',
'filename' => 'Layout.php',
'filepath' => 'hooks',
'params' => array()
);
什么意思手册上说的非常清楚,不再解释
3.控制器
在具体钩子代码之前非常有必要说明一下我的控制器
我扩展了原有控制器以实现更多的功能
libraries/X_Controller.php
class X_Controller extends Controller{
//默认布局文件
var $layout = 'layouts/layout.php';
//默认视图
var $views=array(
'head'=>'common/head',
'header'=>'common/header',
'content'=>'',
'footer'=>'common/footer'
);
//与默认视图匹配的视图数据
var $data=array(
'head'=>array(),
'header'=>array(),
'content'=>array(),
'footer'=>array()
);
public function X_Controller(){
parent::Controller();
}
}
/controllers/start.php
<?php
/**
* 首页控制器
* @author ares
*
*/
class Start extends X_Controller {
function Start()
{
parent::X_Controller();
}
function index()
{
$this->data['title']='这里是标题';
$this->data['test']='测试一下';
}
}
这里请注意一下,借鉴Zend Framework的layout模式,与start控制器index方法对应的视图是/views/start/index.php
/views/start/index.php代码如下
{test}
默认layout /views/layouts/layout.php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
{head}
<link rel=stylesheet href="dcss/common.css" type="text/css">
<title>{title}</title>
</head>
<body>
{header}
<div id="content">
{content}<br />
</div>
{footer}
</body>
</html>
4.具体的钩子
/hooks/Layout.php
<?php
class Layout{
var $CI;
var $layout = 'layouts/layout';
var $views = array();
var $data = array();
function Layout(){
$this->CI=&get_instance();
}
function render(){
//从控制器中读取layout
$this->layout=$this->CI->layout;
//从控制器读取视图文件
$this->views=$this->CI->views;
//覆盖部分默认视图
$this->views['content']=$this->CI->router->directory.$this->CI->router->class.'/'.$this->CI->router->method;
//为每个视图文件准备数据
$data=$this->CI->data;
//覆盖部分默认数据
$data['content']=$this->CI->data;
//从控制器提取layout中用到的直接数据
$this->data['title']=$this->CI->data['title'];
//为layout准备数据
foreach($this->views as $key=>$value){
$this->data[$key]=$this->CI->parser->parse($this->views[$key],$data[$key],TRUE);
}
$this->append_title();
$this->CI->parser->parse($this->layout,$this->data);
}
//自动为每个页面的title添加一个后缀,比如 -CodeIgniter 中国开发者社区
private function append_title(){
$this->data['title'].=$this->CI->config->item('title_suffix');
}
}
原理比较简单,控制器中不用$this->load->view()或$this->parser->parse(),这些会自动完成,控制器中只需要提供数据($this->data)。
这种结构非常有用。
比如有这样一中情况,每个页面除了header,content,footer,还有些页面有左部导航条left
这时候只需要在layout.php中添加上left导航条就OK
其实既然已经有了layout那么这些header和footer什么的就不用再单独定义,新写的东西肯定有问题,但是原理绝对没问题,所以明白原理是最重要。
代码有些多,但是非常有必要仔细看一下
这些代码都是本主题用到的代码,其他不相关的代码都清除了
这只是基本实现,欢迎提出建议和意见
强烈要求加声望{:2_40:} 经过进一步修改基本可以应用到实际
/libraries/X_Controller.php
<?php
class X_Controller extends Controller{
//默认布局文件
var $layout = 'layouts/layout.php';
var $data=array();
public function X_Controller(){
parent::Controller();
$this->validate();
$this->load->scaffolding('');
}
//登录验证
protected function validate(){
//如果要显示登录窗口就不进行有效性验证
if(strpos(uri_string(),'ares/login')!=FALSE){
//验证系统管理员
}elseif(strpos(uri_string(),'ares') != FALSE){
if($this->session->userdata ( 'admin_logged' ) == 'yes'){
}else{
redirect('ares/login');
}
}
}
}
controllers/start.php
/**
* 首页控制器
* @author ares
*
*/
class Start extends X_Controller {
function Start()
{
parent::X_Controller();
}
function index()
{
$this->data['title']='这里是标题';
$this->data['test']='测试一下';
}
}
config/hooks.php
$hook['post_controller'][] = array(
'class' => 'Layout',
'function' => 'render',
'filename' => 'Layout.php',
'filepath' => 'hooks',
'params' => array()
);
hooks/Layout.php
<?php
class Layout{
var $CI;
var $layout;
var $content;
var $data = array();
function Layout(){
$this->CI=&get_instance();
//从控制器中读取layout
$this->layout=$this->CI->layout;
//从控制器读取数据
$this->data=$this->CI->data;
//确定目标视图
$this->content=$this->CI->router->directory.$this->CI->router->class.'/'.$this->CI->router->method;
}
function render(){
//初始化目标视图
$this->data['content']=$this->CI->parser->parse($this->content,$this->data,TRUE);
$this->append_title();
$this->CI->parser->parse($this->layout,$this->data);
}
private function append_title(){
$this->data['title'].=$this->CI->config->item('title_suffix');
}
}
views/layouts/layout.php
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<base href="<?php echo $this->config->item('base_url');?>" />
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $this->config->item('charset');?>" />
<meta name="author" content="" />
<meta name="keywords" content="" />
<meta name="description" content="" />
<link rel=stylesheet href="dcss/common.css" type="text/css">
<title>{title}</title>
</head>
<body>
<div id="header">
<table width="100%">
<tr>
<td width="74%"><h1>codehere.net</h1></td>
<td width="26%">登录 注册</td>
</tr>
</table>
<ul id="nav">
<li><a href="#">首页</a></li>
</ul>
<div class="clear_left"></div>
</div>
<div id="content">
{content}<br />
</div>
<div id="footer">
#footer
</div>
</body>
</html>
视图 views/start/index.php
{test}
很好很强大 不错,顶你一个 用钩子实现的 layout~~~~ 请问楼主,写日志钩子怎么写?
也就是说:每做一个添加或修改或删除操作,都要写一条日志到数据库,当然不同操作的日志信息是不一样的。
如果在每个操作方法里写日志,是个很大的问题,如果能用钩子来处理那就好了,但是我一直没弄明白,请楼主指教。先谢! 我用钩子实现管理系统的权限设置 回复 7# redtamo
我用module实现系统的权限验证 回复 6# aqw23
如果非要这么实现的话会非常牵强而且不一定能实现,不用说太多废话了,用钩子实现是非常不理智的.就老老实实的写相应的函数吧. 好文 收藏