I have the common MVC situation in my PHP system: the Controller
receive a request from the View
containing $_POST
data. Now I have three ways to handle the data:
在我的PHP系统中,我有一个常见的MVC情况:控制器接收来自包含$_POST数据的视图的请求。现在我有三种处理数据的方法:
a) The Controller
only calls the Model
and the Model
handle the $_POST
data.
b) The Controller
transforms the $_POST
data into variables and pass them to Model
.
c) The Controller
transforms $_POST
data into a Model
's domain object and only pass the object to Model
.
a)控制器只调用模型,模型处理$_POST数据。b)控制器将$_POST数据转换为变量并将其传递给模型。c)控制器将$_POST数据转换为模型的域对象,只将对象传递给模型。
Currently, I am following option A, but I believe it is wrong, so I am thinking of using option C.
目前,我选择的是选项A,但是我认为是错误的,所以我在考虑使用选项C。
So, according to MVC, what is the right way to handle $_POST
data?
那么,根据MVC,处理$_POST数据的正确方法是什么?
EDIT At the moment, I'm not using any MVC framework.
目前,我没有使用任何MVC框架。
EDIT 2 Generally, the same Controller
handles request from a browser, a web service, an offline application, etc, or each one has it own Controller
?
编辑2一般来说,同一个控制器处理来自浏览器、web服务、离线应用程序等的请求,还是每个控制器都有自己的控制器?
5 个解决方案
#1
24
The best option is to use #2 approach, with some alterations.
I would write it as something like this:
最好的选择是使用#2方法,并进行一些修改。我会这样写:
public function postLogin( $request )
{
$service = $this->serviceFactory->build('Recognition');
$service->authenticate( $request->getParam('username'),
$request->getParam('password') );
}
// Yes, that's the whole method
There is no need to actually create variables, if you have used something like a Request
instance to abstract the user's input.
如果您使用了请求实例之类的东西来抽象用户的输入,则不需要实际创建变量。
Also, you might want to replace the
Request::getParam()
method with something likeRequest::getPost()
- although I have come to the conclusion that, in a correctly structured application, theGET
andPOST
parameters should not share same name.另外,您可能想要用likeRequest::getPost()来替换theRequest::getParam()方法——尽管我得出的结论是,在一个正确的结构化应用程序中,getandpostparameters不应该共享相同的名称。
The serviceFactory
which you see in the code snippet would be an object that you inject in both controller and view instance. It would let you share same service instances between controllers and views.
您在代码片段中看到的serviceFactory将是您在控制器和视图实例中注入的对象。它允许您在控制器和视图之间共享相同的服务实例。
It is responsible for creation of services (which would contain the application logic, while leaving the domain business logic in the domain objects), which helps you isolate the interaction between domain entities and storage abstractions from the presentation layer.
它负责创建服务(它将包含应用程序逻辑,同时将域业务逻辑留在域对象中),这将帮助您将域实体与存储抽象之间的交互从表示层隔离开来。
About the other options:
-
The Controller only calls the Model and the Model handle the $_POST data.
控制器只调用模型,模型处理$_POST数据。
In the MVC and MVC-inspired design patterns the model should be aware of neither the user interface nor of the presentation layer as whole. The
$_POST
variable in PHP is a superglobal.在MVC和受MVC启发的设计模式中,模型既不应该关注用户界面,也不应该关注整个表示层。PHP中的$_POST变量是一个超全局变量。
If you use it with model layer, your code becomes bound to the web interface and even the specific request method.
如果您使用模型层,您的代码将绑定到web接口甚至是特定的请求方法。
-
The Controller transforms $_POST data into a Model's object and only pass the object to Model
控制器将$_POST数据转换为模型的对象,只将对象传递给模型
Not entirely sure what you meant with this. Seems you were talking about instantiation of an abstraction, which would contain the user's request. But in this case controller becomes responsible for instantiation/creation of said structure, which would violate SRP.
我不太明白你的意思。似乎您正在讨论抽象的实例化,它将包含用户的请求。但是在这种情况下,controller将负责实例化/创建上述结构,这将违反SRP。
Closing notes:
One thing you must understand is that, in context of web based MVC applications, the User of your application is the browser. Not you. Browser sends the request, which is handled by routing mechanism and disseminated by controller. And view produces the response to your browser.
您必须理解的一点是,在基于web的MVC应用程序的上下文中,应用程序的用户是浏览器。不是你。浏览器发送请求,由路由机制处理,由控制器传播。视图生成对浏览器的响应。
And the other thing is: Model is neither a class nor an object. Model is a layer.
另外,Model既不是类,也不是对象。模型是一个层。
Update
Generally, the same Controller handles request from a browser, a web service, an offline application, etc, or each one has it own Controller?
通常,相同的控制器处理来自浏览器、web服务、离线应用程序等的请求,还是每个控制器都有自己的控制器?
You should be able to have single controller, that deals with all the forms of application. But that is only on the condition, you are actually using same application for all 3 use-cases.
您应该能够拥有一个控制器,它处理所有的应用程序形式。但这只是在条件上,您实际上在所有3个用例中都使用相同的应用程序。
To do so there are two conditions:
为此,有两个条件:
- you need to abstract the
Request
instance, that controller receives - 您需要抽象控制器接收的请求实例
- the view should be instantiated outside the controller
- 视图应该在控制器之外实例化。
This way you can have one application to fulfill all the requirements. Only thing, that each variant has different, is the bootstrap stage, where you create the Request
instance and select the proper view.
这样,您就可以有一个应用程序来满足所有的需求。惟一不同的是,每个变体都有不同的引导阶段,在这个阶段您创建请求实例并选择适当的视图。
In the situation, that you described, the changing part would actually be the view, since a REST or SOAP service would be expected to produce a different response than an ordinary web application.
在您所描述的情况下,更改部分实际上是视图,因为REST或SOAP服务应该产生与普通web应用程序不同的响应。
#2
3
Once upon a time was the three tiered application architecture.
曾几何时,有三层应用程序架构。
It all depends on your MVC framework. Normally, the Controller does the link between the user and the model layer, which manipulate domain objects.
这一切都取决于您的MVC框架。通常,控制器执行用户和模型层之间的链接,模型层操作域对象。
In the early days of MVC in PHP, the model layer was actually just the domain objects, called models for that purpose. Some prefered having so called thin models, which only provide an OO representation of the data, (which simplifies persistence). In that case, the controller would regroup the so called actions, containing the bulk of the processing associated with an HTTP request (fat controller).
在早期的PHP MVC中,模型层实际上只是域对象,为此目的被称为模型。有些人更喜欢所谓的瘦模型,它只提供数据的OO表示(这简化了持久性)。在这种情况下,控制器将重新分组所谓的操作,其中包含与HTTP请求(fat controller)相关联的大部分处理。
Others embedded most of said processing in the object model with dedicated methods (fat model).
另一些则使用专用方法(fat模型)将大多数上述处理嵌入到对象模型中。
However, at some point, you have to analyse the content of the query to sanitize and validate it, and this depends on how your view will format the request. Sanitization might be a controller task (this request should only contain these values), while validation is definitely a model task (values should be of these types).
但是,在某些时候,您必须分析查询的内容以对其进行清理和验证,这取决于您的视图将如何格式化请求。杀毒可能是一个控制器任务(这个请求应该只包含这些值),而验证肯定是一个模型任务(值应该是这些类型)。
An interesting question is: how do you deal with actions impacting several domain objects? Where do you put the logic for that?
一个有趣的问题是:如何处理影响多个域对象的操作?你把逻辑放在哪里?
Nowadays, the model layer is composed of services segregating the domain objects from the evil grasp of the controllers, to limit the dependencies between the layers to their respective interfaces only. This is where most of the request processing is done.
现在,模型层是由服务组成的,这些服务将域对象从控制器的邪恶控制中分离出来,以限制层之间的依赖关系到它们各自的接口。这是大部分请求处理的地方。
Symfony2, for instance, provides a sensible answer to this question: each step of the processing of a request is implemented in a dedicated piece of code, which could be described as the following:
例如,Symfony2为这个问题提供了一个明智的答案:处理请求的每个步骤都在一段专用代码中实现,这段代码可以描述为:
- the request is first turned into an object
- 请求首先被转换为对象
- that object is routed using a routing object
- 该对象使用一个路由对象进行路由
- it is handled to a controller
- 它被处理给一个控制器
- the controller pass the request to the service concerned by the action, which build the response object
- 控制器将请求传递给与操作相关的服务,该服务构建响应对象
The service job is then broken in several steps:
然后,服务工作被分解为以下几个步骤:
- validation (using a dedicated object which rely on rules described in a separate file),
- 验证(使用依赖于独立文件中描述的规则的专用对象),
- construction/updating of domain objects (using serialization to/from db if necessary),
- 构造/更新域对象(如有必要,使用对db的串行化),
- selection of a template for the response,
- 选择响应的模板,
- population of said template with the relevant data from the domains.
- 使用来自域的相关数据填充该模板。
CakePHP is another popular framework which follows similar concepts: simple controllers, and services encapsulating domain objects.
CakePHP是另一个流行的框架,它遵循类似的概念:简单的控制器和封装域对象的服务。
See this question for a better insight on the general concepts.
有关一般概念的更深入理解,请参见这个问题。
See this other question for other answers.
其他答案请参见另一个问题。
Thanks to tereško for his invaluable input on the matter.
感谢tereško他宝贵的输入。
#3
1
i am using Zend and following
我正在使用Zend和follow
the 2nd option .
第二选择。
Example a Registration form
例如一个注册表单
step- 1 the forms sends me the post value to the specified controller
步骤1表单将post值发送给指定的控制器
step -2 i will validate the form values for example ( mail and url and empty post values ) through server side validation .
步骤-2我将通过服务器端验证来验证表单值(如邮件和url以及空的post值)。
step -3 send the checked post data either in variable or has whole to the model .
步骤-3将选中的post数据以变量形式或完整形式发送给模型。
step 4- controller calls the model .
步骤4-控制器调用模型。
step -5 the models inserts the post values and creates a new user .
步骤-5模型插入post值并创建一个新用户。
I think your second option is better regardless of framework or approah you use .
我认为您的第二个选择是更好的,无论您使用的框架或批准。
note - same controller can handle everthing depends on your application logic .
注意——同样的控制器可以处理任何事情,这取决于您的应用程序逻辑。
but i prefer to keep different controller for differnt user request and user types
it helps in keeping code readable managebale .
#4
0
Look at some MVC frameworks.
看看一些MVC框架。
For example, in Yii you can write such code inside action:
例如,在Yii中,您可以在action中编写这样的代码:
$model = new Model();
if(isset($_POST['Model'])) {
$model->attributes = $_POST['Model'];
}
Note, that all attributes
of your model must be passed through validation rules. In Yii validation applies during (actually, before) $model->save()
注意,模型的所有属性必须通过验证规则。在Yii中,验证应用于$model->save()期间(实际上,在此之前)
See:
看到的:
- http://www.yiiframework.com/doc/guide/1.1/en/form.model#securing-attribute-assignments
- 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
- http://www.yiiframework.com/doc/guide/1.1/en/basics.mvc
#5
0
'C' is best option. You should not let raw $POST data go in model as model is supposed to be generic handling store and load operations mainly.
“C”是最好的选择。您不应该让原始$POST数据进入模型,因为模型应该主要是通用的处理存储和加载操作。
Example : same model can be used web interface and Web services. On Web $_POST is valid but for web services its not. So model doesnt care how data is received but only how to store and load it.
示例:同样的模型可以使用web接口和web服务。在Web $_POST是有效的,但是对于Web服务则不是。所以模型并不关心如何接收数据,而是只关心如何存储和加载数据。
Yii is definitely a clean implementation of MVC.
Yii绝对是MVC的一个干净的实现。
#1
24
The best option is to use #2 approach, with some alterations.
I would write it as something like this:
最好的选择是使用#2方法,并进行一些修改。我会这样写:
public function postLogin( $request )
{
$service = $this->serviceFactory->build('Recognition');
$service->authenticate( $request->getParam('username'),
$request->getParam('password') );
}
// Yes, that's the whole method
There is no need to actually create variables, if you have used something like a Request
instance to abstract the user's input.
如果您使用了请求实例之类的东西来抽象用户的输入,则不需要实际创建变量。
Also, you might want to replace the
Request::getParam()
method with something likeRequest::getPost()
- although I have come to the conclusion that, in a correctly structured application, theGET
andPOST
parameters should not share same name.另外,您可能想要用likeRequest::getPost()来替换theRequest::getParam()方法——尽管我得出的结论是,在一个正确的结构化应用程序中,getandpostparameters不应该共享相同的名称。
The serviceFactory
which you see in the code snippet would be an object that you inject in both controller and view instance. It would let you share same service instances between controllers and views.
您在代码片段中看到的serviceFactory将是您在控制器和视图实例中注入的对象。它允许您在控制器和视图之间共享相同的服务实例。
It is responsible for creation of services (which would contain the application logic, while leaving the domain business logic in the domain objects), which helps you isolate the interaction between domain entities and storage abstractions from the presentation layer.
它负责创建服务(它将包含应用程序逻辑,同时将域业务逻辑留在域对象中),这将帮助您将域实体与存储抽象之间的交互从表示层隔离开来。
About the other options:
-
The Controller only calls the Model and the Model handle the $_POST data.
控制器只调用模型,模型处理$_POST数据。
In the MVC and MVC-inspired design patterns the model should be aware of neither the user interface nor of the presentation layer as whole. The
$_POST
variable in PHP is a superglobal.在MVC和受MVC启发的设计模式中,模型既不应该关注用户界面,也不应该关注整个表示层。PHP中的$_POST变量是一个超全局变量。
If you use it with model layer, your code becomes bound to the web interface and even the specific request method.
如果您使用模型层,您的代码将绑定到web接口甚至是特定的请求方法。
-
The Controller transforms $_POST data into a Model's object and only pass the object to Model
控制器将$_POST数据转换为模型的对象,只将对象传递给模型
Not entirely sure what you meant with this. Seems you were talking about instantiation of an abstraction, which would contain the user's request. But in this case controller becomes responsible for instantiation/creation of said structure, which would violate SRP.
我不太明白你的意思。似乎您正在讨论抽象的实例化,它将包含用户的请求。但是在这种情况下,controller将负责实例化/创建上述结构,这将违反SRP。
Closing notes:
One thing you must understand is that, in context of web based MVC applications, the User of your application is the browser. Not you. Browser sends the request, which is handled by routing mechanism and disseminated by controller. And view produces the response to your browser.
您必须理解的一点是,在基于web的MVC应用程序的上下文中,应用程序的用户是浏览器。不是你。浏览器发送请求,由路由机制处理,由控制器传播。视图生成对浏览器的响应。
And the other thing is: Model is neither a class nor an object. Model is a layer.
另外,Model既不是类,也不是对象。模型是一个层。
Update
Generally, the same Controller handles request from a browser, a web service, an offline application, etc, or each one has it own Controller?
通常,相同的控制器处理来自浏览器、web服务、离线应用程序等的请求,还是每个控制器都有自己的控制器?
You should be able to have single controller, that deals with all the forms of application. But that is only on the condition, you are actually using same application for all 3 use-cases.
您应该能够拥有一个控制器,它处理所有的应用程序形式。但这只是在条件上,您实际上在所有3个用例中都使用相同的应用程序。
To do so there are two conditions:
为此,有两个条件:
- you need to abstract the
Request
instance, that controller receives - 您需要抽象控制器接收的请求实例
- the view should be instantiated outside the controller
- 视图应该在控制器之外实例化。
This way you can have one application to fulfill all the requirements. Only thing, that each variant has different, is the bootstrap stage, where you create the Request
instance and select the proper view.
这样,您就可以有一个应用程序来满足所有的需求。惟一不同的是,每个变体都有不同的引导阶段,在这个阶段您创建请求实例并选择适当的视图。
In the situation, that you described, the changing part would actually be the view, since a REST or SOAP service would be expected to produce a different response than an ordinary web application.
在您所描述的情况下,更改部分实际上是视图,因为REST或SOAP服务应该产生与普通web应用程序不同的响应。
#2
3
Once upon a time was the three tiered application architecture.
曾几何时,有三层应用程序架构。
It all depends on your MVC framework. Normally, the Controller does the link between the user and the model layer, which manipulate domain objects.
这一切都取决于您的MVC框架。通常,控制器执行用户和模型层之间的链接,模型层操作域对象。
In the early days of MVC in PHP, the model layer was actually just the domain objects, called models for that purpose. Some prefered having so called thin models, which only provide an OO representation of the data, (which simplifies persistence). In that case, the controller would regroup the so called actions, containing the bulk of the processing associated with an HTTP request (fat controller).
在早期的PHP MVC中,模型层实际上只是域对象,为此目的被称为模型。有些人更喜欢所谓的瘦模型,它只提供数据的OO表示(这简化了持久性)。在这种情况下,控制器将重新分组所谓的操作,其中包含与HTTP请求(fat controller)相关联的大部分处理。
Others embedded most of said processing in the object model with dedicated methods (fat model).
另一些则使用专用方法(fat模型)将大多数上述处理嵌入到对象模型中。
However, at some point, you have to analyse the content of the query to sanitize and validate it, and this depends on how your view will format the request. Sanitization might be a controller task (this request should only contain these values), while validation is definitely a model task (values should be of these types).
但是,在某些时候,您必须分析查询的内容以对其进行清理和验证,这取决于您的视图将如何格式化请求。杀毒可能是一个控制器任务(这个请求应该只包含这些值),而验证肯定是一个模型任务(值应该是这些类型)。
An interesting question is: how do you deal with actions impacting several domain objects? Where do you put the logic for that?
一个有趣的问题是:如何处理影响多个域对象的操作?你把逻辑放在哪里?
Nowadays, the model layer is composed of services segregating the domain objects from the evil grasp of the controllers, to limit the dependencies between the layers to their respective interfaces only. This is where most of the request processing is done.
现在,模型层是由服务组成的,这些服务将域对象从控制器的邪恶控制中分离出来,以限制层之间的依赖关系到它们各自的接口。这是大部分请求处理的地方。
Symfony2, for instance, provides a sensible answer to this question: each step of the processing of a request is implemented in a dedicated piece of code, which could be described as the following:
例如,Symfony2为这个问题提供了一个明智的答案:处理请求的每个步骤都在一段专用代码中实现,这段代码可以描述为:
- the request is first turned into an object
- 请求首先被转换为对象
- that object is routed using a routing object
- 该对象使用一个路由对象进行路由
- it is handled to a controller
- 它被处理给一个控制器
- the controller pass the request to the service concerned by the action, which build the response object
- 控制器将请求传递给与操作相关的服务,该服务构建响应对象
The service job is then broken in several steps:
然后,服务工作被分解为以下几个步骤:
- validation (using a dedicated object which rely on rules described in a separate file),
- 验证(使用依赖于独立文件中描述的规则的专用对象),
- construction/updating of domain objects (using serialization to/from db if necessary),
- 构造/更新域对象(如有必要,使用对db的串行化),
- selection of a template for the response,
- 选择响应的模板,
- population of said template with the relevant data from the domains.
- 使用来自域的相关数据填充该模板。
CakePHP is another popular framework which follows similar concepts: simple controllers, and services encapsulating domain objects.
CakePHP是另一个流行的框架,它遵循类似的概念:简单的控制器和封装域对象的服务。
See this question for a better insight on the general concepts.
有关一般概念的更深入理解,请参见这个问题。
See this other question for other answers.
其他答案请参见另一个问题。
Thanks to tereško for his invaluable input on the matter.
感谢tereško他宝贵的输入。
#3
1
i am using Zend and following
我正在使用Zend和follow
the 2nd option .
第二选择。
Example a Registration form
例如一个注册表单
step- 1 the forms sends me the post value to the specified controller
步骤1表单将post值发送给指定的控制器
step -2 i will validate the form values for example ( mail and url and empty post values ) through server side validation .
步骤-2我将通过服务器端验证来验证表单值(如邮件和url以及空的post值)。
step -3 send the checked post data either in variable or has whole to the model .
步骤-3将选中的post数据以变量形式或完整形式发送给模型。
step 4- controller calls the model .
步骤4-控制器调用模型。
step -5 the models inserts the post values and creates a new user .
步骤-5模型插入post值并创建一个新用户。
I think your second option is better regardless of framework or approah you use .
我认为您的第二个选择是更好的,无论您使用的框架或批准。
note - same controller can handle everthing depends on your application logic .
注意——同样的控制器可以处理任何事情,这取决于您的应用程序逻辑。
but i prefer to keep different controller for differnt user request and user types
it helps in keeping code readable managebale .
#4
0
Look at some MVC frameworks.
看看一些MVC框架。
For example, in Yii you can write such code inside action:
例如,在Yii中,您可以在action中编写这样的代码:
$model = new Model();
if(isset($_POST['Model'])) {
$model->attributes = $_POST['Model'];
}
Note, that all attributes
of your model must be passed through validation rules. In Yii validation applies during (actually, before) $model->save()
注意,模型的所有属性必须通过验证规则。在Yii中,验证应用于$model->save()期间(实际上,在此之前)
See:
看到的:
- http://www.yiiframework.com/doc/guide/1.1/en/form.model#securing-attribute-assignments
- 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
- http://www.yiiframework.com/doc/guide/1.1/en/basics.mvc
#5
0
'C' is best option. You should not let raw $POST data go in model as model is supposed to be generic handling store and load operations mainly.
“C”是最好的选择。您不应该让原始$POST数据进入模型,因为模型应该主要是通用的处理存储和加载操作。
Example : same model can be used web interface and Web services. On Web $_POST is valid but for web services its not. So model doesnt care how data is received but only how to store and load it.
示例:同样的模型可以使用web接口和web服务。在Web $_POST是有效的,但是对于Web服务则不是。所以模型并不关心如何接收数据,而是只关心如何存储和加载数据。
Yii is definitely a clean implementation of MVC.
Yii绝对是MVC的一个干净的实现。