【问题标题】:Including header, menu, and footer in controllers在控制器中包含页眉、菜单和页脚
【发布时间】:2014-08-05 12:08:34
【问题描述】:

我正在创建自己的原始 MVC(或某些人可能称之为 MVP)框架,我想知道在我的控制器中包含页眉、页脚和其他任何内容的最佳实践方式。

目前,我在 每个 控制器的末尾执行以下操作:

class Index extends Controller
{
    public function index()
    {
        $hData = array(
            'title'       => 'Home',
            'stylesheets' => array(
                'style1.css',
                'style2.css'
            ),
            'javascripts' => array(
                'script1.js',
                'script2.js'
            )
        );

        $cData = array(
            'heading' => 'My first PHP application',
            'message' => 'Hello, world!'
        );

        //HTML Output
        $header  = new View('/views/header.php');
        $html    = $header->fetch($hData);

        $menu    = new View('/views/menu.php');
        $html   .= $header->fetch();

        $content = new View('/views/index.php');
        $html   .= $content->fetch($cData);

        $footer  = new View('/views/footer.php');
        $html   .= $footer->fetch();

        echo $html;
    }
}

我做得对还是有更好的方法?如果是这样,我将不胜感激。

【问题讨论】:

  • imo,“控制器”更像是“经理”。它要求其他人“用适当的页眉和页脚显示内容”,而不是自己做。它需要知道在什么情况下需要调用哪个“视图”。 “视图”和“模型”决定内容。
  • 我认为没有项目规范很难回答这个问题。如果您正在为 1.000.000 个用户构建应用程序,那么当您为 100 个用户构建应用程序时,您将有其他要求。根据我的经验,我可以告诉你,如果你正在构建一个巨大的应用程序,你需要一个更复杂的框架。除了框架架构问题,我想给你一些建议,让你看看 SPA。 IMO 这就是未来。 AngularJS 是一个不错的入门框架。如果您想编写自己的 SPA 框架,请确保您对 JS(内存泄漏)有足够的了解

标签: php controller include footer


【解决方案1】:

一般来说,自己构建 MVC 框架会迫使你接受一些妥协。但这是我的想法:

  1. 您应该有一些模板引擎(理想情况下,可能是可替换的)。它可以只是 PHP,也可以是一些已经存在的(Twig、Smarty)

  2. 控制器应该只知道模板引擎将呈现的特定视图。因此,视图应该可以通过名称而不是通过模板文件的具体路径获得。

  3. 模板引擎应该知道如何将模板名称解析为真正的模板文件。

  4. 模板引擎应该能够接受模板的变量,这些变量可以从控制器传递给它。

  5. 包括页眉、页脚等,应由您的模板引擎或在您的模板中考虑,而不是在您的控制器中。例如,您的代码可能支持显示部分内部 html 的 AJAX 调用。在这种情况下,模板的名称可以相同,但根据从控制器传递的一些 var,模板引擎(或模板本身)可以显示正常请求的页眉和页脚,而对于 ajax 请求则省略它们。

  6. 当然,以硬编码的方式定义要在模板中加载哪些 css 文件不是控制器的任务。但是,可能有一些系统设置可以在控制器中读取,然后作为变量传递给模板。

2 和 3 可以是可选的,如果您不需要额外的灵活性,或者您很确定以后不需要切换到 Smarty 或 Twig。

