Codeigniter:构建部分视图的最佳方式

时间:2010-09-09 08:58:59

标签: php design-patterns codeigniter

如何在Codeigniter中构建以下页面?

alt text

我考虑为每个部分创建单独的控制器

  1. 左导航
  2. 内容导航
  3. 登录名
  4. 横幅
  5. 排除内容部分(因为此更改取决于左侧导航栏和内容导航栏中用作有点子菜单的链接)。所有其他部分保持大致相同

    我想过:

    Class User_Profile extends Controller
    {
    
        function index()
        {
            $this->load_controller('Left_Nav');
            $this->load_controller('Content_Nav');
            $this->load_controller('Login_Name');
            $this->load_controller('Leaderboard', 'Board');
    
            $this->Left_Nav->index(array('highlight_selected_page' => 'blah'));
    
            $this->load('User');
    
            $content_data = $this->User->get_profile_details();
    
            $this->view->load('content', $content_data);
    
            $this->Login_Name->index();
            $this->Board->index();
        }
    
    }
    

    显然这个load_controller不存在但是这个功能很有用。每个部分的控制器从模型中获取所需的数据,然后通过$this->view->load()

    加载页面

    在新闻,用户,关于我们等所有左侧导航链接中使用此代码可能会令人头疼。但是,然后再次并非每个导航链接都包含所有这些部分,因此我需要将这些部分作为灵活性“部分观点”

    有人能建议更好的方法吗?

7 个答案:

答案 0 :(得分:28)

@Reinis的答案可能正确地针对小于2.0的旧版本的CI正确地点击了,但是从那以后很多时候已经发生了变化,所以我想我会用最新的方法回答这个问题。

大部分内容与@Reinis方法类似,此处也有描述:http://codeigniter.com/wiki/MY_Controller_-_how_to_extend_the_CI_Controller

然而,以下是我所做的更新:

步骤1:创建一个MY_Controller.php文件并将其存储在/ application / core

步骤2:在MY_Controller.php文件中输入以下内容:

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class MY_Controller extends CI_Controller {

    function __construct()
    {
        parent::__construct();
    }

    function _output($content)
    {
        // Load the base template with output content available as $content
        $data['content'] = &$content;
        echo($this->load->view('base', $data, true));
    }

}

步骤3:创建一个基于MY_Controller.php的样本控制器,在这种情况下,我将在application / controllers /中创建一个welcome.php控制器,其中包含以下内容:

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Welcome extends MY_Controller {

    function __construct()
    {
        parent::__construct();
    }

    public function index()
    {
        $this->load->view('welcome_message');
    }

}

设置好这些控制器后,请执行以下操作:

步骤4:在/ application / views中创建一个基本视图并命名文件base.php,该文件的内容应类似于:

<!DOCTYPE html>
<!--[if IE 7 ]><html lang="en" class="ie7"><![endif]-->
<!--[if IE 8 ]><html lang="en" class="ie8"><![endif]-->
<!--[if gt IE 8]><!--><html lang="en"><!--<![endif]-->
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
        <title></title> 
        <link rel="stylesheet" href="<?php echo base_url(); ?>stylesheets/reset.css" media="screen" />
    </head>
    <body>
        <div id="section_main">
            <div id="content">
                <?php echo $content; ?>
            </div>
        </div>
        <?php $this->load->view('shared/scripts.php'); ?>
        </div>
    </body>
</html>

步骤5:在/ application / views中创建另一个视图并将此视图命名为welcome_message.php,该文件的内容将为:

<h1>Welcome</h1>

一旦完成所有这些,您应该看到以下输出:

<!DOCTYPE html>
<!--[if IE 7 ]><html lang="en" class="ie7"><![endif]-->
<!--[if IE 8 ]><html lang="en" class="ie8"><![endif]-->
<!--[if gt IE 8]><!--><html lang="en"><!--<![endif]-->
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
        <title></title> 
        <link rel="stylesheet" href="http://somedomain.local/stylesheets/reset.css" media="screen" />
    </head>
    <body>
        <!-- BEGIN: section_main -->
        <div id="section_main">
            <div id="content">
                <h1>Welcome</h1>
            </div>
        </div>
        <!-- END: section_main -->
        <script src="/path/to/js.js"></script>
        </div>
    </body>
