简体   繁体   English

在MVC网站上验证和处理表单提交的位置

[英]Where to validate and process form submission in MVC website

I'm working on a PHP based Model-View-Controller structured website. 我正在开发一个基于PHP的Model-View-Controller结构化网站。 I understand that the Models should deal with business logic, views present HTML (or whatever) to the user, and the controllers facilitate this. 我知道模型应该处理业务逻辑,视图向用户呈现HTML(或其他形式),并且控制器可以简化此过程。 Where I'm running stuck is with forms. 我遇到问题的地方是表格。 How much processing do I put in the controller, and how much do I put the my model? 我要对控制器进行多少处理,我要对模型进行多少处理?

Assume that I'm trying to update a user's first & last name. 假设我正在尝试更新用户的名字和姓氏。 What I want to do is submit a form using AJAX to one of my controllers. 我要做的是使用AJAX向我的一个控制器提交一个表单。 I want the data to be validated (again) server side, and if valid save it to the database, and then return a JSON response back to the view, as either a success or error. 我希望数据(再次)在服务器端进行验证,如果有效,则将其保存到数据库中,然后将JSON响应返回为成功或错误,返回视图。

Should I create an instance of my user model in the controller, or should I just have the controller relay to a static method in my model? 我应该在控制器中创建用户模型的实例,还是仅让控制器中继到模型中的静态方法? Here is two examples of how this could work: 这是两个如何工作的示例:

Option #1: Process POST in Model 选项1:在模型中处理POST

<form action="/user/edit-user-form-submit/" method="post">
    <input type="text" name="firstname">
    <input type="text" name="lastname">
    <button type="submit">Save</button>
</form>

<?php
    class user
    {
        public function __construct($id){} // load user from database
        public function set_firstname(){} // validate and set first name
        public function set_lastname(){} // validate and set last name
        public function save_to_database(){} // save object fields to database

        public static function save_data_from_post()
        {
            // Load the user
            $user = new user($_POST['id']);

            // Was the record found in the db?
            if($user->exists)
            {
                // Try to set these fields
                if(
                    $user->set_firstname($_POST['firstname'])
                    and
                    $user->set_lastname($_POST['lastname'])
                )
                {
                    // No errors, save to the dabase
                    $user->save_to_database();

                    // Return success to view
                    echo json_encode(array('success' => true));
                }
                else
                {
                    // Error, data not valid!
                    echo json_encode(array('success' => false));
                }
            }
            else
            {
                // Error, user not found!
                echo json_encode(array('success' => false));
            }
        }   
    }

    class user_controller extends controller
    {
        public function edit_user_form()
        {
            $view = new view('edit_user_form.php');
        }
        public function edit_user_form_submit()
        {
            user::save_data_from_post();
        }
    }
?>

Option #1: Process POST in Model 选项1:在模型中处理POST

<form action="/user/edit-user-form-submit/" method="post">
    <input type="text" name="firstname">
    <input type="text" name="lastname">
    <button type="submit">Save</button>
</form>

<?php
    class user
    {
        public function __construct($id){} // load user from database
        public function set_firstname(){} // validate and set first name
        public function set_lastname(){} // validate and set last name
        public function save_to_database(){} // save object fields to database
    }

    class user_controller extends controller
    {
        public function edit_user_form()
        {
            $view = new view('edit_user_form.php');
        }
        public function edit_user_form_submit()
        {
            // Load the user
            $user = new user($_POST['id']);

            // Was the record found in the db?
            if($user->exists)
            {
                // Try to set these fields
                if(
                    $user->set_firstname($_POST['firstname'])
                    and
                    $user->set_lastname($_POST['lastname'])
                )
                {
                    // No errors, save to the dabase
                    $user->save_to_database();

                    // Return success to view
                    echo json_encode(array('success' => true));
                }
                else
                {
                    // Error, data not valid!
                    echo json_encode(array('success' => false));
                }
            }
            else
            {
                // Error, user not found!
                echo json_encode(array('success' => false));
            }
        }
    }
?>

The two examples do the exact same thing, I realize that. 我意识到,这两个示例完全相同。 But is there a right and wrong way of doing this? 但是,这样做有对与错的方法吗? I've read a lot about skinny controllers and fat models, where is where option #1 came from. 我已经读了很多关于瘦控制器和胖模型的信息,选项1是从哪里来的。 How are you handling this? 您如何处理? Thanks, and sorry for the long question! 谢谢,对于很长的问题感到抱歉!

