在 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
只调用Model
,Model
处理$_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()
之类的东西 - 尽管我得出的结论是,在结构正确的应用程序中,GET
andPOST
parameters 应该不共享同名。
您在代码 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) 将domainModelFactory
和dataMapperFactory
注入ServiceFactory
b) 将domainModelFactory
和dataMapperFactory
直接注入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 的 jQuery 数据表服务器端处理。序列化条件表单并将此参数添加到 $ajax.post 方法
处理HTTP Post的正确方法,然后通过HTTP下载,然后保存到核心数据