I'm not sure if this is limited to Yii2 or if it could be also discussed with other frameworks or even in general.
In Yii2 I can call validate() on a model object. This will return true or false. If it is false I can call getErrors() to see which validation problems currently exist within this object.
Why is this behavior implemented this way? Why does validate() not throw some ValidationExceptions? I find it also somehow strange that errors are part of the model object. Why are they not part of such an exception?
What are the advantages of this implementation? Why is it done this way? I would prefer exceptions. With this, I could better distinguish between desired and exceptional processing. All that is not desired is handled in catch blocks. The desired happens in try blocks. Isn't this a good idea?
Because in general the errors are used in combination with a form.
Let's say you have a form with some input fields (linked to the model attributes/properties) and you want to do something with these fields, maybe save them or something.
Before saving the fields you would like to verify that they are all valid. When the validate() method is called all attributes are validated one by one and each one will generate an error if needed. If the validation is false and you have an error collection you can again show the form, but this time attach the errors to the fields.
If you throw an exception each time an error occurs your application would stop running and only display the one error. Or you would have to write try-catch blocks for all attributes, which is just unnecessary. When your validation returns true you can run the next step which does the processing and you can be sure all values are valid.
If you really want exceptions you can, of course, write your own Validators (http://www.yiiframework.com/doc-2.0/yii-validators-validator.html)
Related
I have hit upon a problem with breeze validation.
It seems highly likely that the root cause of this particular problem is due to what looks like a design flaw in breeze. Specifically, that validation errors are not assigned a copy of the validation message generated by its validator. Instead the message is generated each time using the context last supplied to the validator.
This would not be a problem until you realise that validator errors generated from the same validator all share a reference to that same validator instance and that this validator instance uses the last context that was supplied to it to form the validation message.
The consequence of the above is probably best explained with the following scenario:
you have more than one instance of the same entity bound to a page
both entity instances break a rule defined by the SAME validator instance
for each entity instance, different context values are used
the two error messages generated for BOTH validation errors are determined by the last context supplied to the validator
therefore the message for the first validation error uses the context supplied for the second
Like I say, I think this is a design flaw but am happy for explanations why this isn't the case AND alternative means for avoiding the above scenario that don't feel like a hack.
Thanks
It seems like official way to validate models in Laravel 4 is through Validator in Controller? Can somebody point out why is it so?
Wouldn't it make more sense to implement validation in Model?
I prefer the Ardent package for making validation of models as smooth and minimal as possible. To me it makes more sense to have the validation rules in the model as well.
It will return false when $model->save() is called and validation fails, then you can get the error messages through $model->errors()->all() for example.
It does make sense to have validation in the models, but this validation should only be there to make sure you don't save any corrupt data.
The Validator is in the Controller because it's used to handle Input, and generate Output.
If you would do the validation in the Model then you either have to return false, and show the user the most random of error messages about invalid data.
You could also return some kine of array containing all the errors that are generated, but that's something a Model shouldn't do.
Or you could throw an Exception, which is something that should be done when a model tries to consume invalid data, but it kills the application, which is not the wanted solution for a form validator.
When doing the form validation in the Controller, you can do everything you want with the error messages, without changing the purpose of a Model.
And in your model you can do a validation to make sure you didn't make a mistake, which will corrupt your database. Because if this happens the application should shut down.
So to put this in a real answer to your question:
Validation in the model makes sense to avoid corrupt data, but if you want to give feedback to the user about invalid input, it should be in the controller.
I wrestled with this for a while and settled on handling most of my validation in a validation service, based something along the lines of this. I can then have different validation rules based on the context.
As Nico mentions, validation in the model is good to avoid corrupt data, but I prefer thin controllers so I pass the functionality that would sit in controller into the service. This also has the benefit of being able to reuse the validation in different controllers/methods.
Why I prefer In-Model Validation: I've worked with both styles and each have pluses and minuses, but I prefer in-model validation. In our current app I don't see in-controller validation as an option, since we're altering our data in so many places (dedicated forms, inline edit, bulk edit, bulk upload, api, etc). I've never really worked with validation services (though they might be an option) but I personally like to keep logic as close to the model as possible, that way I know another developer won't bypass it. I also don't like adding lots of extra files on top of the MVC and basic Libraries folder because it just seems like more you have to think about organizing properly.
Issues with In-Model Validation: These are some things you need to consider to make In-Model work well. SOME OF THESE ARE ALREADY TAKEN INTO CONSIDERATION BY PLUGINS. I think other frameworks (CakePHP) already deal with these, but Laravel doesn't really.
Values that will be validated but not saved to the db (e.g.,
"accepted_agreement").
Many to many or belongs to many
relationships
Setting conditional defaults (not critical but
might want to think about at the same time)
Various form scenarios - sometimes you might need different validation
depending upon which form submits it. The form reference can be a
purgeable attribute for validation maybe?
How will you get back error messages (all in-model validation plugins handle this for you)
Different validation rulesets. Draft creation vs "real" creation. (Most handle this for you)
Ultimately, for simple applications that don't have lots of ways of interacting with the model, I'd say controller validation may be simpler, other then that I prefer in-model.
As far as I can see, the validation within Entity Framework is built entirely around the assumption that, if an item fails its validation, it must not be persisted to the database. Is there any mechanism, possibly running parallel to normal validation, of making a constraint on a field produce a warning to the user, rather than an error which prevents the record from being saved/updated?
To be more specific, I have a situation where a particular numerical field has limits on it, but these are advisory rather than hard-and-fast. If the user enters a value outside these limits, they should get a warning, but should still be able to save the record.
In theory, I could subclass the ValidationResult class to make, say, a ValidationWarning class, then create a custom subclass of ValidationResults whose IsValid property was sensitive to the presence of ValidationWarning messages, and ignored them in deciding whether the entity is valid. However, this requirement has arisen in a project which is already someway along in its development, and it would require a lot of refactoring to make this kind of custom subclassing work properly. I would prefer to find a mechanism which could be levered in without creating that much disruption/rework.
I had a similar requirement on a project and how I solved it was this. If (ModelState.IsValid) is false, I cleared out the errors out of the ModelState and sent it on its way again,then logged the "error" to another service. This is a bit of a hack and I would'nt recommend doing as it is not exactly best practice.
Suppose I have a service StateService which has a method ChangeState.
ChangeState(State toState, DomainObject object)
I have business rules that checks whether the destination state is valid or not in the domain objects current "state", how can I technically check those rules without first setting the toState on the domain object? It feels wrong to first set the new state, run validation and if one or more rule breaks unset the state.
One solution I came up with is to create some context object that drives the validation eg.
ChangeStateContext that contains the DomainObject along with the State that is to be set.
Another related question is how to report back from the ChageState call how it went?
I can collect all validation rules that broke and throw an exception with those rules that the caller can catch and handle accordingly or I can add a return type on the ChangeState-method like ValidationSummary that contains information about broken rules and such. What is best practices in these cases?
Can't you throw an exception from the ChangeState method when the state transformation is invalid? You can throw specific exceptions such as StateTransformationException or ValidationException that you can catch higher on the call stack. You can optionally include extra properties to these exception types so that you can communicate very precisely what went wrong to the user.
When you want to call multiple ChangeStates after a single user action, you will need a way to revert or rollback. What I usually do is using the unit of work pattern (supplied to me by LINQ to SQL and Entity Framework) and change all state within this unit of work. When an exception is thrown I throw away the complete unit of work with all its changes.
The DomainObject class could have a public bool CanChangeState(State toState) instance method, returning True if toState is a valid transition from the current state of the subject DomainObject. Such method can be called prior to the StateService.ChangeState call.
Of course, if the StateService is responsible for the state change validation, then a CanChangeState(State toState, DomainObject obj) method should be added to the StateService.
To report back the validation error messages, change the return Type of the CanChangeState to a custom Type responsible for reporting validation errors.
I often see people validating domain objects by creating rule objects which take in a delegate to perform the validation. Such as this example": http://www.codeproject.com/KB/cs/DelegateBusinessObjects.aspx
What I don't understand is how is this advantageous to say just making a method?
For example, in that particular article there is a method which creates delegates to check if the string is empty.
But is that not the same as simply having something like:
Bool validate()
{
Result = string.IsNullOrEmpty(name);
}
Why go through the trouble of making an object to hold the rule and defining the rule in a delegate when these rules are context sensitive and will likely not be shared. the exact same can be achieved with methods.
There are several reasons:
SRP - Single Responsibility Principle. An object should not be responsible for its own validation, it has its own responsibility and reasons to exist.
Additionally, when it comes to complex business rules, having them explicitly stated makes validation code easier to write and understand.
Business rules also tend to change quite a lot, more so than other domain objects, so separating them out helps with isolating the changes.
The example you have posted is too simple to benefit from a fully fledged validation object, but it is very handy one systems get large and validation rules become complex.
The obvious example here is a webapp: You fill in a form and click "submit". Some of your data is wrong. What happens?
Something throws an exception. Something (probably higher up) catches the exception and prints it (maybe you only catch UserInputInvalidExceptions, on the assumption that other exceptions should just be logged). You see the first thing that was wrong.
You write a validate() function. It says "no". What do you display to the user?
You write a validate() function which returns (or throws an exception with, or appends to) a list of messages. You display the messages... but wouldn't it be nice to group by field? Or to display it beside the field that was wrong? Do you use a list of tuple or a tuple of lists? How many lines do you want a rule to take up?
Encapsulating rules into an object lets you easily iterate over the rules and return the rules that were broken. You don't have to write boilerplate append-message-to-list code for every rule. You can stick broken rules next to the field that broke them.