Where does input validation belong in an MVC appli

2019-03-12 13:32发布

问题:

I have a MVC application that receives an input from a form.
This is a login form so the only validation that is necessary is to check whether the input is non-empty.
Right now before I pass it to the model I validate it in the controller.
Is this a best practice or not? Does it belong to the model?

回答1:

I don't think there's an official best practice limiting validation to any single part of the MVC pattern. For example, your view can (and should) do some up-front validation using Javascript. Your controller should also offer the same types of validation, as well as more business-logic related validation. The model can also offer forms of validation, i.e., setters not allowing null values.

There's an interesting discussion of this at joelonsoftware.



回答2:

I have been thinking about this for a LONG time and after trying putting validation in both controllers and models.... finally I have come to the conclusion that for many of my applications... validation belongs in the model and not in the controller. Why? Because the same model could in the future be used by various other controller calls or APIs... and then I would have to repeat the validation process over and over again. That would violate DRY and lead to many errors. Plus philosophically its the model which interacts with the database ( or other persistent storage ) and thus is sort of a 'last call for alcohol' place to do this anyway.

So I do my get/post translation in the controller and then send raw data to the model for validation and processing. Of course I am often doing php/mysql web applications and if you are doing other things results may vary. I hope this helps someone.



回答3:

Validation must be in the Model

Only the model knows the "details" of the business. only the model knows which data is acceptable and which data is not. the controller just knows how to "use" the model.

for example: let's say we need the functionality of registering new users to our system.

The Model:

 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;
}

Now the controller/s job is to "use" the model registerUser() function without the knowledge of how the model is going to do the validation, or even what is considered "valid" or not!

the Controller:

$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

The class user

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

having an architecture like that will "free" the controllers completely from the details of the business logic -which is a good thing-.

Suppose we want to make another form of user registration somewhere else in the website (and we will have another controller allocated for it). now the other controller will use the same method of the model registerUser().

But if we distributed the validation logic between the controller and the model they will not be separated -which is bad and against MVC- meaning that every time you need to make new view and controller to register new user you must use the same old controller AND the model together. Moreover if the business logic is changed (we now accept teenagers in our sports club) you are going only to change the code in the model registerUser() function. the controllers code is still the same.



回答4:

Its business logic, so no, it doesn't belong in the model.



回答5:

Within the controller you have the ModelState property to which you can add validation errors to.

See this example on the MSDN.



回答6:

Assuming your application is structured like:

  • Model-View-Controller
  • Service
  • Persistence
  • Model

The user input would come to your controller, and you would use services in the service layer to validate it.



回答7:

Business Logic  -> Controller
Data Validation -> Model