Complex object validation with Symfony Validator - php

I have an object (a person) which is being edited (and validated) over several forms:
personal data form
first name
last name
file input for photo upload
account data form
email
publishing form
can publish only if all required fields have been filled
What I need is to have validations that I can use per-form and also for the whole person, e.g the errors would be:
personal data form - “please fill your first name”, …
whole person - “please fill your personal data”, …
If I define validations in Entity, there might still be some rules that are form-only (file upload, password repeat); it seems kinda wrong anyway because I might have different rules for web form and for API. Then again if I define validations in Form classes, then the rules are scattered around, also how can I initiate validation without form submission (which seems a hackish thing to do anyway).
Most elegant solution seems to me a separate validator which I can divide into validation groups and call it per-form and for whole object. How to do that using compound validator so that I can use other validators?
Or is there another way? Thank you.
Symfony verson is 6.

Related

CakePHP highly integrated SignUp Form

I just wonder how to build up a signup form like this with cakephp 2.x:
A member can have multiple workingtimes and multiple vacationtimes.
There should be one large signup form with one submit button and 3 visually separated areas: memberdetails, workingtimes, vacationtimes.
During signup a member should enter his personal data inside memberdetails and add arbitrary workingtimes as well as arbitrary vacationtimes in the designated areas before hitting the submit button. All the entered times should be listed tabular inside the form before submitting the whole form. At some point the memberdetails, workingtimes and vacationtimes look good and the user submits the form(I know that this is only the ideal situation and there are missing some functions).
My first approach was including the forms for adding workingtimes and vacationtimes inside the members form and send serialized form data via Ajax-POST to the other controller actions (Workingtime->add, Vacationtime->add) and also load the whole related data with something like a crud index function via Ajax and inject the response into the signup form without reloading it. This seems to keep things like validation, security component or the view layout simple, because most of the work will be done by cakephp and not with javascript, but I think it only works if I have allready a database ID for the member - after this I can store workingtimes and vacationtimes. Like allready said, I would prefer one form with one submit button and be able to cancel the whole registration even if there where allready added workingtimes or vacationtimes.
So what is the cake way to achive an integrated form like this? Is it useful to start a transaction and create a dummy member when the form is loading? And then use the ID of this dummy record to store the related workingtimes and vacationtimes? And when hitting the submit button the dummy member is updated to store the entered personal data and everything can be commited? Or should the entered related model data only be validated without saving and then just cache these data for a final transaction block?
Any other ideas?
I think the best approach for this is to manage states. Allow user to enter the basic data, change state, and then you can ask for more information but you will have already a user id to associate and match info. If the user comes back later it will have the current state already.
With Cake, a Component would help you to go from one step to another. Each data you enter should be validated.

Form::file: How to repopulate with Input::old After Validation Errors and/or on Update?

In my PhotosController, I am trying to modify the edit action so that it shows the existing value in the Form::file() input field (and, so that it repopulates the field if validation fails).
if ($validation->passes())
{
// saves the image on the FS and updates the db entry
}
return Redirect::route('photos.edit')
->withInput(Input::all())
->withErrors($validation)
->with('message', 'There were validation errors.');
The uploading process works fine, but when I view an existing record, or if validation fails upon creation, the Form::file doesn't show the value. I looked up the method in the api, and it only accepts the name and optional options arrays. Whereas, the other methods in the FormBuilder class allow us to set the value using Input::old().
I've tried passing in the following values to withInput, but they've been to no avail:
* Input::all()
* Input::old()
* Input::except('photo_path')
* Input::get('photo_path')
How can I update this so that if validation fails, or if a user views an existing record, the Form::file() method will show the existing value?
I'm sure that I'm overlooking something incredibly simple because I haven't found other threads of people asking this...
Apparently you can't.
Browsers don't allow you to set a value on a file input for security reasons.
There are two silimar questions, not laravel related but i think answers could help you:
Can you re-populate file inputs after failed form submission with PHP or JavaScript?
Restoring the value of a input type=file after failed validation
Maybe your best shot would be to make the validation client-side (javascript/jquery).
Of course there has to be (ALWAYS) server-side validation. (remember javascript can be disabled on client-side).
But I believe that, this way 99.99% of the cases, the form submission will be successful!
Basically, when is indeed submit, it is already validated with sames rules as the servers, so it will not submit until it is not "as the server likes" :)
Cheers
For complex form submits I would recommend to use AJAX:
You may do a first AJAX form send that does the server side validation.
Then, if it's all fine you should launch via Javascript the form POST with file input.
I've answered a similar question for Laravel there but I hope it will be helpful for a general approach: Laravel 5.1: keep uploaded file as old input
Remove the redirect, your validation and input values should show on the same page, only redirect upon success.

