Codeigniter CI 框架的一些思考

前段时间使用CI做了两个小项目,对CI的流程和设计理念也有了一些新的认识。CI架构的一些基本优化这里就不做介绍了,如搬离system 文件夹等。

最近有一个稍微大一点的系统,也准备拿CI来做。设计时遇到架构上的一个问题:

我们知道,CI的工作流程大致是这样的,官网3.0的图:

一个典型的网站加载流程应该是在 controller 里添加public 方法,在方法里调用 load->view() 来显示视图,返回结果。CI 对于敏捷开发快速迭代相当友好,一个网站很容易就搭起来,而且似乎还条理清晰。但是,在有一些复杂逻辑的时候,就需要在设计时做好一些考虑。比如,网页一般都有header, main_content, footer,header 和 footer可能每个页都是一致的,每个页可能还会有menu bar之类也是一致,如果按照最简单的写法,那么每次我们都需要

$this->load->view(‘templates/header‘);
$this->load->view(‘body‘);
$this->load->view(‘templates/footer‘);

那么,如何省略每次的header和footer的load呢?很自然的,我们自定义一个Loader,在里面实现一个新的方法如 template,自动调用header和footer的载入过程,如

class MY_Loader extends CI_Loader {
    public function template($template_name, $vars = array(), $return = FALSE)
    {
        $content  = $this->view(‘templates/header‘, $vars, $return);
        $content .= $this->view($template_name, $vars, $return);
        $content .= $this->view(‘templates/footer‘, $vars, $return);

        if ($return)
        {
            return $content;
        }
    }
}

3.X 的话,可以

class MY_Loader extends CI_Loader {
    public function template($template_name, $vars = array(), $return = FALSE)
    {
        if($return):
        $content  = $this->view(‘templates/header‘, $vars, $return);
        $content .= $this->view($template_name, $vars, $return);
        $content .= $this->view(‘templates/footer‘, $vars, $return);

        return $content;
    else:
        $this->view(‘templates/header‘, $vars);
        $this->view($template_name, $vars);
        $this->view(‘templates/footer‘, $vars);
    endif;
    }
}

那么我们调用的时候便可以

$this->load->template(‘body‘);

就行了。

还有一种办法,在官方的git wiki上,想法是每个页面有类似的模板,然后把header body footer分别载入好了之后传入变量,在view中echo 出来。所有的页面都是一个模板:

<html>
<head>
<?php
    echo "\n". link_tag(‘assets/stylesheets/COMMON.css‘);
    echo "\n". link_tag(‘assets/stylesheets/‘. $theme .‘.css‘);
?>

<title>
    <?php echo $title; ?>
</title>
</head>

<body>

<?php
?>

<div id="div_everything_wrapper">

    <div id="div_topbar_wrapper">
        <?php echo $top_bar_view; ?>
    </div>

    <div class="break">
    </div>

    <div id="div_torso_wrapper">

        <div id="div_navigation_menu">
            <?php echo $main_menu_view; ?>
        </div>

        <div id="div_main_content">
            <?php echo $main_content_view;  ?>
        </div>

    </div>

    <div class="break">
    </div>

    <div id="div_footer_wrapper">
        <table width="100%">
            <tr width="100%">
            <td width="25%" align="left">
                <b>
                <!-- Can‘t pre-render this, as it‘ll throw the reported results -->
                Rendered in {elapsed_time}s, and {memory_usage}.
                </b>
            </td>
            <td width="50%" align="center">
                $other_stuff
            </td>
            <td width="25%" align="right">
                Developed using
                <?php echo anchor_popup ("http://codeigniter.com/", "Code Igniter"); ?>
            </td>
            </tr>
        </table>
    </div>
</div>

</body>
</html>

这两类方法,第一种方法缺乏一定的灵活性,有些时候有很多template的一些子view是共有的,难以复用。第二种方法controller的代码实际上有些臃肿。两种方法均太弱化了view的功能。这里我便有一种架构。

  1. 页面仍然存在模板,但不是一个模板,不同页面的模板可能会稍有不同

    在官方wiki的第二个方法中,其所有页面均是一个模板,这样一个问题就是难以处理多种类型的页面之间的不一致性(header中载入的一些common.css js不一样,这些就可以在不同的模板view中写好,而不用再去controller里写)

  2. CI_Loader做扩展,但是自定义的loader的传入的参数不是view的名称,而是view的内容,一个方法对应一个模板页面:
