我可以从视图中调用模型吗?

Bra*_*enP 6 php model-view-controller

而不是使用完整的PHP MVC,我正在设计一个最适合我的用途.我已经完成了基本框架,并编写了运行我的网站所需的模型和控制器.

现在我正在转向观点,我遇到了一个小困境.我的方法对我来说很好,但是为了将来的参考,我想知道我正在做的是一个坏习惯.

我正在做的事情:

在我的视图中,我正在调用运行我的身份验证系统的模型,并请求用户的登录状态.然后我使用该布尔值来决定是否在视图中显示某些元素,以及在何处放置其他元素.

我应该为每个登录状态设计单独的视图,还是这种方法很好?但是,如果我要将这个MVC应用到我正在为我的客户做的工作中,我需要使用最佳实践.

任何意见,将不胜感激!

Gor*_*don 16

我可以从View中调用模型吗?

是的你可以.只要您保持M,V和C之间的关注分离,您就可以从视图中调用模型(或控制器).大多数MVC图表至少在View和Model之间显示双向连接.但是你不想做的是将Model(或控制器)中的逻辑/代码放入View中,你不想从那里修改模型.

例如,您的页面上可能有一个小部件,用于汇总您网站每个页面上您最喜欢的博客的最新十个博客帖子标题.你可以通过打电话来获取头条新闻,比如MyFavFeeds::getLatest();你的模特.你现在有什么选择?

  1. 可以添加代码以将标题提取到控制器中,但这需要您在每个控制器操作中复制它,这违反了DRY原则.此外,控制器的关注点是处理特定操作的用户输入,并且在每次调用时获取标题甚至可能与这些操作无关.
  2. 如果您的架构支持它,您可以在某种preDispatch挂钩中获取该数据,也就是说,标题会从插件或回调中加载并注入到View中.这将是DRY,但是第二个开发人员可能不会意识到该插件并且意外地覆盖了控制器操作的头条新闻变量.并且可能存在您不想加载标题的情况,例如,当仅为表单提交呈现确认页面时,因此您必须具有用于禁用插件的机制.这需要考虑很多.
  3. 您将调用(不是代码)MyFavFeeds::getLatest()放入View或Layout模板中,或者更好的是ViewHelper,它封装对模型类的调用并呈现窗口小部件.这样您就不必担心覆盖任何变量或重复.当您不需要视图的标题时,您根本就不包含它.

关于你的另一个问题:

在我的视图中,我正在调用运行我的身份验证系统的模型,并请求用户的登录状态.然后我使用该布尔值来决定是否在视图中显示某些元素,以及在何处放置其他元素.

在调用任何控制器操作之前,您需要在应用程序流的早期进行身份验证.因此,您不应在View中运行(整个)身份验证系统.实际身份验证不是与视图相关的逻辑.另一方面,仅在认证后请求用户状态是可以的.例如,如果你想呈现一个显示用户名的小部件并给出一个登录/注销按钮,那么可以做一些类似的事情.

<?php //UserHelper
class UserMenuHelper
{
    public function getUserMenu()
    {
        $link = '<a href="/user/logout">Logout</a>';
        if(MyAuth::userHasIdentity()) {
           $link = sprintf('<a href="/user/logout">Logout %s</a>',
                            MyAuth::getUsername());
        }
        return $link;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您的GUI的较大部分被用户角色修改,您可能希望将View拆分为部分块并根据状态包含它们,而不是将所有HTML写入View Helper.

如果您只想基于用户角色渲染导航,请查看Zend Framework Zend_NavigationZend_Acl查看它们是如何进行的.

  • @Karsten上述方法不违反M/V分离.获取头条新闻的逻辑仍然在模型中封装.您只需绕过控制器,这在示例中是完全可以接受的,因为没有用户输入要处理.复合视图只是针对同一问题的一种不同方法,但最终你仍然只有一个视图,它就是在圆圈中运行的地方,因为这取决于你如何以及在何处进行组装.随意提供OP的答案,向他展示复合视图方法,而不是从视图中获取标题. (4认同)
  • -1:关于你的"每个页面上最喜欢的博客作为小部件"的例子,我宁愿使用View Composition而不是从View中调用Model.模型/视图分离的重量应该比这里的DRY论证重要得多. (3认同)

jak*_*xer 5

可以,但你不应该。除了一些极端情况(并且根据登录状态分支视图绝对不是“极端情况”)之外,从视图中调用模型内容几乎总是一个坏主意。

在您的情况下,您可能想要做的是将布尔值通过控制器传递给视图。这样,如果您更改了有关用户模型的某些内容,只要控制器保持行为相同,视图就不必知道。