这两条经常被提及的 MVC 建议似乎相互矛盾:
- 视图中没有 for 循环或条件逻辑
- 除了视图,其他地方都没有 HTML
假设我有 $items 必须作为无序列表输出。迭代逻辑不是必须有html吗?在这种情况下,我应该把它放在哪里?
在我看来,可重用性主张把它放在视图以外的地方,同时为模板作者提供标签、类等参数。
你怎么看?你为什么这么认为的实际原因是非常受欢迎的。
这两条经常被提及的 MVC 建议似乎相互矛盾:
假设我有 $items 必须作为无序列表输出。迭代逻辑不是必须有html吗?在这种情况下,我应该把它放在哪里?
在我看来,可重用性主张把它放在视图以外的地方,同时为模板作者提供标签、类等参数。
你怎么看?你为什么这么认为的实际原因是非常受欢迎的。
在处理视图模板上的列表和表格时,您总是会遇到某种循环。您听到人们争论在模板中添加视图逻辑是一个坏主意的原因与ViewModel 范例有关。
有时仅循环遍历数据是不够的,例如:
<?php foreach( $users as $user ): ?>
<?php if ( in_array( $user->getId(), $members ) ): ?>
<!-- Users is member -->
在这种特定情况下,user entity
没有方法isMember()
来检查用户是否是成员。假设您使用的是用户实体附带的第 3 方模块,并且您不想扩展它以添加新的依赖项(例如组)。您必须在域模型之外检查这一点,以便如上例所示正确显示视图模板。
但是,在这种情况下,我们正在向视图添加逻辑:if ( in_array( $user->getId(), $members ) )
。您应该将它放在您的业务逻辑或视图逻辑中。后者是使用ViewModels实现的。因此,不是让您的视图与域模型对象交互,而是与 ViewModel 交互,后者将实现isMember()
方法并封装上述逻辑。
这种范式的主要思想是您的视图无法访问域模型,而是仅与 ViewModel 交互,从而保持视图独立于域模型。
更新
例如,如果您有设计/前端团队,您将不允许他们调用$user->setName()
,但仅$user->getName()
使用ViewModel您不会将此方法作为选项包含在内。
还有另一个例子:假设您的应用程序有皮肤/主题。如果您保留视图逻辑,就像在视图模板上的第一个示例中一样,您需要为具有类似模板的所有主题复制此逻辑。与您的模板分离后,您将避免重复的视图逻辑分布在您的视图模板中。
当然,您可以在视图中放置循环 - 您还打算如何渲染<ul>
s?:))
您也可以放置一些条件逻辑,例如根据授权状态在右上角打印“注销”与“登录”,主要在模板的共享部分中。
重点是视图层必须完全不知道它呈现的数据:他是一堆数组/对象和浏览器中呈现的实际 HTML 之间的一个造物主。提供这样的数据是控制器的事情,即做出所有的决定,过滤的东西,等等。
想想 web 服务:您可以以不同的格式渲染相同的资源 [xml、json、纯 html] - 它是从任何地方获取数据的控制器,然后视图获取它并渲染正确的文档。