<?php
/**
 * Created by PhpStorm.
 * User: Sorean
 * Date: 2015/5/23
 * Time: 21:03
 */
defined(‘BASEPATH‘) OR exit(‘No direct script access allowed‘);

class MY_Loader extends CI_Loader{
    //一种page 对应一种模板
    var $footer = ‘‘;
    function main_page($page_content = ‘‘, $page_data = array(), $header = ‘‘, $navbar_data = array(), $sidebar_data = array(), $footer = ‘‘){
        $page_data[‘header‘] = $header;
        $page_data[‘page_content‘] = $page_content;
        $page_data[‘navbar‘] = parent::view(‘main/navbar‘,$navbar_data, TRUE);
        $page_data[‘sidebar‘] = parent::view(‘main/sidebar‘, $sidebar_data, TRUE);
        $page_data[‘footer‘] = $this->footer . $footer;
        parent::view(‘main/default‘, $page_data);
    }

    function login_page($data = array()){
        parent::view(‘login/login‘, $data);
    }

    function admin_page($page_content = ‘‘, $page_data = array(), $header = ‘‘, $navbar_data = array(), $sidebar_data = array(), $footer = ‘‘){
        $page_data[‘header‘] = $header;
        $page_data[‘page_content‘] = $page_content;
        $page_data[‘navbar‘] = parent::view(‘admin/navbar‘,$navbar_data, TRUE);
        $page_data[‘sidebar‘] = parent::view(‘admin/sidebar‘, $sidebar_data, TRUE);
        $page_data[‘footer‘] = $this->footer . $footer;
        parent::view(‘admin/default‘, $page_data);
    }

    // --------------------------------------------------------------------

    /**
     * View Loader
     *
     *  每个view可以添加一个同名的js,会自动load在document 末尾
     *
     * @param    string    $view    View name
     * @param    array    $vars    An associative array of data
     *                to be extracted for use in the view
     * @param    bool    $return    Whether to return the view output
     *                or leave it to the Output class
     * @return    object|string
     */
    public function view($view, $vars = array(), $return = FALSE)
    {
        if(file_exists(APPPATH ."/views/$view-js.php")) {
            $this->footer .= parent::view($view . ‘-js‘, $vars, TRUE);
        }
        return $this->_ci_load(array(‘_ci_view‘ => $view, ‘_ci_vars‘ => $this->_ci_object_to_array($vars), ‘_ci_return‘ => $return));
    }

}

如此,在controller中便可以对page_content做自由的订制,传入子view等等,而sidebar 和navbar的数据可以做进一步的扩展。

不同的页面模板做不同的xx_page名称,如admin_page, main_page,在controller中使用的时候,

$this->load->main_page(
            $this->load->view(xxxxx, xxxxx),
            array(‘title‘ => ‘xxxx‘), // page里的一些共有data,如标题
            ‘‘,
            parent::nav_bar_data());

还可根据要求在header和footer上做额外扩展

3.  对CI_Controller做两层扩展。

首先说明一下,对CI_Controller的扩展必须以MY_开头(定义在config文件中)。做多层扩展的类,必须和MY_Controller处于同一个文件内。因为CI只会识别MY_Controller.php那个文件。

有些人可能认为不需要多层扩展,这里分两层的作用是区分业务代码,在Comm_Controller里面是一些get_navbar_data(), get_xxx_comm_view()之类的函数,而MY_Controller里做一些非业务的逻辑,如session中的数据处理,超时。

4.细心的读者可能会发现,我重写了load->view方法,在其中寻找对应的js文件,存在则自动载入。

大多数view会有一些js处理文件,这些文件一般建议放在文档尾部(如果和view写在一个文件里,那么有些js的载入顺序难以保证,如我需要jQuery在document尾部载入,而view中的一些js依赖jQuery)

正如CI官网对自己的介绍所说“CodeIgniter is a powerful PHP framework with a very small footprint, built for developers who need a simple and elegant toolkit to create full-featured web applications.”CI最大的优势就在于功能齐全且方便扩展。这一套继承的逻辑问题在一个稍微大型里的系统里都会遇到,但是CI并没有官方的指引说建议这么写这么写,个人认为这正是CI最吸引人的地方。可以依据个人的想法和项目的需求做非常灵活的变化。我曾尝试过在view中写很多底层逻辑(如sidebar的active判定),也未尝觉得是一种丑陋的脱离MVC本源的做法。