Put shortly, you can use either of these approaches - but you should change them a bit. 简而言之,您可以使用这两种方法中的任何一种- 您应该对其进行一些更改。

Consider this: The models don't really "know" about post, get and whatnot. 考虑一下:这些模型并不真正“知道”发布,获取以及诸如此类的东西。 They should only know about whatever business-related thing they are - in your case a user. 他们应该只知道与他们有关的任何与业务相关的事物-在您的情况下是用户。

So while approach #1 can be used, you should not access post variables directly from the model. 因此,虽然可以使用方法#1,你应该从模型直接访问后变量。 Instead, make the function take an array of parameters which are then used to create the user. 取而代之的是,使函数采用一组参数,然后使用这些参数来创建用户。

This way you can easily reuse the code, say in a shell script or whatever, where there is no such thing as $_POST . 这样,您可以轻松地重用代码,例如在shell脚本等中,没有$_POST类的东西。

While the second approach is more verbose in the controller, it's something you could do too. 尽管第二种方法在控制器中更为冗长,但是您也可以这样做。 However, perhaps a bit better approach in the style is to use a "service class". 但是,这种样式中也许更好的方法是使用“服务类”。 The service would have a method, let's say "createUserFromArray", which takes an array and returns a user. 该服务将具有一个方法,例如“ createUserFromArray”,该方法采用一个数组并返回一个用户。 Again, you would pass this method the $_POST as parameters - similar to how you should pass them into the function in modified #1. 同样,您可以将$_POST作为参数传递给此方法-类似于将它们传递给修改后的#1中的函数的方式。

Only the controller should deal with inputs directly. 仅控制器应直接处理输入。 This is because the controller handles the request, and thus it can know about post. 这是因为控制器处理请求,因此可以知道有关发布的信息。

tl;dr your models should never use superglobals like $_POST directly. tl; dr,您的模型永远不应直接使用$_POST类的超全局变量。

From my point of view and the way we're doing it at work, model will handle the validation and filtering of datas that are passed to it, but we use the controller to push thoose datas inside the model. 从我的观点以及我们在工作中的工作方式来看,模型将处理传递给它的数据的验证和过滤,但是我们使用控制器将选择的数据推入模型中。

Has stated in above comments, the model don't have to know about $_POST or $_GET these are user input that the controller has to deal with. 在上面的注释中已经说明,模型不必知道$ _POST或$ _GET这些是控制器必须处理的用户输入。 In the other hand the model must handle all verification of datas passed to it as you definitely don't want to make again and again your data validation in different code portion of your project. 另一方面,该模型必须处理所有传递给它的数据的验证,因为您绝对不想在项目的不同代码部分中一次又一次地进行数据验证。

A big reason for the MVC design pattern is that it's a good way of maintaining Separation of Concerns. MVC设计模式的一个重要原因是它是维护关注分离的好方法。 The View should be ignorant of the Model, and vice-versa. 视图应忽略模型,反之亦然。 The Controller is there only as a sort of traffic cop mediating between the Model and the View. 控制器仅作为在模型和视图之间进行调解的一种交通方式。 So the Controller should take the data from the View, do the minimal processing needed so that the Model can understand the data without needing to know how the View is implemented (ie via an HTML form), and give it to the Model so the model can persist the data. 因此,控制器应从视图中获取数据,进行所需的最少处理,以便模型无需了解视图的实现方式(即通过HTML表单)即可理解数据,并将其提供给模型,以便模型可以保留数据。

This makes it so the Model can be reused in other instances when an item needs to be created / saved / persisted by other means than an HTML form, without duplicating item-saving code across multiple Controllers. 这样,当需要通过HTML表单以外的其他方式创建/保存/保存项目时,可以在其他实例中重用该模型,而无需在多个Controller之间复制保存项目的代码。

UPDATE: I forgot to mention validation. 更新:我忘了提到验证。 Along the same lines as for persisting the data, the Controller should take the data and pass it to the Model for validation, since the Model is the one that knows the exact format of the data it needs. 沿着与保留数据相同的方式,控制器应获取数据并将其传递给模型进行验证,因为模型是知道所需数据确切格式的模型。 You could combine validation and persistence by having the Model throw an exception if the data is invalid, which the Controller can catch and deal with as necessary (eg render JSON error response.) 您可以通过在数据无效的情况下让Model引发异常来组合验证和持久性,Controller可以根据需要捕获并处理该异常(例如,呈现JSON错误响应)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM