在 MVC 中处理 _POST 美元数据的正确方法是什么?

我的PHP系统中有常见的MVC情况:从包含数据接收请求。现在我有三种方法来处理数据:ControllerView$_POST

a) 唯一调用 和 处理数据。
b) 将数据转换为变量并将其传递给 。
c) 将数据转换为 的域对象,并且仅将该对象传递给 。ControllerModelModel$_POSTController$_POSTModelController$_POSTModelModel

目前,我正在遵循选项A,但我认为这是错误的,所以我正在考虑使用选项C。

那么,根据MVC的说法,处理数据的正确方法是什么?$_POST

编辑目前,我没有使用任何MVC框架。

编辑 2通常,相同的处理来自浏览器,Web服务,脱机应用程序等的请求,或者每个应用程序都有自己的?ControllerController


答案 1

最好的选择是使用#2方法,并进行一些更改。
我会把它写成这样:

public function postLogin( $request )
{
     $service = $this->serviceFactory->build('Recognition');
     $service->authenticate( $request->getParam('username'),
                             $request->getParam('password') );
}
// Yes, that's the whole method

如果您已经使用类似实例的东西来抽象用户的输入,则无需实际创建变量。Request

另外,您可能希望将Request::getParam() 方法替换为Request::getPost()-尽管我得出的结论是,在结构正确的应用程序中,GETPOST参数不应共享相同的名称。

您在代码片段中看到的将是您在控制器和视图实例中注入的对象。它允许您在控制器和视图之间共享相同的服务实例。serviceFactory

它负责创建服务(将包含应用程序逻辑,同时将域业务逻辑保留在域对象中),这有助于您将域实体和存储抽象之间的交互与表示层隔离开来。

关于其他选项:

  • 控制器仅调用模型,模型处理 $_POST 数据。

    在 MVC 和 MVC 启发的设计模式中,模型既不应了解用户界面,也不应了解整个表示层。PHP 中的变量是一个超全局变量$_POST

    如果将其与模型层一起使用,则代码将绑定到 Web 界面,甚至绑定到特定的请求方法。

  • 控制器将_POST美元数据转换为模型的对象,并仅将对象传递给模型

    不完全确定你的意思。似乎您正在谈论抽象的实例化,它将包含用户的请求。但在这种情况下,控制器负责实例化/创建所述结构,这将违反SRP

结束语:

您必须了解的一件事是,在基于Web的MVC应用程序的上下文中,应用程序的用户是浏览器。不是你。浏览器发送请求,该请求由路由机制处理并由控制器传播。视图会生成对浏览器的响应。

另一件事是:模型既不是一个类,也不是一个对象。模型是一个层


更新

通常,同一个控制器处理来自浏览器,Web服务,离线应用程序等的请求,或者每个控制器都有自己的控制器?

您应该能够拥有单个控制器,该控制器处理所有形式的应用程序。但这只是在条件上,您实际上对所有3个用例使用相同的应用程序。

为此,有两个条件:

  • 您需要抽象实例,该控制器接收Request
  • 视图应在控制器外部实例化

这样,您就可以有一个应用程序来满足所有要求。每个变体都有不同的唯一一件事是引导阶段,您可以在其中创建实例并选择正确的视图。Request

在您描述的情形中,更改部分实际上是视图,因为 REST 或 SOAP 服务应生成与普通 Web 应用程序不同的响应。


答案 2

曾几何时是三层应用程序体系结构。

这完全取决于您的 MVC 框架。通常,控制器在用户和模型层之间执行链接,模型层操作域对象。

在PHP中MVC的早期,模型层实际上只是域对象,为此目的称为模型。有些人更喜欢所谓的精简模型,它只提供数据的OO表示(这简化了持久性)。在这种情况下,控制器将重新组合所谓的操作,包含与HTTP请求(胖控制器)关联的大部分处理。

其他人使用专用方法(脂肪模型)将大部分所述处理嵌入到对象模型中。

但是,在某些时候,您必须分析查询的内容以对其进行清理和验证,这取决于您的视图将如何格式化请求。清理可能是控制器任务(此请求应仅包含这些值),而验证肯定是模型任务(值应为这些类型)。

一个有趣的问题是:如何处理影响多个域对象的操作?你把逻辑放在哪里?

如今,模型层由服务组成,将域对象与控制器的邪恶把握隔离开来,以将层之间的依赖关系限制在各自的接口上。这是大多数请求处理完成的地方。

例如,Symfony2为这个问题提供了一个合理的答案:处理请求的每个步骤都在一段专用代码中实现,可以描述如下:

  • 请求首先转换为对象
  • 该对象是使用路由对象路由的
  • 它被处理到控制器
  • 控制器将请求传递给操作相关的服务,后者构建响应对象

然后,服务作业将分几个步骤中断:

  • 验证(使用依赖于单独文件中描述的规则的专用对象),
  • 域对象的构造/更新(如有必要,使用与 db 之间的序列化),
  • 为响应选择模板,
  • 所述模板的人口与来自域的相关数据。

CakePHP是另一个流行的框架,它遵循类似的概念:简单的控制器和封装域对象的服务。

请参阅此问题,以更好地了解一般概念。

有关其他答案,请参阅此其他问题

感谢Tereško对此事的宝贵投入。


推荐