Should my Domain Objects have an isValid() method

2019-07-27 08:16发布

问题:

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.

回答1:

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.



回答2:

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.