当部分依赖于业务逻辑时,应该如何加载部分?

时间:2010-08-31 18:54:23

标签: php model-view-controller view controller partials

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

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

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

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

解决方案1 ​​

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

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。每种情况都会变得更糟。请记住,将侧边栏视为局部的整个要点是避免复制它,这种方法似乎打败了这一点。

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

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

  

然而,在MVC设计模式中,   必须保持表象逻辑   业务逻辑的视图   必须保存在控制器中。

恕我直言:从架构的角度来看,我将业务逻辑推回到控制器之外。我们使用服务来处理所有业务逻辑和存储库以进行数据检索。服务调用存储库,然后传回我们的数据模型,其中包含为我们决定的所有业务逻辑。外面的任何逻辑都是真正的UI逻辑(显示这一点,隐藏它),因为我们的返回数据可以(应该可以)用于任何类型的应用程序,无论是移动应用程序,Windows应用程序还是Web应用程序。 / p>

您可以为控件使用扩展辅助方法,如果您不希望渲染侧边栏,则可以在partial的模型中返回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();

        }