5

I know questions like this one have been asked various times on stackoverflow, but even after having read those, I remain confused. I would like to gain clarity as to where form validation is supposed to be handled through demonstrating an issue with an example.

Let's say I have a form on my website, with a field that somebody fills out and subsequently submits. The model would like the controller to pass it this value correctly in order to process that value internally. The model receives the input through the function getInput, which sets the following rules:

  • The input must be of the string type.
  • The input must be of more than 0 and fewer than or equal to 100 characters.
  • The input must match the pattern of an e-mail address.

I suppose I should throw an exception inside getInput, if any of these conditions do not meet; after all, the controller passed a value that did not match the rules that had been set by the model.

Apart from the aforementioned rules, the controller (at least I am rather certain this applies to the controller) must also validate whether the input value had been set in the first place, before the script proceeds with the other three rules.

Now my question is: which of these (4) rules are to be validated by the controller, and which ones by the model? It is apparent that the controller knows what the model requests, so that it can adjust to that (and if it doesn't, it may face the consequence of an exception being thrown). On the other hand, it seems redundant to have several controllers, which all make use of the model and its getInput, validating the same kind of string so that it matches the rules set by the model. Also, if the controller firstly validates if the input is of the correct length - for example - and the model does the precise same thing immediatly after that, once getInput gets called, even more redundancy seems to arise.

In the example, the controllers and the model could be seen as a partnership with the model being a grumpy perfectionist, who is going to validate the input he gets from the controllers, regardless of the actions of these cordial partners who try hard to supply him with all his desires. But isn't such a relation terribly inefficient?

user2180613
  • 739
  • 6
  • 21

2 Answers2

2

The only thing your controller should care about is how to pass the data to the model and (optionally) how to ask it whether they're valid or not. The actual validation should be done inside of the model, because:

  • It is your model's responsibility to validate the data it is going to use.
  • You want to be able to reuse that model without repeating yourself.
  • You want to be able to able to substitute the model object (e.g. define a subclass with a completely different set of validation rules) and your controller shouldn't care.
lafor
  • 12,472
  • 4
  • 32
  • 35
  • Ask the model if the input is valid or not? I don't think I should make a validation function for each public function the model has and accepts arguments for. At this moment I have such a public function throw an exception if a parameter passed is invalid, is that not optimal? – user2180613 Aug 07 '13 at 21:58
  • There's a difference between validating user input and enforcing method argument type. If you're trying to do the latter with the former, you're doing it wrong. Plus, input validation shouldn't throw Exceptions. Input being invalid is definitely not an exceptional situation in a typical web application. – lafor Aug 07 '13 at 22:06
  • Passing wrong arguments to a model is exceptional however. So I could argue that a controller must check if a e-mail address is valid, if the model requires an e-mail address as parameter (whose validity it is subsequently going to check by itself). – user2180613 Aug 07 '13 at 22:13
0

It depends.

Best case for DRY (don't repeat yourself) validate in the model.

However. There can be occasion when the validation you need to perform may be tailored and specific to a certain view, and although these views might have differing requirements, input from both could be valid to the model.

Often our models validate safe input based on a database schema, whilst the controller which may validate via a form, or even a method on the model, might be concerned which much more purpose specific validation.

Validating form input for your very specific purpose, and validating that a model will be correct are not always the same thing.

Gavin
  • 2,153
  • 2
  • 25
  • 35
  • If a method of a model desires an input that complies with the rules I wrote about, the controller supposedly knows this. So shouldn't the controller ensure that it does not cause any exceptions to be thrown inside the model? – user2180613 Aug 07 '13 at 21:11
  • Yes, it should, but your model could be used outside the scope of that specific controller so must also be able to protect itself. However IMO the controller would provide validation feedback, whilst the model might throw an exception. I would prefer to see model validation that can bubble back to the controller than controller validation only, but I can think of cases when you might need to validate in the controller and the model, because you need more restrictive data than the model might allow. – Gavin Aug 07 '13 at 21:16
  • Isn't it immensely inefficient for the script if the controller checks if the input has the right length, complies with the e-mail address pattern, then pass it to the model, which will do these same checks again? – user2180613 Aug 07 '13 at 21:22
  • Possibly, but not if the model does the validation check, and remembers if it is valid. For example. In the controller $model = Model::LoadFromPostData($data); if($model->Validate()){ $model->Update(); } If you need more specific validation and only if, you can add this to the controller in addition to the model validation. – Gavin Aug 07 '13 at 21:27
  • The controller calls the model, so it won't consult the model whether or not the input it passed was valid, it will be too late by then (the model is the "last line of defence"). I used to check with `Form::mailaddressValidity` and such before passing to the model. However I realised that the model should be able to check the parameters passed, without having to rely on the controller. I could shift the Form checks to the model, that would save controller code. However, the model is not supposed to know anything about data that has been posted to the script. – user2180613 Aug 07 '13 at 21:35
  • I suppose architecture and framework can play a big factor. I agree very much with (the model is the "last line of defence") and if validation can only occur in one place that is the most secure one. – Gavin Aug 07 '13 at 21:40
  • @user2180613 The model knows everything about data posted to the script as soon as it is loaded with data. At some point you must tell the model the data! You are creating yourself artificial problems. If you cannot pass data to the model, your inefficiencies are caused by artificial rules which can be coded around quite readily. Careful not to rule yourself into a box! – Gavin Aug 08 '13 at 08:03