【问题标题】:Codeigniter: Best way to structure partial viewsCodeigniter:构造部分视图的最佳方式
【发布时间】:2010-09-09 08:58:59
【问题描述】:

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

我想过为每个部分创建单独的控制器

  1. 左导航
  2. 内容导航
  3. 登录名
  4. 排行榜

不包括内容部分(因为这取决于左侧导航上的链接和用作子菜单的内容导航)。所有其他部分大致相同

我想过做:

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()加载页面

在所有左侧导航链接(如新闻、用户、关于我们等)中包含此代码可能会让人头疼。但同样,并非每个导航链接都有所有这些部分,所以我需要将这些部分作为“局部视图”

任何人都可以提出更好的方法吗?

【问题讨论】:

    标签: php design-patterns codeigniter


    【解决方案1】:

    @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');
        }
    
    }
    

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

    第四步:在 /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>
    

    如您所见,&lt;h1&gt;Welcome&lt;/h1&gt; 已放入基本模板中。

    资源:

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

    【讨论】:

    • 如果您是从全新安装中执行此操作,您还需要在 application/config/autoload.php 中启用“url”帮助程序(以便 base_url() 工作)。
    • 我了解您基本上构建了初始内容视图,然后在输出之前构建基础视图并将预构建的内容添加到基础视图。我不明白通过引用传递?我已经以相同的方式进行了设置,并且只将数据数组中的几个位传递给了基础(如 page_title、page_keywords 等),但它给了我一个空白屏幕......所以它似乎没有加载基本视图,但没有错误...查看 $data 确实显示了所有正确的信息,因此构建了内容,并且任何地方都没有拼写错误。有什么想法吗?
    【解决方案2】:

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

    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');
        }
    }
    

    然后我可以像这样在我的视图中使用它的属性(这是填充 &lt;head&gt; 元素的“元”视图):

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

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

    【讨论】:

    • 这似乎是一个不错的选择,但我并不热衷于“视图嵌入其他视图”的想法——其他视图如何获取数据?我认为这只有在包含的视图具有静态内容时才能正常工作
    • 视图只是包含,因此它们共享相同的控制器 ($this) 和变量作为基本模板。查看我如何在基本模板中包含的“元”视图中使用$this-&gt;title。我也可以在那里使用$content
    • 我在 Home 控制器中添加了一个控制器特定视图的示例。
    • 在对_output 是一个神奇的 Codeigniter 函数这一事实绞尽脑汁之后,它看起来像是一种不错的方法。所以基本上如果你想要一个新的模板/布局,你可以创建另一个 MY_New_Template 并扩展你的新控制器来使用它?我仍然不完全相信这是嵌入其他视图的好主意,因为您需要让 DATA 传递到每个视图。我认为这就是控制器的用途,不应该直接调用视图,流程应该始终是控制器 --> 获取数据 --> 传递给视图,还是我遗漏了什么?
    • @Reins 我刚刚尝试了这段代码,但遇到了一些麻烦。 _output 实际上并没有输出任何我必须做的事情 echo $this-&gt;output-&gt;get_output(); 在我得到任何输出之前。在控制器 Home 中,因为 $this-&gt;load-&gt;view('home') 它会在该点回显它,因此它会回显内容两次!
    【解决方案3】:

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

    语法很简单:

    // 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 中,这样会更容易。

    【讨论】:

      【解决方案4】:

      您考虑过模板吗?只需稍加搜索即可获得许多不错的 - 检查 CI wiki。

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

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

      【讨论】:

        【解决方案5】:

        我会创建一个 MY_Controller 来处理这一切。您可以在其顶部使用布局(模板)/导航库来生成所有布局、导航、显示/突出显示选定的菜单项、加载视图等。

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

        【讨论】:

          【解决方案6】:

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

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

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

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

          这就是我的工作:

          • 在每个控制器中,我都有 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 中的

          forth 文件看起来像:

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

          fifth 包装器是简单的结构化 HTML 中的一些 php 头(加载 html 标题、标题等...) 标头/标头(如果传递的 $data['view']['headers'] 变量/数组中有任何标头,则加载标头) 布局(在布局文件中加载,只有新的 html 结构化文件和下一级加载文件) 页脚/页脚(如果传递的 $data['view']['footers'] 变量中有任何页脚,则加载页脚) 脚本(在标签之前加载诸如分析/facebook 脚本之类的 inscript)

          sixth 因此,同样,布局也会加载到 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. $this->load->view('main',$data);

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

          3. 再次使用 $data['view']['layout'] 中的数据在包装器中进一步加载其他更深层次的结构,如布局...
          4. 布局,使用相同的 $data['view']['mainbar'], $data['view']['sidebar'] 并捕获其他重要部分以加载,例如主栏模板,侧边栏模板...李>

          就是这样……

          附言我很抱歉没有使用数字,但是 stackoverflow 系统太奇怪了,它没有显示 3,而是显示 1.. 如您所见,我有一些嵌套列表...

          【讨论】:

            【解决方案7】:

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

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

            对于更好的模板,您可以将小节放在单独的文件中,并且大模板包含它们:

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-02-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多