51

On one hand form validation could be seen as part of the application logic and therefore belonging in the model.

On the other hand, it deals directly with the input coming from view and handles displaying errors, etc. From that angle it makes more sense to put it into controllers.

Which one is the right approach from the MVC point of view?

P.S my form validation actually consists only of writing a list of fields, their rules, and passing it on to a form validation library, which returns true/false on whether it passed validation or not.

Example:

$this->load->library('form_validation');
$this->form_validation->set_rules('name', 'Name', 'required');
$this->form_validation->set_rules('email', 'Email', 'required|valid_email');
//........
if ($this->form_validation->validate())
    // Process data
else
    $this->register_form(); //A controller action that will show a view with errors

Should this be put into a controller or model?

tereško
  • 58,060
  • 25
  • 98
  • 150
Ali
  • 261,656
  • 265
  • 575
  • 769
  • 4
    I suppose people, who say validation should be done in Controller are from CakePHP-like-world, but I'm from Yii-like-world :) [Validation in CakePHP](http://api.cakephp.org/class/controller#method-Controllervalidate) VS [Validation in Yii](http://www.yiiframework.com/doc/api/1.1/CModel#validate-detail) – Nemoden Apr 14 '11 at 05:04
  • @Mad If you're editing as admin and want all fields to be omitted, its the controller's job to check that and not call the validation method. Simply not doing the validation will solve that scenario. – Ali Apr 14 '11 at 20:25
  • @Mad I could just as easily check within the model itself whether the user is logged in as admin or not since my authentication library is available to both controllers & models. That's probably the right way to do it. – Ali Apr 15 '11 at 06:50

9 Answers9

75

Ideally, you want 3 layers of validation:

  1. View: Client side (javascript, html5 validation, etc.). This catches obvious errors and omissions before the data hits the controller, wasting the user's time and invoking an unnecessary page load if there are errors.
  2. Controller: This is your Form validation layer. Controllers usually are meant to handle input directly, and send it over to the model. It is very rare that every field in your form has a directly related column in your DB, you usually need to alter the data in some way before passing it to the model. Just because you have a field you need to validate called "confirm email", doesn't mean that your model will be dealing with a "confirm email" value. Sometimes, this will be the final validation step.
  3. Model: This is your last line of defense for validation, and possibly your only validation in the case of sending data to the model without it coming directly from a form post. There are many times when you need to send data to the DB from a controller call, or with data that is not user input. We don't want to see DB errors, we want to see errors thrown by the app itself. Models typically should not be dealing with $_POST data or user input directly, they should be receiving data from the controller. You don't want to be dealing with useless data here like the email confirmation.
