将数据从 MVC 控制器传递到 PHP 中的视图

Posted

技术标签:

【中文标题】将数据从 MVC 控制器传递到 PHP 中的视图【英文标题】:Passing data from MVC Controller to View in PHP 【发布时间】:2010-10-31 05:26:48 【问题描述】:

对于我正在从事的一些项目,我有自己的手动 php MVC 框架。当我第一次创建框架时,它是在构建管理 CMS 的上下文中。因此,模型、视图和控制器之间存在非常好的一对一关系。您在数据库中有一行,它映射到一个模型。控制器加载模型并将其传递给要渲染的视图(例如进入编辑表单)。漂亮、干净、简单。

但是,现在我在网站的前端工作,事情变得棘手。页面并不总是单个模型的视图。它可能是一个包含 20 个用户(每个用户模型)的用户目录列表。此外,可能还有关于请求的元数据,例如分页(当前页、总页数、结果数)和/或搜索查询。

我的问题是,将所有这些数据传递给视图的最简洁的方法是什么?

我正在考虑的一些选项:

让控制器创建一个数组并将其作为单个参数传递给视图:

class UserController

    public function renderView()

        // assume there's some logic to create models, get pagination, etc.
        $data = array()
        $data['models'] = $models; 
        $data['currentPage'] = $current;
        $data['totalPages'] = $total;
        return $view->render($data);
    


class UserView
    public function render($data)
        // render the data
    

在视图类中创建属性并让控制器填充它们:

class UserView
    public $models;
    public $currentPage;
    public $totalPages;


class UserController

    public function renderView()

        // assume there's some logic to create models, get pagination, etc.
        $view = new UserView();
        $view->models = $models; 
        $view->currentPage = $current;
        $view->totalPages = $total;
        return $view->render();
    

为视图提供某种通用 HashMap 或 Collection 对象作为容器,可以容纳任意数量和名称的数据。

class UserView
    public $collection = new Collection(); // works like a Java collection


class UserController

    public function renderView()

        // assume there's some logic to create models, get pagination, etc. 
        $view = new UserView();
        $view->collection->add($models,'models');
        $view->collection->add($currentPage,'currentPage');        
        return $view->render();
    

我知道从技术上讲,任何一个都可以工作,但我不确定最佳选择,或者我是否缺少更好或更传统的选择。

【问题讨论】:

【参考方案1】:

我将推荐Fat Models, Skinny Controllers 的概念(或者,如果您愿意的话,Fat Models Thin Controllers...)

换句话说,您的模型过于严格 - 将您的模型绑定为仅表示 RowDataGateway 之类的东西是非常有限的。

事实上,我认为好的模型完全隐藏了您正在从数据库中读取数据的事实。因为,实际上,您的数据可能位于文本文件中,也可能来自 Web 服务或其他任何东西。如果您将您的模型视为一个美化的 DBAL,那么您注定要在控制器中使用紧密耦合的代码,这不会让您摆脱“数据仅来自数据库”的思维方式。

【讨论】:

有趣的是,在我发布这个问题之前,我刚刚阅读了 Jamis Buck 关于胖模型的文章,但我没有意识到谷歌搜索这个概念会返回如此丰富的概念资源。我以为这只是他自己的小哲学。感谢您的提示。 好文章 :-) 我不确定我是否完全同意 Fat Models 的想法。我认为模型应该只是一个模型,具有作用于自身的方法(以单数形式)。换句话说,像 FindPeople() 这样的方法不适合。然而,我完全同意瘦控制器的好处。输入服务层的参数。现在我对此知之甚少,也不会声称自己是专家,但我认为值得指出。是的,它会增加新层的额外复杂性,但控制器可以调用例如 PeopleService::FindPeople() 模型本身可以是多层的。一些开箱即用的框架已经带有多层模型。例如,Symfony 带有一个 DBAL 和一个 ORM,它用推进任务搭建起来。 ZF 为我们提供了表和行网关,并留给我们应用领域模型。我建议在这里阅读 Bill Karwin 的文章 karwin.blogspot.com/2008/05/activerecord-does-not-suck.html - 顺便说一下,他也是***的 SOer。 这是一个很好的建议,只要“胖模型”指的是代码的,而不是对象类。太多人忘记了MVC 代表应用程序的三个不同,不一定是三种不同类型的对象。【参考方案2】:

我已经看到在流行的 MVC/模板框架中实现的前两种方法。

django 使用第一种方法,将变量字典传递给视图,视图使用该字典填充模板。

smarty 使用第二种方法,创建一个 Smarty 对象并为容器中的每个属性分配值。

您的第三种方法似乎与第二种方法基本相同,只是架构略有不同。

真的,我想我还没有说任何你还没有想到的事情。基本上,这些都是听起来不错的想法,所以实施你觉得最舒服的任何东西。

【讨论】:

【参考方案3】:

在我使用的那个中,它自动在控制器中有一个视图属性,您可以访问视图上的方法和属性。然后可以在视图视图“$this”中访问所有公共属性,因为视图是在它自己的对象上下文中呈现的。

在控制器中:

$this->view->myVar = 'test';

在视图中:

$this->myVar; // 'test'

布局也是如此,因为它们都是同一视图对象的独立实例:

$this->layout->myVar = 'test';

然后在布局中:

$this->myVar; // 'test'

该框架曾经是专有的,但即将向公众发布。如果您认为这会有所帮助,我很乐意将其中的一些代码发送给您。请记住,最简单的答案通常是最好的答案。

【讨论】:

这正是我在第二个示例中所考虑的。我保持代码示例简单,所以我忽略了我的控制器确实有一个视图实例,因此会完全按照你的建议工作: $this->view->foo = 'bar' 什么让我不舒服关于这个选项的一点是,我有一个 View 类,可以呈现同一模型的 5 个不同视图。每个视图都可以有自己的数据需求。这意味着 View 类将有一堆属性,其中只有少数与任何一个视图相关。这没有我想要的那么干净。有什么建议吗? 在我上面的例子中,我注意到布局和视图都是独立的实例。您可能希望创建多个视图对象,而不是使您的视图成为单例。这样,视图是与布局不同的实例,并且您在每个实例上设置的属性彼此独立。因为你可以有多个实例,你也可以有不同的助手路径、视图路径等,所以某些助手只对某些视图可用,就像属性一样。它允许更高级别的自定义(如果需要)以及逻辑组织。

以上是关于将数据从 MVC 控制器传递到 PHP 中的视图的主要内容,如果未能解决你的问题,请参考以下文章

如何将数据从剃刀视图传递到 mvc3 中的控制器?

ASP.Net MVC 将数据从视图传递到不同文件夹中的控制器

将输入值从控制器传递到 MVC 中的视图

将模型和额外参数从视图传递到 MVC 中的操作

iOS MVC - 如何将数据从模型传递到控制器?

在 MVC 中将数据从视图传递到控制器时,数据列表变为空