CakePHP 3中的MVC - 模型和视图之间的关注点分离

时间:2016-06-01 12:56:51

标签: php cakephp model-view-controller cakephp-3.0

这是关于MVC的一般性问题,但上下文是CakePHP。

Cake文档在很大程度上避免了讨论与模型相关的代码的最佳放置,例如查询。也许为了简单起见,或者为了避免对开发人员如何构建他们的应用程序强加任何想法,他们只是总是将查询记录在控制器中。基本上,一个胖控制器模式。

e.g。

该页面需要4个大型查询才能在视图“XYZ”中显示不同的数据区域。查询的最终结果是一组非常具体的数据,仅用于视图XYZ。

Fat Controller

  • 控制器处理请求
  • Controller在模型1上运行查询
  • Controller在模型2上运行查询
  • Controller在模型3上运行查询
  • Controller在模型4上运行查询
  • Controller对数据执行其他逻辑
  • Controller发送数据以查看XYZ

在这种情况下,控制器正在完成所有工作,并且只是利用Cake的内置模型框架功能来查询正确的表。模型层本身不包含自定义代码。

所以替代方法是使用Fat Model模式,但是我觉得这也不正确,特别是在模型确定将哪些数据发送到视图的情况下。

脂肪模型

  • 控制器处理请求
  • 控制器调用模型1以检索数据
  • 模型1查询并对数据执行其他逻辑,然后发送回Controller
  • 控制器调用模型2以检索数据
  • 模型2查询并对数据执行其他逻辑,然后发送回Controller
  • 控制器调用模型3 ...
  • 控制器呼叫模型4 ......
  • Controller发送数据以查看XYZ

这使控制器保持良好和干净,它只用于处理请求,委托检索所需的数据,然后将其转发到视图。

对我来说,问题在于模型层(可能在表类中)现在包含非常特定的查询,这些查询检索专门为视图XYZ格式化的数据。如果我想更改视图XYZ中显示的数据,我可以通过修改返回视图所需字段的方法在模型层中进行这些更改。

这似乎是错误的,导致大型模型臃肿,具有大量特定功能。

问题

  • 哪种方法更好?
  • 是否有第三种解决方案可以解决以下问题:

控制器

  • 处理请求
  • 决定视图需要哪些数据,但将作业委托给模型
  • 将数据从模型转发到视图
  • 保持敏感

模型

  • 处理所有业务逻辑和数据库查询
  • 数据库查询逻辑不知道视图需要什么
  • 特定视图的特定一次性功能不会膨胀

是否有另一层可以弥合控制器和模型表之间的差距,还是没有意义?在Cake环境中它会是什么?表或实体之外的自定义类?我完全理解模型层不仅仅意味着活动记录或数据库查询。

2 个答案:

答案 0 :(得分:1)

  

Cake文档在很大程度上避免讨论与模型相关的代码的最佳放置,例如查询。

这不是必需的,也不是框架的责任,教育人们关于设计模式 - 恕我直言。这些层次及其职责解释为here。有关更多信息,请使用Google或阅读Martin Fowlers关于设计模式的出版物。

  

或许为了简单起见,或者避免对开发人员如何构建他们的应用程序强加任何想法,

是。你可以自由地做任何你想做的事情,但是人们期望人们至少熟悉MVC,OOP和设计模式的基础知识。教授这些主题不是框架文档的工作。

  

他们只是将查询记录在控制器中。基本上,一个胖控制器模式。

谁是“他们”?我确信文档不会鼓励不良做法或反模式。

  

对我来说,问题在于模型层(可能在表类中)现在包含非常特定的查询,这些查询检索专门为视图XYZ格式化的数据。如果我想更改视图XYZ中显示的数据,我可以通过修改返回视图所需字段的方法在模型层中进行更改。

你的方法很可能会发胖而且具体。你将无法避免使用特定的方法(总有一些东西不能通用),但你应该使用许多通用的小方法来构建它们。一个方法应该只做一件事,做得好,最好不要超过~80行。

Cake3中的自定义查找器是撰写查询的好方法:

public function findIndex(Query $query, array $options = [])
    return $query->find('active')->find('index')->find('somethingElse');
}

我们的应用程序中有很多“活动”检查,因此我将活动查找器放入特征并在需要的地方使用它。其他两个查找器为查询添加了其他内容。我将三种发现结合起来,可以单独使用,也可以根据需要进行不同的组合。

在您的控制器中,然后只需致电$query = $this->Articles->find('index');并将其传递给您的分页器。

也永远不要忘记“模型”描述的是完整的图层,而不仅仅是表格对象。 Cake2可能导致经验不足的开发人员可能会得到模型== table的印象。我们在App\Model中有几个名称空间与DB操作完全无关,或者使用表对象来完成任务。

答案 1 :(得分:0)

还有用于在类和帮助程序中协作控制器代码的组件,以在类中协作视图代码。因此,为了使控制器变得苗条,您可以为每个作业添加组件并在控制器中使用它们,而不是在控制器操作中执行所有操作。

它还有另一个优点。如果您在组件中放入可重复的代码,那么您不需要在每个视图中复制它们,并且您仍然可以观察DRY(不要重复自己)原则。