Wesley Murch
  • 101,186
  • 37
  • 194
  • 228
  • 11
    That's it! Controller is just a validation LAYER! But Controller does NOT CONTAIN validation rules and it does not know how to validate data presented by user! Controller only knows which action is requested and action creates decent model which knows how to validate data. If data validation (BY MODEL) fails, controller just renders appropriate view with errors. That's exactly what I'm talking about. Thus, data validation is totally models issue. I think everybody confuse validation layer (at which point should data be validated) and validation place (by who/where data should be validated). – Nemoden Apr 14 '11 at 04:43
  • @Nemoden Take a look at [my example](http://stackoverflow.com/questions/5651175/mvc-question-should-i-put-form-validation-rules-in-the-controller-or-model#comment70199678_5651431), please. – x-yuri Jan 05 '17 at 23:57
  • This is a typical answer! @ClickUpvote I see no reason why this is not the correct/best answer – evilReiko Aug 15 '17 at 07:27
20

Validation is Model's issue. Only model knows how your data should look like. You describe your data fields in model, so you should describe validation rules for this fields in the same place.

It seems to be obvious for me, but I'd gladly listen to opponents.

Nemoden
  • 8,816
  • 6
  • 41
  • 65
  • 19
    He should put database validation in the Model (assuming it's a db model) and http data validation in the controller. Xss filtering, for example, does not pertain to the Model. it pertains to the Controller in input and to the View in output. – tacone Apr 13 '11 at 20:00
  • 2
    We don't talk about data filtering here, but validation. And why you're not able to perform filtering in model? You've loaded data from the web form, loaded it into model, model validated data, filtered it, and saved it wherever you want to. Filtering XSS is just about data conversion and data is belongs to Model. Maybe I need some examples? ... Models are not about the place where they SAVE data. It should not matter if you have model that stores data in DB or in file or it does not save data anywhere, but just send this data by email (Email sending form)... – Nemoden Apr 14 '11 at 04:12
  • I'm with Nemoden. In my case XSS filtering is handled in the background by the framework. I think the people who think validation belongs in the controller should read up on MVC a bit more (I made the same mistake). – Ali Apr 14 '11 at 06:07
  • @Madmartigan, "Should we define whether or not the input is valid in the model in this case? I don't think so". You don't think so, but it's EXACTLY like I think. Why don't you do that? There should be a strong reason, right? – Nemoden Apr 14 '11 at 07:28
  • 2
    @Madmartigan the problem is, you're thinking that a model is only related to the things that go in the database. Its not true, the model's job is to take care of all the business logic which includes credit card processing and validating. You should have a Booking model which validates the form and stores the booking, and an Order model which processes/validates the cc. The controller first validates the form via booking model, then validates + charges cc via Order model, and then stores order via booking model. If any errors, it passes them to view. – Ali Apr 14 '11 at 19:27
  • @Mad The reason to load the Booking and Order model is to keep your code clean by not mixing the business logic code with the code of the controller. Loading 2 classes barely takes any resources :). Consider my earlier example where if you need to validate a form with the same fields twice, e.g for an 'add booking' and 'edit boking' form, unless the validation rules are in a model you'd have to copy them twice. – Ali Apr 15 '11 at 06:54
  • I know I'm a bit late to this discussion, but here's my take: I tend to put as much logic/data validation on the model as possible. But one of the cases that led me to move some "form" or "input" validation to the controllers is when I want to reuse the _same_ model for an API. In this case the API controllers need to check other stuff (via other models) such as an API key, which are not present in a basic html form. – Víctor López García Jul 09 '12 at 19:05
  • `Xss filtering, for example, does not pertain to the Model.` I see no reason why it doesn't. But I'd rather do it when displaying data. To be able to amend filtering, if it was buggy. If you changed user data, they're no more. `Models are not about the place where they SAVE data.` The matter of terminology, I suppose. I'd rather call them business objects. `who think validation belongs in the controller should read up on MVC a bit more` There are a load of MVCs, which one do you mean? – x-yuri Jan 05 '17 at 23:40
  • `unless the validation rules are in a model you'd have to copy them twice` Quite contrived example I'd say. But in Laravel you've got [form requests](https://laravel.com/docs/5.3/validation#creating-form-requests), so you're not necessarily true. `In this case the API controllers need to check other stuff (via other models) such as an API key, which are not present in a basic html form.` In Laravel one'd use middleware for that, I believe. Is that also a model? Other way would probably be extracting auth into base controller. – x-yuri Jan 05 '17 at 23:48
  • Putting that all aside, consider this example. There is a form on a DNS registrar's site where you can order a bunch of domains. User don't want to copy them to the form one by one. The list of domains might have come over skype. And if I were a user, I'd like to just copy the whole list. Not one domain at a time. So we need textarea, where domains are separated by new line. Then how do we handle it with just model alone? The field that user has on the form doesn't match the attribute that model Domain has. – x-yuri Jan 05 '17 at 23:56
13

I would say the form validation code should be in the controller (not the model) in most cases.

Madmartigan put it best in his comment above "Form validation !== Data validation. Not all forms interact with a model"

Web forms are logically part of the View/Controller part of MVC, since the user interacts with them in the view.

JohnWright
  • 248
  • 1
  • 7
  • 2
    +1 - I agree. The idea that if it is data belongs to the Model does not apply here in my opinion. – ronaldosantana Apr 13 '11 at 20:01
  • 5
    What kind of forms don't interact with Model? In my opinion you can create models for all types of forms. Data DOES belong to Model. Wiki: "The model is not necessarily merely a database; the 'model' in **MVC IS BOTH THE DATA and the BUSINESS/domain LOGIC needed TO MANIPULATE the DATA** in the application". Validating data in Controller makes your Model incomplete. Model contains business logic that knows how to process data. If you don't validate your data before processing (you've forgotten to do it in Controller), you'd be in trouble. In my case I'll never forget to validate my data – Nemoden Apr 14 '11 at 03:56
  • 3
    I agree with Nemoden, its the responsibility of the model and not the controller. I think you should read up on MVC a bit more. – Ali Apr 14 '11 at 06:05
  • The keyword in the context of CodeIgniter is $this->FORM_validation which is referring to the html form, which is part of the view. As you said "it deals directly with the input coming from view and handles displaying errors, etc. From that angle it makes more sense to put it into controllers." If you put this in the model, your coupling your model code to require the form_validation object, which is part of the view. You can do this for convenience if you don't plan to reuse your model anywhere else. But from a purist point of view, this is a bad practice. – JohnWright Apr 14 '11 at 07:28
  • 4
    @JohnWright In CodeIgniter the 'form_validation' is a 'library' which is available to both controllers and models equally. Also, it actually makes more sense to put it in the model, since if you have 2 forms with the same fields: registration and 'my account', but with differnt controllers, both controllers can call on $this->user_model->validate() to see if the form was validated or not. – Ali Apr 14 '11 at 19:34
5

Seems like everyone always says model hands down to this question, which has its merits (compared to the opposite), but I think the answer to the question is more subtle. Validation of the data itself should be performed on the model.

But there are other types of validation, such as whether the form has been submitted with unexpected fields (for security purposes, obviously) or whether a user has permission to make the operation requested. By putting these types of validation in the model, it cements the model (an abstraction of the data) to completely separate things, like how the user system works or how form submissions are evaluated for security purposes.

You can imagine changing one of those classes or systems of classes, then having a mess because you have to change all of your models, too. Whereas controllers are the mediator between the client input and the data: in that role, they are the proper validators of the examples above, and likely many others.

Ryan Williams
  • 959
  • 7
  • 15
2

It is an interesting theoretical discussion, but if we focus on the point that the question was made in the context of Codeigniter(CI):

In CI you can specify a custom validation rule like this:

$this->form_validation->set_rules('email', 'Email', 'required|callback_my_validation');

In this scenario, you must define a public function called "my_validation" that must return true or false and the framework will add the error (if returned false) to a stack of errors.

So... if you put this code in the controller, you are inadvertedly exposing a public url, meaning it would by possible to call something like "http://yoursite.com/my_validation" (I don't think you intend that). The only way to protect this url would be to go into the "routes.php" file and prevent there the access to this url. This does not seem practical and seems to point us in the direction that CI developers intended us to handle validation in the model.

Luís Osório
  • 51
  • 1
  • 7
  • actually, if you just make your validation function private, then it can't be called by url. i.e `private function my_validation()`. It doesn't need to be a public function. Also, it can't be a function on a model, it must be defined on the controller for the callback to work. – Ali Dec 25 '13 at 09:25
  • realy? thanks, at first I was making this validation on the controller, but the validation seemed to stop working when I set it to private. The second point you make, seems to point in the opposite direction of my first answer, should we conclude that CI develporers intendend for this validation to made on the controller? (if so, most of the opinions above are contraditory to this) – Luís Osório Jan 02 '14 at 23:19
2

Taking in account other answers (and some research), if you have to validate data with rules like not-empty fields, email validation and stuff, the Controller shouldn't let this data pass through itself, but if you have rules like "only a user with a reputation greater than 150 can vote down an answer", you should do this in the model layer.

If you want to have business rules validation, I advise you to have an object like the Business Object Pattern, with that, in any part of the software when you want to "vote down an answer" you have your business logic preserved and centralized.

ViniciusPires
  • 983
  • 3
  • 12
  • 26
1

The model should validate its own data.

Say you have a Contact model, that only requires a first name and phone number. It should validate that first name and phone number are filled.

However, if this Contact model is part of a Quote, you may need a full name and email address as well.

In that case, you could either extend the Contact model (to be a QuoteContact model) and add more validations, or you could do the extra validations on the Quote model.

You should write your models so as to be reusable in other applications (even if they never will be), so they should be independent of the controller. If the validations are in the controller, then you lose those validations if you switch to say a command line version.

Neil McGuigan
  • 46,580
  • 12
  • 123
  • 152
0

If you validate form in serverside using codeigniter then it validate in controller

You need to include the form_validation library using autoload like this

$autoload['libraries'] = array("form_validation") 

OR directly you load in Controller

$this->load->library('form_validation');

Then you set the validation rule to each form field

$this->form_validation->set_rules('username', 'User Name', 'required');
$this->form_validation->set_rules('useremail', 'User Email', 'required|valid_email');

If any error found after validation a form field then it catch in validate function

if ($this->form_validation->validate()) {
    //return back to form
} else {
    //successful validate all field 
}
Andrew Stubbs
  • 4,322
  • 3
  • 29
  • 48
prash.patil
  • 687
  • 8
  • 7
0

There is another angle to this not covered in the other answers. It depends on what you are saying you Controller / View is! If it is Javascript that checks for validation as users type, for security reasons you should have a validation in your backend as well (this could again be in the controller of your backend or model because anyone can just push Data through Ajax without the browser.

For performance reasons, you should have a validation in your front end controller / view as well because you don't want to be hitting your database every time a user selects an invalid Birth Date or something.

So apart from the theoretical foundation of validation in M, V, and / or C you must also consider the practicality of frontend vs backend irrespective of MVC.

My personal recommendation is to not limit yourself to only one level of validation. An ill placed validation (like the Confirm Password example mentioned in the other answers) can have serious implications on the architecture.

Gaurav Ramanan
  • 3,655
  • 2
  • 21
  • 29