0

我使用术语“部分”来指代在许多视图中重复的一小部分演示代码。例如,侧边栏。在 vanilla PHP 中,业务和表示逻辑混合在一起,包括一个侧边栏是没有问题的:

if($someCondition) {
    include('sidebar.php');
}

但是,在 MVC 设计模式中,表示逻辑必须保留在视图中,而业务逻辑必须保留在控制器中。如果我希望无条件地包含一个部分,那么这是没有问题的,因为我可以include('sidebar.php')在我看来。但是,我不能再有条件地这样做,因为如果我认为逻辑被禁止的话。

我尝试了许多解决方案,但它们都有问题。我目前正在使用解决方案 2:

解决方案 1

在我的视图类中创建一个包含函数,它可以有条件地包含来自我的控制器的内容。所以在我的控制器中,我可以有以下逻辑:

if($someCondition) {
    $this->view->include('sidebar.php');
}   
$this->view->show('index.php');

问题: sidebar.php 需要在特定点包含到 index.php 中,这需要视图对象上的 include 方法进行某种解析。

解决方案 2

将部分控件移出视图并将它们放入控制器中:

if($someCondition) {
    $this->view->show('header.php', 'sidebar.php', 'index.php', 'footer.php');
}
else {
    $this->view->show('header.php', 'index.php', 'footer.php');
}

问题:将大部分表示逻辑移动到控制器领域。对我来说,决定是否包含标题似乎更自然。事实上,我能找到的每个 PHP MVC 教程都有部分在视图而不是控制器的控制下。

解决方案 3

复制视图并更改克隆,使其包含侧边栏。然后我可以有条件地在控制器中加载一个或另一个:

if($someCondition) {
    $this->view->show('indexWithSidebar.php');
}
else {
    $this->view->show('index.php');
}

问题:代码重复。考虑一下如果我有 2 个需要有条件加载的侧边栏会发生什么。然后我需要index.php, indexWithSidebar1.php, indexWithSidebar2.php, indexWithSidebar1And2.php. 这只会在每种情况下变得更糟。请记住,将侧边栏作为部分取出的全部目的是为了避免复制它,而这种方法似乎违背了这一点。

这些解决方案中的任何一个都是“正确”的解决方案吗?如果是,我该如何克服他们的问题?那里有更好的方法吗?

4

2 回答 2

1

让您的控制器评估条件并将结果传递给您的视图。然后,视图可以决定是否包含部分。

例如,控制器可以检查变量 ,$foo是否不为空。它通过模型的属性将比较结果传递给视图$model->isFooed。在这种情况下,视图可以根据 的值显示侧边栏$model->isFooed

于 2010-08-31T19:05:25.327 回答
1

但是,在 MVC 设计模式中,表示逻辑必须保留在视图中,而业务逻辑必须保留在控制器中。

恕我直言:从架构的角度来看,我将我的业务逻辑推到更远的地方,远离控制器。我们使用服务来处理所有业务逻辑和存储库以进行数据检索。服务调用存储库,然后将我们的数据模型与为我们决定的所有业务逻辑一起传回。真正的 UI 逻辑之外的任何逻辑(显示这个,隐藏那个),因为我们返回的数据可以(应该能够)在任​​何类型的应用程序中使用,无论是移动应用程序、Windows 应用程序还是 Web 应用程序。

您可以为您的控件使用扩展帮助器方法,如果您不希望呈现侧边栏,则可以在部分模型中返回 EmptyResult()。或者,更简洁地说:

<% Html.RenderAction<MyController>(x => x.Sidebar({params})); %>

然后在控制器中:

public ViewResult Sidebar({params})
        {
            SidebarModel model = new SidebarModel();

            //...get/build model

            if ({someCondition})
            {
                return View("MySidebarPartialView", model);
            }


            return new EmptyResult();

        }
于 2010-08-31T19:28:38.473 回答