1

I have recently moved my form data validation to the Model layer, specifically in the Domain Objects setters (is this right or wrong?). When I am in my User service and I do this

$user->setFirstName($firstName);

and the input is too long (over 25 chars) should I set some sort of state variable in the Domain Object to unstable (maybe = 0) and set the error message in the Model for retrieval in the View?

I would check the state of the object in the View by running the isValid() method.

Would this be the correct way to do it?

Thanks.

ibanore
  • 1,500
  • 1
  • 12
  • 25
  • possible duplicate of [Validate form input in Domain Objects setters?](http://stackoverflow.com/questions/15040979/validate-form-input-in-domain-objects-setters) – tereško Feb 24 '13 at 10:26
  • possible duplicate of [Exceptions, is the message for outputting to the user or just for developers?](http://stackoverflow.com/questions/15042820/exceptions-is-the-message-for-outputting-to-the-user-or-just-for-developers) – tereško Feb 24 '13 at 10:27
  • possible duplicate of [Model now doing data/form validation. How to return user friendly error messages to the view?](http://stackoverflow.com/questions/15043946/model-now-doing-data-form-validation-how-to-return-user-friendly-error-messages) – tereško Feb 24 '13 at 10:27
  • I would throw an exception if the name is too long :) – Ja͢ck Feb 24 '13 at 10:28

2 Answers2

0

This is more of an architectural question, and there are many answers. The Grails web framework takes a similar approach to this but auto-magically adding validate() to Domain Objects. CodeIgniter has you roll your own similar.

Personally, I'm a fan of putting validation logic in setters/constructors and throwing exceptions if my preconditions aren't met. This means that rather than having an object your views have to interrogate to see if it is valid, your users must ensure they enter valid data or explicitly handle when they don't.

  • Thanks for the reply. I was trying to do it with exceptions except I ran into a problem. Example, in the `UserService` I am setting a firsName and lastName in my `User` Domain Object. I set the firstName, no exceptions, I set the lastName and It throws a `LengthException`. When I catch that exception I know it is a `LengthException` but I do not know for which field that exception was thrown. I don't want to set the exception message with the field name because apparently you are never supposed to show the exception message to the user/client. How do you get around this? – ibanore Feb 24 '13 at 09:57
  • You should set the Exception's message when you throw the Exception with something informative. If you don't want to show the message to the client, you yourself can always read it programatically and "do something interesting" (like highlighting text in red). – Visionary Software Solutions Feb 24 '13 at 10:10
  • So lets say if no lastName was supplied, in my `setLastName()` I would throw an `InvalidArgumentException('lastName')` then when catching my exceptions I can find out what required field was not supplied by doing `catch(InvalidArgumentException $ex) { $field = $ex->getMessage() }` and now I know what field threw the exception? Is this correct? – ibanore Feb 24 '13 at 10:16
  • Yup, that should do it. – Visionary Software Solutions Feb 24 '13 at 10:19
  • Is this what exceptions are for though? I thought they were mainly for developers to help debug things etc. – ibanore Feb 24 '13 at 10:20
  • **-1:** Views should never have direct access to domain objects. Data validation on setters fails, when you have multiple bound parameters. And since when CodeIgniter has become the standard of coding and design practices ?! – tereško Feb 24 '13 at 10:25
  • Exceptions are for exceptional conditions. Error Codes versus Exceptions is a long running debate. Robert Martin has a good discussion on this topic in Clean Code. – Visionary Software Solutions Feb 24 '13 at 10:26
  • @tereško How do I validate form data correctly? I used to do it in the Controllers, now I have changed to doing it in the setters but it is proving to be a bit messy, if data validation on setters fails what is the correct way to do it? – ibanore Feb 24 '13 at 10:29
  • @VisionarySoftwareSolutions since when has the submission of login form without password become an exceptional event? Also, you still have not addressed issue regarding parameters that are cannot be validated independently from others. – tereško Feb 24 '13 at 10:37
  • Clearly a form submission with an empty password should be handled at the UI layer. If it is not, and a User object is attempted to be constructed with an empty password, setter validation on `setPassword()` can raise an exception that the controller can properly handle. As for multiple bound parameters, you can easily define your own custom type of exception that handles this special case. If it spans multiple Domain objects, obviously that complex validation belongs in a service that's in charge of constructing the composite, not the individual objects themselves – Visionary Software Solutions Feb 24 '13 at 10:44
  • @tereško I just seen your reply to my other post from yesterday. I have read a million articles/posts about this topic but no examples so I end up going in the wrong direction at some stage during implementation. For coding one example is worth more than a million words I think. You say don't throw exceptions in the setter but did not advise me what to do? Return some array with information? Return false? Set some object state property to invalid? Set some message property in the object with an error message? Return a plain old message? – ibanore Feb 24 '13 at 10:50
  • So your solution is to repeat the same question again and again, and again, and again till someone give you code? Also, I did advise what to do. – tereško Feb 24 '13 at 10:55
  • He has a pretty through description of MVC in http://stackoverflow.com/questions/5863870/how-should-a-model-be-structured-in-mvc/5864000#5864000 Essentially, throwing exceptions in the setters is fine for simple self-field range validation. For cross-range (prop A depends on prop B and vice versa), or cross-Domain Object concerns, you would create a Service which would manage the creation of the individual objects and validate them accordingly. – Visionary Software Solutions Feb 24 '13 at 10:57
  • @tereško actually the first question was asking if form data should be validated in Domain Objects setters, the second was asking if an exception message should be outputted to users or is it just for coders, and the third was asking how to return user friendly messages from validation in the Model layer. And I still don't know what the setter should return/do if the data is invalid. You say don't throw exceptions, what do you return/do for invalid form data when validating in your Model layer? I am very interested. – ibanore Feb 24 '13 at 11:10
  • @VisionarySoftwareSolutions , that was the answer he got 3 questions ago: http://stackoverflow.com/a/15043523/727208 . He has just been repeating and repeating the same thing, till someone will confirm, that his initial reasoning (taken from phpmaster.com of all the placed for bad ideas) was correct. – tereško Feb 24 '13 at 11:19
  • @tereško You are way off. How is asking if my Domain Object should have an isValid() method that returns its current state the same as asking if the message in exceptions is only for developers and not for the end user or asking how to get user friendly error messages from the Service layer to the UI repeating the same thing? And still no example given of how you do it. Is there any website or book that has information you don't conflict? Where did you learn to code, from some programming God only you have seen? I would love to see your code, honestly. It must be complete perfection. – ibanore Feb 24 '13 at 11:30
  • 1
    @tereško Also on this post: http://stackoverflow.com/questions/15040979/ you said "setters should not be validating the data" at the top of your post, then you said I have two validation options one of which is "validation in each setter" and then at the bottom said "validation in setters is only the viable solution." and in this post right here above me you said "Data validation on setters fails, when you have multiple bound parameters.". What am I supposed to take from that? One example would clear it up, I have seen enough writing with no implementation that's why I am here. – ibanore Feb 24 '13 at 12:00
0

I'd say form validation has nothing to do in domain objects. If a submitted form is invalid there usually is no reason to create/modify a domain object at all, it is an issue that lies completely in the presentation layer/user interface. Putting validation of user input into the domain objects violates the separation of concerns principle.

However, it is a controversial question and there is no absolutely right or wrong way to do it. Because if you want to ensure that a domain object can't be in an invalid state (throwing exceptions in constructor and setters) you might end up with duplicate code.

But if you use validation in domain objects for form validation or not, you should prefer exceptions over a isValid state. The objects should always be in a valid state, this is one major advantage of OOP

Update

To the question where I put input validation: I use specialized request objects for each controller and use them in the controller like this:

try {
    $user = $this->request->extractUserFromPost();
} catch (ValidationException $e) {
    $this->showValidationError($e->getMessage(), $e->getAffectedFields());
}

The methods could also be in the controller itself but I prefer thin controllers that contain as little own logic as possible. Another common method are form objects that manage generation and validation of forms at one place (Example: Zend\Form). If the request always comes from a form, this makes sense. My example above would work for a web service as well as for an HTML user interface.

Fabian Schmengler
  • 24,155
  • 9
  • 79
  • 111
  • And where would you put said validation to not violate it? In the controller? In request abstraction? In storage abstraction? – tereško Feb 24 '13 at 10:32
  • Do you know what "domain object" is an what are its responsibilities? – tereško Feb 24 '13 at 10:54
  • Yes. What are you implying? – Fabian Schmengler Feb 24 '13 at 11:00
  • http://c2.com/cgi/wiki?DomainObject – tereško Feb 24 '13 at 11:14
  • There is nothing about user input validation in this definition. If you refer to "validate themselves", I wrote about that in my answer too, but distinguished it from input validation. Think about a registration form where you have to enter your email address twice. Would you give your user domain object two email attributes? I hope not! – Fabian Schmengler Feb 24 '13 at 12:10