php CI框架高级视图功能,视图继承,多重继承,视图片段

可参考http://codeigniter.org.cn/forums/thread-8949-1-1.html

我这里是从项目代码里总出来的:

1、首先在application/core文件夹下增加MY_Loader.php文件。只要增加这个类就可以,其他操作不变,在视图文件中就可以使用视图继承了。

文件内容如下:

  1 <?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2 
  3 /**
  4  * Loader Extend Class
  5  *
  6  * Loads views and files
  7  *
  8  * @package        CodeIgniter
  9  * @subpackage    Libraries
 10  * @author        Kth007#gmail.com
 11  * @category    Loader
 12  * @link        http://codeigniter.org.cn/forums/viewthread.php?tid=8949
 13  */
 14 class MY_Loader extends CI_Loader
 15 {
 16 
 17     /**
 18      * 视图堆栈
 19      *
 20      * @var array
 21      */
 22     private $_stacks = array();
 23 
 24     /**
 25      * 当前处理的视图
 26      *
 27      * @var int
 28      */
 29     private $_current;
 30 
 31     /**
 32      * 视图的继承
 33      *
 34      * @param string $tplname
 35      *
 36      * @access protected
 37      */
 38     protected function _extends($tplname)
 39     {
 40         $this->_stacks[$this->_current]['extends'] = $tplname;
 41     }
 42 
 43     /**
 44      * 开始定义一个区块
 45      *
 46      * @param string $block_name
 47      * @param mixed $config
 48      *
 49      * @access protected
 50      */
 51     protected function _block($block_name, $config = null)
 52     {
 53         $stack =& $this->_stacks[$this->_current];
 54         if (!empty($stack['blocks_stacks']))
 55         {
 56             // 如果存在嵌套的 block,则需要记录下嵌套的关系
 57             $last = $stack['blocks_stacks'][count($stack['blocks_stacks']) - 1];
 58             $stack['nested_blocks'][] = array($block_name, $last);
 59         }
 60         $this->_stacks[$this->_current]['blocks_config'][$block_name] = $config;
 61         array_push($stack['blocks_stacks'], $block_name);
 62         ob_start();
 63     }
 64 
 65     /**
 66      * 结束一个区块
 67      *
 68      * @access protected
 69      */
 70     protected function _endblock()
 71     {
 72         $block_name = array_pop($this->_stacks[$this->_current]['blocks_stacks']);
 73         $this->_stacks[$this->_current]['blocks'][$block_name] = ob_get_clean();
 74         echo "%block_{$block_name}_{$this->_stacks[$this->_current]['id']}%";
 75     }
 76 
 77 
 78     /**
 79      * 载入一个视图片段
 80      *
 81      * @param string $element_name 视图名称
 82      * @param array $vars
 83      *
 84      * @access protected
 85      */
 86     protected function _element($element_name, array $vars = null)
 87     {
 88         $file_exists = FALSE;
 89         $filename = '';
 90         foreach ($this->_ci_view_paths as $view_file => $cascade)
 91         {
 92             $filename = $view_file.$element_name.EXT;
 93             if ( ! file_exists($filename))
 94             {
 95                 $file_exists = FALSE;
 96             }else{
 97                 $file_exists = TRUE;break;
 98             }
 99         }
100         if(!$file_exists){
101             show_error('Unable to load the requested file: '.$filename);
102         }else{
103             extract($this->_ci_cached_vars);
104             if (is_array($vars)) extract($vars);
105             include($filename);
106         }
107     }
108 
109     /**
110      * Loader
111      *
112      * 这个函数用来加载视图或者文件.
113      * 这个函数改写 CI_Loader 类内函数,使其支持视图继承和多重继承。
114      *
115      * @access    private
116      * @param    array
117      * @return    void
118      */
119     function _ci_load($_ci_data)
120     {
121         // 设置默认的数据变量
122         foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return', '_ci_viewid', '_ci_stack') as $_ci_val)
123         {
124             $$_ci_val = ( ! isset($_ci_data[$_ci_val])) ? FALSE : $_ci_data[$_ci_val];
125         }
126 
127         // 设置请求文件的路径
128         if ($_ci_path != '')
129         {
130             $_ci_x = explode('/', $_ci_path);
131             $_ci_file = end($_ci_x);
132         }
133         else
134         {
135             $_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION);
136             $_ci_file = ($_ci_ext == '') ? $_ci_view.'.php' : $_ci_view;
137 
138             foreach ($this->_ci_view_paths as $view_file => $cascade)
139             {
140                 if (file_exists($view_file.$_ci_file))
141                 {
142                     $_ci_path = $view_file.$_ci_file;
143                     $file_exists = TRUE;
144                     break;
145                 }
146 
147                 if ( ! $cascade)
148                 {
149                     break;
150                 }
151             }
152         }
153 
154         if ( ! file_exists($_ci_path))
155         {
156             show_error('Unable to load the requested file: '.$_ci_file);
157         }
158 
159         // 这允许任何加载使用 $this->load (views, files, etc.)
160         // 成为从内部控制器和模型函数访问.
161 
162         $_ci_CI =& get_instance();
163         foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var)
164         {
165             if ( ! isset($this->$_ci_key))
166             {
167                 $this->$_ci_key =& $_ci_CI->$_ci_key;
168             }
169         }
170 
171         /*
172          * 提取缓存和变量   也就是把数组下标变成变量
173          *
174          * You can either set variables using the dedicated $this->load_vars()
175          * function or via the second parameter of this function. We'll merge
176          * the two types and cache them so that views that are embedded within
177          * other views can have access to these variables.
178          */
179         if (is_array($_ci_vars))
180         {
181             $this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars);
182         }
183         extract($this->_ci_cached_vars);
184 
185         //-----by:kth007 20100422------------------------------------------------------------------------------
186         if ( ! $_ci_viewid) $_ci_viewid = mt_rand();
187 
188         $stack = array(
189         'id'            => $_ci_viewid,
190         'contents'      => '',
191         'extends'       => '',
192         'blocks_stacks' => array(),
193         'blocks'        => array(),
194         'blocks_config' => array(),
195         'nested_blocks' => array(),
196         );
197         array_push($this->_stacks, $stack);
198         $this->_current = count($this->_stacks) - 1;
199         unset($stack);
200         //-----------------------------------------------------------------------------------
201 
202         /*
203          * 缓冲输出
204          *
205          * We buffer the output for two reasons:
206          * 1. Speed. You get a significant speed boost.
207          * 2. So that the final rendered template can be
208          * post-processed by the output class.  Why do we
209          * need post processing?  For one thing, in order to
210          * show the elapsed page load time.  Unless we
211          * can intercept the content right before it's sent to
212          * the browser and then stop the timer it won't be accurate.
213          */
214         ob_start();
215 
216         // If the PHP installation does not support short tags we'll
217         // do a little string replacement, changing the short tags
218         // to standard PHP echo statements.
219 
220         if ((bool) @ini_get('short_open_tag') === FALSE AND config_item('rewrite_short_tags') == TRUE)
221         {
222             echo eval('?>'.preg_replace("/;*\s*\?>/", "; ?>", str_replace('<?=', '<?php echo ', file_get_contents($_ci_path))));
223         }
224         else
225         {
226             include($_ci_path); // include() vs include_once() allows for multiple views with the same name
227         }
228         
229         
230         log_message('debug', 'File loaded: '.$_ci_path);
231 
232 //-----by:kth007 20100422-----------------------------------------------------------------------------------------------------
233         $stack = $this->_stacks[$this->_current];
234         $stack['contents'] = ob_get_clean();
235 
236         // 如果有继承视图,则用继承视图中定义的块内容替换当前视图的块内容
237         if (is_array($_ci_stack))
238         {
239             foreach ($_ci_stack['blocks'] as $block_name => $contents)
240             {
241                 if (isset($stack['blocks_config'][$block_name]))
242                 {
243                     switch (strtolower($stack['blocks_config'][$block_name]))
244                     {
245                         case 'append':
246                             $stack['blocks'][$block_name] .= $contents;
247                             break;
248                         case 'replace':
249                         default:
250                             $stack['blocks'][$block_name] = $contents;
251                     }
252                 }
253                 else
254                 {
255                     $stack['blocks'][$block_name] = $contents;
256                 }
257             }
258         }
259         // 如果有嵌套 block,则替换内容
260         while (list($child, $parent) = array_pop($stack['nested_blocks']))
261         {
262             $stack['blocks'][$parent] = str_replace("%block_{$child}_{$_ci_viewid}%",
263             $stack['blocks'][$child], $stack['blocks'][$parent]);
264             unset($stack['blocks'][$child]);
265         }
266         // 保存对当前视图堆栈的修改
267         $this->_stacks[$this->_current] = $stack;
268 
269         if ($stack['extends'])
270         {
271             //私有继承.
272             $filename = "{$stack['extends']}".EXT;
273                 
274             return $this->_ci_load(array(
275                                 '_ci_view' => $filename, 
276                                 //'_ci_vars' => $this->_ci_cached_vars,
277                                 '_ci_return' => $_ci_return,
278                                 '_ci_viewid'=>$_ci_viewid, 
279                                 '_ci_stack'=>$this->_stacks[$this->_current],
280             ));
281         }
282         else
283         {
284             // 最后一个视图一定是没有 extends 的
285             $last = array_pop($this->_stacks);
286             foreach ($last['blocks'] as $block_name => $contents)
287             {
288                 $last['contents'] = str_replace("%block_{$block_name}_{$last['id']}%",
289                 $contents, $last['contents']);
290             }
291             $this->_stacks = array();
292             
293             
294             if ($_ci_return === TRUE)
295             {
296                 @ob_end_clean();
297                 return $last['contents'];
298             }
299 
300             if (ob_get_level() > $this->_ci_ob_level + 1)
301             {
302                 ob_end_flush();
303             }
304             else
305             {
306                 $_ci_CI->output->append_output($last['contents']);
307                 @ob_end_clean();
308             }
309 
310         }
311 //--------------------------------------------------------------------------------------------
312 
313         
314         // Return the file data if requested
315 /*        if ($_ci_return === TRUE)
316         {
317             $buffer = ob_get_contents();
318             @ob_end_clean();
319             return $buffer;
320         }
321 */
322         /*
323          * Flush the buffer... or buff the flusher?
324          *
325          * In order to permit views to be nested within
326          * other views, we need to flush the content back out whenever
327          * we are beyond the first level of output buffering so that
328          * it can be seen and included properly by the first included
329          * template and any subsequent ones. Oy!
330          *
331          */
332 /*        if (ob_get_level() > $this->_ci_ob_level + 1)
333         {
334             ob_end_flush();
335         }
336         else
337         {
338             $_ci_CI->output->append_output(ob_get_contents());
339             @ob_end_clean();
340         }
341 */
342 
343 
344     }
345 
346 }
347 
348 /* End of file MY_Loader.php */
349 /* Location: ./application/core/MY_Loader.php */