</html>

如您所见,<h1>Welcome</h1>已放入基本模板。

资源:

希望这可以帮助其他人遇到这种技术。

答案 1 :(得分:23)

我不能保证这是最好的方法,但我创建了一个这样的基本控制器:

class MY_Controller extends CI_Controller {

    public $title = '';
    // The template will use this to include default.css by default
    public $styles = array('default');

    function _output($content)
    {
        // Load the base template with output content available as $content
        $data['content'] = &$content;
        $this->load->view('base', $data);
    }

}

名为“base”的视图是一个模板(包含其他视图的视图):

<?php echo doctype(); ?>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <?php $this->load->view('meta'); ?>
    </head>
    <body>
        <div id="wrapper">
            <?php $this->load->view('header'); ?>

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

            <?php $this->load->view('footer'); ?>
        </div>
    </body>
</html>

这实现了每个控制器将其输出包装在基本模板中,并且该视图具有有效的HTML而不是在一个视图中打开标记而在另一个视图中关闭。如果我想让特定的控制器使用不同的模板或不使用模板,我可以覆盖魔术_output()方法。

实际控制器如下所示:

class Home extends MY_Controller {

    // Override the title
    public $title = 'Home';

    function __construct()
    {
        // Append a stylesheet (home.css) to the defaults
        $this->styles[] = 'home';
    }

    function index()
    {
        // The output of this view will be wrapped in the base template
        $this->load->view('home');
    }
}

然后我可以在我的视图中使用它的属性(这是填充<head>元素的'meta'视图):

echo "<title>{$this->title}</title>";
foreach ($this->styles as $url)
    echo link_tag("styles/$url.css");

我喜欢我的方法,因为它尊重DRY原则,页眉,页脚和其他元素只包含在代码中一次。

答案 2 :(得分:6)

我的模板库可以处理所有这些。您可以创建一个(或多个)布局文件,其中包含部分内容和主体内容所在位置的标记。

语法简单如下:

// Set the layout: defaults to "layout" in application/views/layout.php
$this->template->set_layout('whatever') 

// Load application/views/partials/viewname as a partial
$this->template->set_partial('partialname', 'partials/viewname');

// Call the main view: application/views/bodyviewname
$this->template->build('bodyviewname', $data); 

简单吧?

将其中的一部分放入MY_Controller中,它更容易。

答案 3 :(得分:1)

你考虑过模板吗?有很多不错的搜索可供选择 - 查看CI维基。

模板或多或少地完全符合您的要求。您可以定义一个主模板和“部分”,每次都会为您加载

不想插入太多,这可能会让你开始 - template libraries in CI

答案 4 :(得分:1)

我会让MY_Controller来处理这一切。您可以使用布局(模板)/导航库来生成所有布局,导航,显示/突出显示所选菜单项,加载视图等。

如果您为每个页面部分使用控制器,我会说这不是正确的方法。您可以为此使用视图和嵌套视图。

答案 5 :(得分:1)

我喜欢Phil Sturgeon提到的。虽然它被认为非常复杂,但我真的很喜欢magento的模板结构。

受到这种结构化方式的启发,我制作了我的逻辑,(这根本不是很好,但它很简单,也许我可以覆盖 - > gt;视图加载器并让它接受某种对象模板名称,然后根据需要加载结构)