Anyway,合适的才是最好的。

时间: 2024-08-27 10:10:04

Codeigniter CI 框架的一些思考的相关文章

PHP框架CodeIgniter CI框架源码学习笔记-index.php一切的入口

CI框架(CodeIgniter)的基本执行流程图以备参考: index.php作为CI框架的入口文件,源码阅读,自然由此开始.

CodeIgniter(CI)框架中的验证码

在CodeIgniter框架中,CI本身自带了验证码,但是查看文档的时候,发现: 需要新建一个表,用来存储验证码信息.因为习惯了session存储验证码信息,所以我把我认为比较好看的验证码应用在了CI的框架中. 在 CodeIgniter/application/libraries/ 目录下,新建一个文件 取名 captcha.php. 1 <?php 2 defined('BASEPATH') OR exit('No direct script access allowed'); 3 4 cl

CI框架源码阅读笔记4 引导文件CodeIgniter.php

到了这里,终于进入CI框架的核心了.既然是"引导"文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.com/usr/reg 经过引导文件,实际上会交给Application中的UsrController控制器的reg方法去处理. 这之中,CodeIgniter.php做了哪些工作?我们一步步来看. 1.    导入预定义常量.框架环境初始化 之前的一篇博客(CI框架源码阅读笔记2 一切的入

**【ci框架】精通CodeIgniter框架

http://blog.csdn.net/yanhui_wei/article/details/25803945 一.大纲 [php] view plaincopy 1.codeigniter框架的授课内容安排 2.codeigniter框架的简介 |-----关于框架的概念 |-----使用CI框架的好处 |-----为什么选择CI框架 3.codeigniter框架的具体安装步骤 |-----官网下载:http://www.codeigniter.com/ |-----httpd.conf配

nginx rewrite php的CI(CodeIgniter)框架

一. 了解nginx rewrite: 正则表达式匹配,其中: * ~ 为区分大小写匹配    * ~* 为不区分大小写匹配    * !~和!~*分别为区分大小写不匹配及不区分大小写不匹配 文件及目录匹配,其中: * -f和!-f用来判断是否存在文件    * -d和!-d用来判断是否存在目录    * -e和!-e用来判断是否存在文件或目录    * -x和!-x用来判断文件是否可执行 flag标记有: * last 相当于Apache里的[L]标记,表示完成rewrite    * bre

ci框架操作数据库基本方法

授课过程中如果涉及到文件夹或目录时,可使用缩进进行演示: application |-----libraries |-----xxx_helper.php system |-----libraries |-----url_helper.php --------------------------------------------------------------------------------------------------------------------------------

CI框架剖析一

CodeIgniter 是一个小巧但功能强大的 PHP 框架,作为一个简单而"优雅"的工具包,它可以为开发者们建立功能完善的 Web 应用程序.本人使用CI框架有一段时间了,现在决定把该框架源码剖析一遍,理解其构架的用意与精妙之处.分析完所有的源码后,我才来总结CI框架的优缺点,以及适用于哪些场景开发. 目前CI最新的版本是 3.1.4, 4.0版本也即将发布.我们先分析3.1.4版本,然后再看看4.0有哪些重大突破. 首先是查看根目录下index.php文件了,主要定义了几个常量:

CI框架源码分析

这几天,把ci源码又看了一遍,于是有了新的收获.明白了在application目录下core文件夹的作用,就是用来写ci核心文件的扩展的, 而且需要在配置文件中添加类前缀MY_. CI框架整体是但入口文件,入口文件是Index.php在该文件中定义了一些系统变量,比如BASEPATH和 APPPATH等,最后加载ci框架的核心文件CodeIgniter文件,该文件位于system文件夹下的core文件夹下,此文件夹是ci的核心文件,包括了 controller,model,router,conf

CI框架源码阅读笔记5 基准测试 BenchMark.php

上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功能,各模块之间可以相互调用,共同构成了CI的核心骨架. 从本篇开始,将进一步去分析各组件的实现细节,深入CI核心的黑盒内部(研究之后,其实就应该是白盒了,仅仅对于应用来说,它应该算是黑盒),从而更好的去认识.把握这个框架. 按照惯例,在开始之前,我们贴上CI中不完全的核心组件图: 由于BenchMa