2、在视图文件中使用视图继承:

首先可以在视图中增加一些基础的视图文件作为父视图,以供继承使用,如:view/_layouts/default_layout.php

代码可参考如下:

 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3 <head>
 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 5 <title><?php $this->_block('title'); ?>我的被别人继承的<?php $this->_endblock(); ?></title>
 6 <script type="text/javascript" src="/static/js/jquery.js"></script>
 7 <script type="text/javascript" src="/static/css/layout.js"></script>
 8 <?php $this->_block('head'); ?><!--这里是载入私有的CSS和JS--><?php $this->_endblock(); ?>
 9 </head>
10 <body>
11 <div>这里是头部</div>
12 <div>这里是导航</div>
13 <div>这里是左栏</div>
14 <div><!--这里是内容-->
15 <?php $this->load->_block('content'); ?><?php $this->load->_endblock(); ?></div>
16 </div>
17 <div><?php $this->_block('footer')?> 这里是尾部 <?php $this->_endblick();?></div>
18 </body>
19 </html>

然后在自已的视图里就可以继承这个视图了

如:

 1         //继承父视图
 2  <?php  $this->_extends('_layouts/default_layout'); ?>
 3  // 重写title
 4  <?php $this->_block('title'); ?>我自己的title,覆盖父类的title<?php $this->_endblock(); ?>
 5  
 6 //重写head部分,可以引入一些自己的JS和CSS,
 7 <?php $this->_block('head'); ?><!--这里是载入私有的CSS和JS--><?php $this->_endblock(); ?>
 8 
 9  //覆盖父视图中的contents部分,这里就可以自定义自己的内容部分了
10   <?php  $this->_block('contents'); ?>
11   
12   <br><br><br><br><br><br>
13   <center>
14   <div style="width:300px;border:1px solid #70B1CD;background:#E0EFF8"><br><br>
15   <h3 style="color:red;font-size:12px;"><?php echo $message_caption; ?></h3><br>
16   <p style="color:#000;font-size:12px;">
17    <?php echo nl2br(htmlspecialchars($message_body)); ?>
18  </p><br>
19  <p style="font-size:12px;">
20    <a href="<?php echo $redirect_url; ?>">如果您的浏览器没有自动跳转,请点击这里</a>
21  </p><br>
22  </div>
23  </center>
24  <script type="text/javascript">
25  setTimeout("window.location.href ='<?php echo $redirect_url; ?>';", <?php echo $redirect_delay * 1000; ?>);
26  </script>
27 <?php echo $hidden_script; ?>
28  
29  <?php  $this->_endblock(); ?>

还可以载入某个视图片段,方法如下:

<?php $this->load->_element('topnews', $topnews);?>
posted @ 2012-11-26 17:24  欧麦噶地  阅读(1741)  评论(0编辑  收藏  举报