【问题标题】:Where does input validation belong in an MVC application?输入验证在 MVC 应用程序中属于哪里?
【发布时间】:2011-01-05 08:00:06
【问题描述】:

我有一个从表单接收输入的 MVC 应用程序。
这是一个登录表单,因此唯一需要的验证是检查输入是否为非空。
现在,在我将它传递给模型之前,我在控制器中对其进行验证。
这是否是最佳实践?是否属于模型?

【问题讨论】:

标签: model-view-controller language-agnostic model controller


【解决方案1】:

我认为没有官方的最佳实践将验证限制在 MVC 模式的任何单个部分。例如,您的视图可以(并且应该)使用 Javascript 进行一些预先验证。您的控制器还应该提供相同类型的验证,以及更多与业务逻辑相关的验证。该模型还可以提供验证形式,即不允许空值的设置器。

有一个关于这个at joelonsoftware的有趣讨论。

【讨论】:

  • 我认为应用程序的某处有一些 Javascript?除非这是一个老式的 Web 1.0 风格的 Web 应用程序或框架。
  • 有但我不会触摸/编码/处理它,除非我真的很想这样做:) 在这个框架中,视图只创建和初始化小部件并将它们附加到根小部件。不过,它可以具有验证功能。那么视图是验证数据是否为空的地方,而模型是验证输入的用户名和密码是否正确的地方?
  • 视图也应该调用模型函数吗?这将它们结合在一起,它失去了全部意义。所以这就是控制器现在正在做的事情:验证非空值并将其传递给模型。我是否应该让视图调用将调用模型身份验证方法的控制器,然后将答案返回给将在视图中返回答案的控制器?这听起来像是一项重大开销。
【解决方案2】:

我一直在考虑这个问题并尝试在控制器和模型中进行验证之后......最后我得出的结论是,对于我的许多应用程序......验证属于模型而不是在控制器中。为什么?因为相同的模型将来可能被各种其他控制器调用或 API 使用......然后我将不得不一遍又一遍地重复验证过程。这将违反 DRY 并导致许多错误。再加上哲学上它与数据库(或其他持久存储)交互的模型,因此无论如何都是“最后一次喝酒”的地方。

所以我在控制器中进行 get/post 转换,然后将原始数据发送到模型进行验证和处理。当然,我经常做 php/mysql web 应用程序,如果你在做其他事情,结果可能会有所不同。我希望这对某人有所帮助。

【讨论】:

    【解决方案3】:

    验证必须在模型中

    只有模型知道业务的“细节”。只有模型知道哪些数据可以接受,哪些数据不能接受。控制器只知道如何“使用”模型。

    例如:假设我们需要向我们的系统注册新用户的功能。

    模型:

     public function registerUser(User $user){
        //pseudo code
           //primitive validation
           if(!isInt($user->age)){
               //log the invalid input error
               return "age"; 
           }
           if(!isString($user->name)){
               //log the invalid input error
               return "name";
           }
           //business logic validation
    
            //our buisnees only accept grown peoples
            if($user->age < 18){
                //log the error
                return "age";
            }
            //our buisness accepts only users with good physique
            if($user->weight > 100){
                //log the error
                return "weight";
            }
            //ervery thing is ok ? then insert the user
            //data base query (insert into user (,,,) valeues (?,?,?,?))
            return true;
    }
    

    现在控制器的工作是“使用”模型 registerUser() 函数,而不知道模型将如何进行验证,甚至不知道什么被认为是“有效”!

    控制器:

    $user = new User();
    $user->age = isset($_POST['age']) ?  $_POST['age'] : null;
    $user->name = isset($_POST['name']) ?  $_POST['name'] : null;
    $user->age = isset($_POST['weight']) ?  $_POST['weight'] : null;
    $result = $theModel->registerUser($user);// <- the controller uses the model
    if($result === true){
    //build the view(page/template) with success message and die
    }
    $msg = "";
    //use the return value from the function or you can check the error logs
    switch ($result){
        case"age" :
            $msg = "Sorry, you must be over 18";
            break;
        case "name":
            $msg = "name field is not correct";
            break;
        case "weight":
            $msg = "Sorry, you must have a good physique";
            break;
    }
    //build the view(page/template) with error messages and die
    

    班级用户

    class User { 
        public $age;
        public $name;
        public $weight;
    }
    

    拥有这样的架构将使控制器完全从业务逻辑的细节中“解放”出来——这是一件好事——。

    假设我们想在网站的其他地方进行另一种形式的用户注册(我们将为它分配另一个控制器)。现在另一个控制器将使用与模型registerUser()相同的方法。

    但是,如果我们在控制器和模型之间分配验证逻辑,它们将不会被分离——这对 MVC 不利——这意味着每次你需要创建新视图和控制器来注册新用户时,你必须使用相同的旧控制器和模型在一起。此外,如果业务逻辑发生变化(我们现在在体育俱乐部接受青少年),您只需更改模型 registerUser() 函数中的代码。控制器代码还是一样的。

    【讨论】:

      【解决方案4】:

      它的业务逻辑,所以不,它不属于模型。

      【讨论】:

      • 下面的答案另有说明。请详细说明并解释您为什么这么认为。
      • 我可能会走下面概述的路线。在这种情况下,它将进入您的服务层。基本上,这样想;不允许空字符串是模型对您施加的约束吗?它不是用户界面问题。所以这一定是一个商业问题;用户无法使用空用户名登录。
      • 呃。如果您在模型中正确执行 MVC 业务逻辑,而不是视图或控制器。应用逻辑属于控制器,视图就是视图。可以说验证不是业务逻辑而是应用程序逻辑,但那是一种分裂。
      【解决方案5】:

      在控制器中,您有 ModelState 属性,您可以向其中添加验证错误。

      this example on the MSDN

      【讨论】:

        【解决方案6】:

        假设您的应用程序结构如下:

        • 模型-视图-控制器
        • 服务
        • 坚持
        • 型号

        用户输入将到达您的控制器,您将使用服务层中的服务来验证它。

        【讨论】:

        • 更多层?什么是服务层?没有数据库,因此本身没有持久性,所有数据都来自另一个进程,所有数据都从 UI 或进程中更改。
        【解决方案7】:
        Business Logic  -> Controller
        Data Validation -> Model
        

        【讨论】:

        • 上面的答案说它是业务逻辑,所以它不属于模型。你说这样做对吗?我糊涂了。请详细说明并解释您为什么这么认为。
        • 我不同意。我会说:业务逻辑 -> 领域;用户界面逻辑 -> 控制器;验证 -> 域 + UI(可选)
        • @the_drow:我是说业务逻辑属于Model,它属于Controller。
        • @Martinho: @unknown 和 @Kaleb 似乎同意我的观点。
        • 让我澄清一下:我所说的域是指所谓的域模型、域层或有时是业务逻辑层 (martinfowler.com/eaaCatalog/domainModel.html)。 UI 是用户界面。 MVC 是一种用户界面架构 (martinfowler.com/eaaDev/uiArchs.html)。我上面说的是业务逻辑不属于用户界面,而是属于领域层。验证应该在领域层,但也可以用在其他层,比如 UI(可能在 Controller 或 Js 中的 View),以向用户提供快速反馈。
        猜你喜欢
        • 1970-01-01
        • 2011-04-23
        • 1970-01-01
        • 2017-05-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-21
        • 2010-09-25
        相关资源
        最近更新 更多