【讨论】:

    【解决方案2】:

    MVC 是专门为分离功能而设计的。

    模型 - 将此视为您的应用程序层。当您设计模型时,它就是应用程序本身。你需要什么内容?这通常以原始形式返回。数组、对象、JSon等

    视图 - 视图是您提供数据的方式。 PHP 是一个很棒的模板引擎,但还有其他一些引擎,例如 SmartyTwig,它们基于 PHP 并且专为模板设计。看看他们,看看你的想法。我个人使用 Smarty,并且正在研究 Symfony(一个使用 Twig 获取视图的 MVC 框架)来开发一个潜在的未来项目。但是很多人说单独使用 PHP 就可以了。各有利弊。

    控制器 - 控制器告诉程序做什么和去哪里。这是您的业务逻辑层。您的 Front Controller 位于您的模型和视图之间,以便将正确的内容放在正确的位置。

    因此,在考虑页眉和页脚时,请考虑它们所属的位置。最后,因为这是一个模板和图像的问题,它可能最适合在视图中。

    编辑:视图示例

    如果您选择使用 PHP 作为您的模板,您可以从非常基本(难以扩展)一直到从头开始高度动态的面向对象的模板引擎。根据您的项目范围,我将再次强烈建议您至少看看 Smarty 或 Twig 作为一个选项。

    简单模板:用户资料 模板可以像这样简单:

    <?php include("header.html.php");
     /*I am using .html because you can also create .xml views.
          The beauty of MVC is you can create multiple views with 
          the same model, just having your controller direct 
          to the correct view. */ ?>
    <!-- Your content here -->
        <div id="userPicture"><img src="<?php echo $userPictureLocation; ?>"></div>
        <div id="userDetails">
            <div id="userName">
                <span class="key">Name:</span>
                <span class="value"><?php echo $userNameValue; ?></span>
            </div>
            <div id="userBio">
                <span class="key">Bio:</span>
                <span class="value"><?php echo $userBioValue; ?></span>
            </div>
        </div>
    <!-- End Content -->
    <?php include ("footer.html.php"); ?>
    

    使用这个非常简单且难以维护的模板系统,您可以在前端控制器中简单地使用include $file;

    如果您想创建面向对象的视图而不使用 Smarty 或 Twig 之类的模板引擎,那么您将寻求创建自己的对象类。您可能可以查看 Smarty 和/或 Twig 的功能,以了解需要什么。它正在重新发明轮子,但重新发明轮子是一个很好的学习工具。但是,您可以做的一个非常简单的初始操作是添加一个具有函数setValue()getValue()load() 的模板类。 load()setValue() 可以在您的模板中使用,getValue() 可以在您的模板中使用。

    class template {
        private $values;
    
        public function __construct() {
            $this->values = array();
        }
    
        public function setValue($key, $value) {
            $this->values[$key] = $value;
        }
    
        public function getValue($key) {
            return $this->values[$key];
        }
    
        public function load($file) {
            //The APPLOCATION constant below would be under a configuration
            //file define('APPLOCATION','/var/www/html/'); or whatever your app location
            //is. A Registry Class is probably a better bet for a large application and is
            //the best practices way to do it.
            include APPLOCATION . "template/{$file}";
        }
    }
    

    这个类非常轻量级但也可以添加。它可以防止一些更严重的复制,并且可以通过有限的努力进行扩展。

    再说一次,我们之前看过的模板,这次是 Template 对象。

    <?php 
    //In this example I am assuming you declared a new Template 
    //in your Controller and assigned it the value of $template.
    $template->load("header.html.php");
    ?>
    <!-- Your content here -->
        <div id="userPicture"><img src="<?php echo $template->getValue('userPictureLocation'); ?>"></div>
        <div id="userDetails">
            <div id="userName">
                <span class="key">Name:</span>
                <span class="value"><?php echo $template->value('userNameValue'); ?></span>
            </div>
            <div id="userBio">
                <span class="key">Bio:</span>
                <span class="value"><?php echo $template->value('userBioValue'); ?></span>
            </div>
        </div>
    <!-- End Content -->
    <?php $template->load("footer.html.php"); ?>
    

    【讨论】:

    • 您能否提供一个您的答案中描述的视图示例?
    【解决方案3】:

    您是否考虑过创建一个 printView 方法来获取您的两个参数并将其包装起来?如果您真的想这样做,那么如果脚本不会更改,则没有理由需要指定脚本。比如:

    class Controller {
    
        // Protected makes it visible to children, but not to callers
        protected function printHTML($bodyPage, $bodyData = array(), $altHeaders = array()){
            $defaultHeaders = array(
                'title'       => 'Home',
                'stylesheets' => array(
                    'style1.css',
                    'style2.css'
                ),
                'javascripts' => array(
                    'script1.js',
                    'script2.js'
                )
            );
            $trueHeaders = array_merge_recursive($defaultHeaders, $altHeaders);
    
            $header  = new View('/views/header.php');
            $html    = $header->fetch($trueHeaders);
    
            $menu    = new View('/views/menu.php');
            $html   .= $header->fetch();
    
            $content = new View($bodyPage);
            $html   .= $content->fetch($bodyData);
    
            $footer  = new View('/views/footer.php');
            $html   .= $footer->fetch();
    
            echo $html;
       }
    }
    
    class Index extends Controller {
        public function index() {
            $this->printHTML(
                '/views/index.php',
                array(
                    'heading' => 'My first PHP application',
                    'message' => 'Hello, world!'
                ),
                array(
                    'title' => 'My Index Page',
                    'stylesheets' => array(
                        'style3.css'// Will use styles 1, 2 and 3 because we merge the array recursively.
                    )
                )
            );
        }
    }
    

    【讨论】:

    • 每个控制器的脚本和样式表可能不同。
    • @KidDiamond 这就是为什么你只包含常量的东西(jquery 和基本布局或其他东西),然后每个页面都可以定义它自己的添加到列表中,就像它可以覆盖标题一样。
    【解决方案4】:

    创建一个名为 layout 的文件夹并放置一个名为 Header 的文件和一个名为 footer 的文件,并将所有标签放置到您的内容 div 之前,然后在 header.php 之后需要来自 View.php 的视图文件,然后放置您的 footer.php 和在文件之后需要并关闭所有标签。我就是这样做的。

    【讨论】:

      猜你喜欢
      • 2015-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-01
      • 1970-01-01
      • 2017-01-20
      • 1970-01-01
      相关资源
      最近更新 更多