首先:必须非常负责任地使用此方法(您可以在模板所需的控制器/方法中准备数据!

第二:模板需要准备好并且结构合理。

这就是我的所作所为:

  • 在每个控制器中我都有Array类型的属性,如下所示:

    class Main extends CI_Controller {
    
    public $view = Array(
            'theend' => 'frontend',
            'layout' => '1column',
            'mainbar' => array('content','next template file loaded under'),
            'sidebar' => array('generic','next template file loaded under'),
            'content' => '',
    );
    
  • 在我想要使用以前结构的每个方法中,如果我想稍微更改它,我会这样写:

    public function index()
    {
    $data['view'] = $this->view;  // i take/load global class's attribute
    $data['view']['mainbar'] = Array('archive','related_posts'); // i change mainbar part of it
    // i add/load data that i need in all those templates that are needed $data['view'] also my using same Array  $data['my_required_data_that_i_use_in_template_files'] = 1;
    $this->load->view('main',$data); //
    }
    

第三在/ application / view文件夹中我有

之类的结构
/view/main.php <-- which basically just determines which side's wrapper of web to load (frontend or backend or some other)

/view/frontend/wrapper.php

/view/backend/wrapper.php

/view/mobile/wrapper.php   <-- this wrappers are again another level of structuring for ex:

/view/backend/layouts/   <-- inside i have templates different layouts like 1column.php 2columns-left (have left side is narrow one),2columns-right,3columns... etc...

/view/backend/mainbar/   <-- inside i have templates for mainbar in pages

/view/backend/mainbar/.../ <-- in the same way it's possible to add folders for easily grouping templates for example for posts so you add for example

    /view/backend/mainbar/posts/  <-- all templates for creating, editing etc posts... 

    /view/backend/sidebar/   <-- inside i have templates for sidebar in pages

    /view/backend/...other special cases.... like dashboard.php
/app/view/main.php中的

文件类似于:

if ($view['theend'] == "frontend")
{
$this->load->view('/frontend/wrapper');
} elseif ($view['theend'] == "backend")
{
$this->load->view('/backend/wrapper');
}

第五个包装器很简单,你可以在结构化HTML中使用php     head(加载html标题,标题等...)     标题/标题(如果在传递$ data ['view'] ['headers']变量/数组中有任何内容,则在标题中加载)     布局(在布局文件中加载,只有新的html结构化文件,下一级加载文件)     页脚/页脚(如果有任何传入$ data ['view'] ['footers']变量,则按页脚加载)     脚本(在标记之前加载诸如analytics / facebook脚本之类的文档)

第六所以同样的方式,布局也会加载在public $ view = Array(....)

中指定的主栏/侧边栏内容中

如果我需要某种方法,我只是覆盖public $ view = Array(...)属性的一部分,并且我只覆盖不同的部分。

它完成了这样的事情:

public function index()
{
    $data['view'] = $this->view;  // i take/load global class's attribute
    $data['view']['mainbar'] = Array('archive','related_posts'); // i change mainbar part of it
// i add/load data that i need in all those templates that are needed $data['view'] also my using same Array  $data['my_required_data_that_i_use_in_template_files'] = 1;
    $this->load->view('main',$data); //
}

最终加载如下:

  1. $这 - &GT;负载&gt;查看( '主',$数据); &lt; - 加载/app/view/main.php并传递$ data $ data有节点'view'($ data ['view']),其中有子节点,它确定其他重要的东西,如:什么是结束,什么布局,什么标题,什么页脚等......

  2. 在$ data ['view'] ['theend']中使用已定义的数据,它会加载正确的包装

  3. 再次在包装中使用$ data ['view'] ['layout']中的数据,它会加载其他更深层次的结构,如布局......
  4. 布局,使用相同的$ data ['view'] ['mainbar'],$ data ['view'] ['sidebar']并抓住其他重要部分加载,如主栏模板,侧边栏模板...
  5. 就是这样......

    P.S。我很抱歉没有使用数字,但stackoverflow系统是如此奇怪,而不是显示3.它显示我1 ...你看到我有一些嵌套列表......

答案 6 :(得分:-1)

我所做的(在Kohana 2中)有1个模板,包含所有子部分(如左侧菜单,顶部标题),以及一个控制器,用于填充将在模板中替换的变量。

然后,每个子部分的变量可以由控制器本身调用的函数生成。您还可以将这些函数放在单独的控制器类的构造函数中,您的每个控制器都会扩展该控制器,以便它们自动运行并设置为类变量以便于访问。

对于稍微好一点的模板,您可以将子部分放在单独的文件中,大模板包含它们:

<?php include 'leftMenu.php'; ?>