codeigniter - what if I don't have any model?

It's the first time I'm using an PHP framework and I have a question regarding this design pattern.
Let's say I'm trying to build an php app that has a contact us page (which will ask for the name, email address comment etc and once submitted it will simply use the mail function to send an email to the admin). I know what my view is gonna be, I will also use a controller to render the view, but what should be my model? I'm not going to load anything from the database or save anything to the database. So in this case should I skip the model?
I’d say that, even with a contact form, a model has its use.
A contact form handles enquiries, a contact form has fields, and a contact form usually requires some form of validation. This can be wrapped up in an Enquiry model.
In fact, this is exactly what I do with CakePHP applications. I have an Enquiry model that defines the fields and data validation, and saves any enquiries to the database (for archiving purposes) and has an afterSave callback method that sends me the enquiry details via email. I’m sure you could do something analogous in CodeIgniter.
the gritty details go in the model. even a simple contact form has lots of gritty specific details: names of fields, specific validation rules, etc.
the controller is the boss - validate this form! it does not say how to validate it, and it doesn't need the details of each field in the form. if the form validates - the controller calls the next view. if it does not validate - then the controller shows the form again and maybe passes specific error messages.
the validation details for the contact form - put that in a model.
the emailing of the form: the content of the email, taking the form values and putting it into the email, who the email goes to, the details of actually sending the email - that is all work for a model.
what does this gain us? when your client calls in a year and says - change the text in the email - you won't be hunting through a bunch of controller code. you will look at your model names and know exactly where to go. separation of concerns is not just for building - its for the inevitable changes that happen over time.
EDIT
yes the business logic should be in the model. so like for a contact form the business rules might be - we ask for name and address - and we require the email address and phone number. the validation rules then fulfill the business rules.
then six months later your client calls and says - well people don't like us requiring the phone number - just make the email required. you have put those validation rules in your model - therefore it is only that specific model which needs to change. the controller does not change at all! and since you separated the form validation rules from the sending of the email into separate models - if you make a mistake when changing the validation rule - its much less code to look through and debug.
the other way to look at is - how specific and 'granular' is the method? the more specific it is, the further from the controller it should be. the controller methods should rarely change because of changes to business rules.
so when i said the controller orders "validate this form" - i just meant that the controller is calling the validation method that is in the model, and then its getting back true or false, no matter what changes happen to the form over time.
Models are optional in Codeigniter. If you don't need one then don't use one.
Models are optionally available for those who want to use a more traditional MVC approach.
Documentation
In your particular case you have no need of a model so don't worry about making one.
OP here, just want to do a quick update on this.
I have looked at CodeIgniter's documentation, and surprisingly found out that the form validation code is inside the controller:
http://ellislab.com/codeigniter/user-guide/libraries/form_validation.html#validationrules
which IMO is not a good idea.
Fortunately, there is a way to clean up the controller, which requires you to create a form validation config file inside the config folder:
http://ellislab.com/codeigniter/user-guide/libraries/form_validation.html#savingtoconfig
since I don't want to reinvent the wheel, I guess I will just create the config file without creating the model

Symfony2/DC2/PHP: prevent the user from creating someone elses entity

I have the entities Floor and LeaseTerm. Floor can have many LeaseTerms.
In my LeaseTerm CREATE form, I have a hidden floor_id field.
My question is: how can i effectively prevent the user from changing the floor_id field himself and creating LeaseTerms for floors he doesnt own (each floor has it's owner)?
Conceptually the 'how' is to validate the floor_id upon submission, ensuring that the current user owns/has access to the floor. Theoretically even if they do change it, so long as it's still an id they have access to, the operation is probably still valid (if not, additional validations on the submission context would be necessary).
In Symfony 2 as a specific implementation this could be achieved with the logic directly in a controller, or perhaps alternatively with help from a 'Data Transformer' and/or Custom Validator.
Hope this helps.

i want to add captcha with ajax

well i have a form in which email and captcha validation was there but now i want to do some thing like if captcha is incorrect or left empty than my form must not reload the page i.e all those field which are already been filled out must not get blank.
You can either
A) Submit the form as you are doing right now, and fill the fields with the existing field data
B) Use a CAPTCHA library that supports AJAX submission, e.g. reCAPTCHA http://wiki.recaptcha.net/index.php/Overview#AJAX_API
I believe that (A) is a lot better because it allows you to deal seamlessly with all other kinds of validation. But depending on what you already have (B) might be trivial to implement. So YMMV.

Categories