In Symfony 2.5.10, I have multiple form types, each with their own validation groups, calling various class constraints. Each type represents a particular step in a workflow. The final step iterates over all other steps, performs the necessary validation and displays any possible violations to the user.
The data behind each form type (data_class) is always the same: a doctrine entity.
Each displayed violation links to the URL/path representing the step in question, with an additional parameter which, when present, should trigger the validation. The idea is that the form should display the errors immediately, without submitting. In other words, I wish to trigger form submission programmatically (server-side, not JS!).
I've tried various different ways:
Somehow put the entity (which I have) into the request and set the method of the latter to POST, so that Form::handleRequest handles everything automatically. Problem: converting the entity object to an array, as would be returned from a real form submission. Maybe a DataTransformer? PropertyAccessor?
As 1. but call Form::submit instead. See http://symfony.com/doc/2.5/cookbook/form/direct_submit.html#calling-form-submit-manually
Validate myself (in the same way I do in the final step), giving me a ConstraintViolationList. Iterate over the list and call Form::addError for each violation. Problem: I need to add the errors to the correct child elements, not just the parent. Maybe I could do this using the propertyPath of each error, but how to go from that to child form?
Any help would be much appreciated. I've trawled stackoverflow and the web in general, but to no avail.
First way looks good. You just should check the ajax form and them just use something like
$entity = $form->getData()
to retrieve data from form (which could be array, entity, or some other stuff you have in you form).
Then just pass this entity to the twig view to form an request answer. Alongside with entity you might want to provide form errors aquired from $form->createView() FormView object.
I am submitting a form with a lot of fields and trying to validate it with handleRequest($request) as it is shown in the Symfony documentation.
My entity is very big and has a lot of relations with other entities.
handleRequest($request) is validating each form field submitted and checking for errors.
The problem found is while submitting an id of a related entity of my main entity (in example a person of an office), handleRequest will internally get all objects of the related entity (the full table of the related entity, all persons) and hydrating them as objects.
I think it should just check if the submitted id exists in the other table, get that related entity object and check it for errors (instead of getting all the related table).
If you check and debug the source code of Symfony2 handleRequest, you may easily spot the same problem at this lines:
Form/Form.php
// Normalize data to unified representation
$normData = $this->viewToNorm($viewData);
$value = $transformers[$i]->reverseTransform($value);
How can I still validate the form without dealing with this issue which makes it insanely slow to validate a form with handleRequest($request)?
If I don't use handleRequest to validate it, which automatically add the errors to my form for each field, how could I manually validate each field and later add the errors to my form for each field and show them in the next view?
This question is a little vague, and the answer very much depends on your specific form. Please post the form definition that is giving you the hardest time.
Check to make sure that you are not EAGER fetching associations here.
handleRequest() is going to take the request object and construct the model that your form describes, as your form defined it to.
If the objects are required in order to display data on your initial form to the user, or to validate the data on submit, the "entity" field type will fetch all of the objects you told it to in its definition. If you are displaying a big select list, for example, all of this data is needed.
I had a similar problem in the past and it was because I was using a lot of choice fields that were being used as a series of multiple select checkboxes. My bottleneck was actually in the twig layer while rendering out the thousands of checkboxes I had stored as separate entities.
I switched from a set of checkboxes to a single multi-select box and it increased my speed significantly.
in my case, after having a similar behaviour I detected that it was a problem in my xdebug configuration. By editing php.ini and disabling xdebug I found that everything went much faster. It can be interesting to do this check when all else fails. I'm leaving this message here in case it might be of help to someone else.
one "simple" question: http://mwop.net/blog/2012-07-02-zf2-beta5-forms.html
is it possible to use the zf2 zend form annotation validation rules without using zend form, so i can share the validation rules between a model validator (e.g. using for check if the model is correct before persisting it) and the zend form validation?
if my "name" should be not empty and between 5 and 20 characters, it is the same rule for the form and the model.
i hope i pointed it out clearly
Roman
Well, since all data that the models are getting would be from user input or the database, you shouldn't need to test the models itself, too. THe data inside the database should be correct!
IE: trust your own data but not the users?
But if you still wanna do that, i guess you could build the form with the AnnotationBuilder, then get the InputFilters from the Form (im sure there's a method, maybe on per-element-basis) and then use those inside your models - but as my first paragraph implies, i see this as a quite useless point :)
As for multi usable input filters, best thing would be to write own classes extending Zend\InputFilter\InputFilter on a per model basis. When you build your form then you can attach that class as the filter definition via $form->setInputFilter($myModelInputFilterClass) and you could also call that class inside your models to run your data through those filters. I haven't done this manually but it should work.
The only pitfall i guess might happen if you run into required statements. Checking on a per element basis, i don't know if that will work, too. As the InputFilter checks against all given filters. Though if you import a full CSV-Sheet or something you'd have a populateFromCsv() function or something that then checks all data anyways i guess.
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?
Ideally, you want 3 layers of validation:
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
}
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.
For my framework I've written down this concept to solve the form validation problem. I want it to be as straightforward as possible for the framework user.
Every Form (=object) has one or many FormElements (=objects). Every FormElement can have 0-n FormValidators (=objects). Everything easily configured through the backend (simple drag&drop stuff).
When the Form View is rendered, it loops over all the FormElements, and for each of them it loops over all their associated FormValidators. That way it builds up all the needed JavaScript to validate the form on client side.
A FormValidator is an lightweight object which defines only these seven things:
PHP class name of the validation utility class
method name of the validation utility class, which must be called
a string for additional arguments (comma-separated values)
JavaScript "class" name of the validation utility
"method" name which must be called
a tring for additional arguments (comma-separated values)
an associated ErrorInfo object which contains an formatted error message
Every of these validation methods takes as first argument an input variable with the input data. Every of these methods just check the input if it matches some rule(s), and returns TRUE or FALSE.
When the form is submitted, an FormDataManager is created and receives:
- the Form object (so it knows from where the data came from)
- the input data (typically $_POST)
It then just iterates over all the FormElements, checks all their FormValidators, and if anything is invalid, it reloads the Form which is passed the error messages array. If everything is fine, the data is further processed (i.e. stored to db).
Are there improvements in this design? Anything I've missed?
One common validation concept which I think you have missed is validation groups. For instance, you may want to cater for one of the following scenarios:
Form field B is mandatory only if field A has any value.
Form field B is mandatory only if field A has a specific value.
Form field B is mandatory only if field A is in a specific range (numerical or dates).
Either field A OR field B needs to have a value (they cannot both be empty).
Either field A OR field B needs to have a value (they cannot both be empty or both have a value) - (XOR).
Password and confirm password fields need to be equal.
And I'm sure there are other scenarios where validation depends on the validity or optional aspect of other form elements. Also - 'mandatory' in the scenarios above may also be simply 'applicable', which would be a different situation again.
Typical (medical system) example here is: "Are you male/female?", with a follow-up of "Are you pregnant?" for females. Or AOP related questions, where you have the birthday and have a certain follow-up question only IF they are 65 years or older.
It means you need some validationgroup or validation association object that contains these dependencies in a useful and generic way.
I guess in your design it means you can also have FormValidator objects that are not directly linked to one FormElement but to a combination of FormElements and include a conditional check before triggering validation.
Sounds interesting. I think you're on the right track, especially because it sounds like you are validating both client side and server side.
One thing that you should do (and I might have missed this when reading your question) is make sure that the validation also happens on the server as well. That way your form information is still validated even if someone turns off or tinkers with the javascript.