在 MVC 中处理 $_POST 数据的正确方法是啥?

Posted

技术标签:

【中文标题】在 MVC 中处理 $_POST 数据的正确方法是啥?【英文标题】:What is the right way to handle $_POST data in MVC?在 MVC 中处理 $_POST 数据的正确方法是什么? 【发布时间】:2012-11-01 19:51:20 【问题描述】:

我的 php 系统中有常见的 MVC 情况:Controller 收到来自 View 的请求,其中包含 $_POST 数据。现在我有三种方式来处理数据:

a) Controller 只调用ModelModel 处理$_POST 数据。 b) Controller$_POST 数据转换为变量并将它们传递给Model。 c) Controller$_POST 数据转换为Model 的域对象,并且只将对象传递给Model

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

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

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

编辑2一般来说,同一个Controller处理来自浏览器、网络服务、离线应用等的请求,还是每个都有自己的Controller

【问题讨论】:

Symfony2 主要遵循选项 C,因为它的价值。 我通常更喜欢第二个选项。所有数据处理都应该只在控制器中完成,并且应该只将所需的数据传递给模型或视图.. 【参考方案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() 之类的东西 - 尽管我得出的结论是,在结构正确的应用程序中,GETandPOSTparameters 应该不共享同名。

您在代码 sn-p 中看到的serviceFactory 将是您在控制器和视图实例中注入的对象。它可以让您在控制器和视图之间共享相同的服务实例。

它负责创建services(其中将包含应用程序逻辑,而将域业务逻辑留在domain objects中),它可以帮助您隔离域实体之间的交互和表示层的存储抽象。

关于其他选项:

Controller 只调用 Model,Model 处理 $_POST 数据。

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

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

Controller 将 $_POST 数据转换为 Model 的对象,并且只将对象传递给 Model

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

结束语:

您必须了解的一点是,在基于 Web 的 MVC 应用程序的上下文中,您的应用程序的 User 是浏览器。不是你。浏览器发送请求,请求由路由机制处理,由控制器传播。并且视图产生响应到您的浏览器

另一件事是:模型既不是类也不是对象。 Model is a layer。


更新

一般来说,同一个Controller处理来自浏览器、Web服务、离线应用等的请求,还是每个都有自己的Controller?

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

要做到这一点有两个条件:

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

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

在您所描述的情况下,更改部分实际上是视图,因为 REST 或 SOAP 服务预计会产生与普通 Web 应用程序不同的响应。

【讨论】:

最佳实践是什么? a) 将domainModelFactorydataMapperFactory 注入ServiceFactory b) 将domainModelFactorydataMapperFactory 直接注入Service,类似于$this->domainModelFactory->create('user')。 ? 最佳实践是使用 DI 容器。【参考方案2】:

曾几何时是三层应用架构。

这完全取决于您的 MVC 框架。通常,Controller 负责用户和模型层之间的链接,模型层操作域对象。

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

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

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

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

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

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

请求首先变成一个对象 该对象是使用路由对象路由的 它由控制器处理 控制器将请求传递给操作所涉及的服务,从而构建响应对象

服务作业随后分几个步骤中断:

验证(使用依赖于单独文件中描述的规则的专用对象), 域对象的构造/更新(必要时使用到/从 db 的序列化), 为响应选择模板, 使用来自域的相关数据填充所述模板。

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

请参阅this question 以更好地了解一般概念。

其他答案请参见this other question。

感谢tereško 对此事的宝贵意见。

【讨论】:

“清理可能是一个控制器任务” -> 模型 @cyril 您如何处理影响多个模型的操作?【参考方案3】:

我正在使用 Zend 并关注

第二个选项。

注册表单示例

第 1 步表单将 post 值发送给指定的控制器

步骤 -2 我将通过服务器端验证来验证表单值(例如邮件和 url 以及空帖子值)。

步骤 -3 将检查过的帖子数据以变量或完整的形式发送到模型。

第 4 步- 控制器调用模型。

步骤 -5 模型插入帖子值并创建新用户。

无论您使用何种框架或方法,我认为您的第二个选项会更好。

注意 - 同一个控制器可以处理任何事情取决于您的应用程序逻辑。

 but i prefer to keep different controller for differnt user request and user types

 it helps in keeping code readable managebale .

【讨论】:

MVC 中的控制器不应该负责验证 我相信控制器也应该进行验证,就像第一个表单将验证输入(视图)然后将其发送到(第二)控制器,该控制器还将仔细检查(控制器)并(第三)将其发送到我们所在的模型如果我们愿意,可以添加一些验证。但是如果我们在第一个实例中进行验证,则可以避免使用控制器,但我更喜欢一直使用它进行验证。【参考方案4】:

看看一些 MVC 框架。

例如,在 Yii 中,您可以在 action 中编写这样的代码:

$model = new Model();
if(isset($_POST['Model'])) 
    $model->attributes = $_POST['Model'];

请注意,您的模型的所有attributes 都必须通过验证规则。在 Yii 中验证适用于(实际上是之前)$model->save()

见:

    http://www.yiiframework.com/doc/guide/1.1/en/form.model#securing-attribute-assignments http://www.yiiframework.com/doc/guide/1.1/en/basics.mvc

【讨论】:

【参考方案5】:

'C' 是最好的选择。您不应该让原始 $POST 数据进入模型,因为模型应该主要是通用处理存储和加载操作。

示例:可以使用相同的模型来使用 Web 界面和 Web 服务。在 Web 上 $_POST 有效,但对于 Web 服务则无效。所以模型不关心如何接收数据,只关心如何存储和加载。

Yii 绝对是 MVC 的干净实现。

【讨论】:

以上是关于在 MVC 中处理 $_POST 数据的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

MVC 3 Razor Form Post w/ 多个强类型的部分视图不绑定

MVC的使用方法!

使用带有 mvc 的 jQuery 数据表服务器端处理。序列化条件表单并将此参数添加到 $ajax.post 方法

处理HTTP Post的正确方法,然后通过HTTP下载,然后保存到核心数据

在 MVC 4 应用程序中正确处理 HttpAntiForgeryException 的方法

重定向处理时如何通过 $_POST 将表单错误发送回表单