I have a dynamic form.
For exemple, if something, my form contains FormType1 else my form contains FormType2 or FormType3 ....
I would detect if my form is modify.
If my form is completed, I apply is valid() method and if there is an error I return in the form or if there is no error, I apply a redirection.
I know how to do that.
But, if my fom was submitted without modifications (with no new value) I want to apply an other redirection without validation because my validation will return false with required fields.
I can't test if all values are null because in form there may be combobox or boolean, or initial value, ...
I have a solution with javascript and two submit buttons.
If the value of button submit is 'just_redirection' I don't apply the validation else I apply validation.
Is there a way in Symfony2 (or full PHP) to know if the submitted form is the same that the initial form?
Let's assume your form is bound with an entity MyEntity, in your controller you need to copy your original object, let the form handle the request, then compare your objects:
public function aRouteAction(Request $request, MyEntity $myEntity)
{
$entityFromForm = clone $myEntity;
// you need to clone your object, because since PHP5 a variable contains a reference to the object, so $entityFromForm = $myEntity wouldn't work
$form = $this->createForm(new MyFormType(), $entityFromForm);
$form->handleRequest($request);
if($entityFromForm == $myEntity) {
// redirect when no changes
}
if($form->isValid()) {
// redirect when there are changes and form submission is valid
}
else {
// return errors
}
}
For object cloning please refer to the php manual.
Related
I'm trying to figure out how to work with dynamic forms/form types in Symfony 2. I've managed so far, but what I don't know and can't find is how to redirect after the POST_SUBMIT event.
Do I do it inside the controller or does it happen directly in the form type class? What happens atm is the page reloads, but the data in the page is not updated. Plus I would like to redirect to another page.
Thanks in advance.
From the doc :
if ($form->isValid()) {
// perform some action, such as saving the task to the database
return $this->redirect($this->generateUrl('task_success'));
}
the isValid() method will return true only when a POST request has been performed and when the data sent is valid.
If you want to redirect after POST request even in the case the form is not valid, you can do this :
public function newAction(Request $request)
{
// ...
if ($request->isMethod('POST')) {
if ($form->isValid()) {
// perform some action...
}
return $this->redirect($this->generateUrl('page_after_post_request'));
}
// ...
}
in all the examples I find of Zend_Form the view showing the form corresponds to the action in which it is processed. However, I want a view that displays multiple independent forms and separate actions to process each of the forms (whose view is not used).
Redirect to individual actions is not a problem, the forms are processed there but when validation errors appears, I want them displayed on the common view next to each item, Zend_Form style. As I understand, when a form is populated (with invalid data) errors are displayed automatically. Then, when a form is invalid, I use FlashMessenger to store the invalid content, then redirected to the main common action and populate the form with him.
The problem arises with the password fields. These, of course, refuse to be populated, and therefore do not show any error message. Could I display it without having to manually figure out which error occurred?
Thank you for your attention and your patience with my english :P
PS: For better understanding i append a sample code explaining what I do...
class TestController extends Zend_Controller_Action
{
...
public function commonAction() {
/*Initialize form objects*/
$form1 = new Application_Form_Form1();
...
$formN = new Application_Form_FormN();
/*Fill forms if needed*/
$flashMess = $this->_helper->FlashMessenger;
if ($flashMess->hasMessages()) {
$messages = $flashMess->getMessages();
switch ($messages[1]) {
case 'form1':
$form1->populate($messages[0]);
break;
...
case 'formN':
$fotmN->populate($messages[0]);
break;
default:
...
break;
}
}
/*Assign to the view*/
$this->view->form1 = $form1;
...
$this->view->formN = $formN;
}
public function form1Action() {
if ($this->getRequest()->isPost()) {
$form1 = new Application_Form_Form1();
$data = $this->getRequest()->getPost();
if ($form1->isValid($data)) {
...
} else {
$this->_helper->FlashMessenger($data);
$this->_helper->FlashMessenger('form1');
}
}
$this->redirect('/test/common');
}
...
}
As I understand, when a form is populated (with invalid data) errors
are displayed automatically.
This is not the case, if you populate the form with invalid values, you will have to call isValid again in order to run the validators and mark the form and elements with the appropriate error messages.
You could also save the error messages for each element in the FlashMessenger and then re-attach the error messages back to each element, but you can also call isValid again. If you ever used a form with a File element, you would have to save the error message as you would not be able to re-populate the element with the uploaded file.
The problem arises with the password fields. These, of course, refuse
to be populated.
If you set the renderPassword flag (ex: $el->setRenderPassword()) on each password field, they will populate along with the rest of the values and when you call isValid, the password field will be validated and any appropriate error message would show up.
Hope that helps.
I need to create a form where the elements (texbox, select, ..) will be dynamically inserted. Right now I have created a empty Form file with just a hidden element and them in my controller I go inserting elements according to certain conditions.
My form file:
class Form_Questions extends Zend_Form {
public function __construct() {
parent::__construct($options);
$this->setName('Questions');
// Hidden Label for error output
$hiddenlabel = new Zend_Form_Element_Hidden('hiddenlabel');
$hiddenlabel->addDecorator(new Form_Decorator_HiddenLabel());
$this->addElements( array($hiddenlabel) );
}
}
In the controller I have something like:
...
$form = new Form_Questions();
$request = $this->getRequest();
if ($request->isPost())
{
$formData = $request->getPost();
if ($form->isValid($request->getPost()))
{
die(var_dump($form->getValues()));
}
}
else
{
//... add textbox, checkbox, ...
// add final submit button
$btn_submit = new Zend_Form_Element_Submit('submit');
$btn_submit->setAttrib('id', 'submitbutton');
$form->addElement($btn_submit);
$this->view->form = $form;
}
The form displays fine but the validation is giving me big trouble. My var_dump() only shows the hidden element that is staticly defined in the Form file. It does not save the dinamic elements so altought I can get them reading what's coming via POST, I can not do something like
$form->getValue('question1');
It behaves like if Zend uses the Form file to store the values when the submit happend, but since the elements are created dinamically they do not persist (either their values) after the post so I can not process them using the standar getValue() way.
I would appreciate any ideas on how to make them "live" til after the post so I can read them as in a normal form.
The form which you are calling isValid() and getValues() methods on is actually your "empty" form - you have instantiated it only a few lines up and haven't added any elements to it at that point.
Remember that POST only sends an array of fieldName => fieldValue type, it doesn't actually send a Zend_Form object.
It is difficult to suggest a new solution without knowing what you are trying to achieve. It is generally better to add all possible elements to your Zend_Form right away, and then only use the ones you need in the view scripts, i.e. echo $this->form->myField;. This will allow isValid() to process all the elements of the form.
It sounds like the form is dynamic in the sense that the questions come from a db, not in then sense that the user modifies the form itself to add new questions.
Assuming this is the case, then I wouldn't add the question fields in the controller. Rather, I'd pass the questions to the form in the constructor and then add the question fields and the validators in the form's init() method. Then in the controller, just standard isPost() and isValid() processing after that.
Or, if you are saying that the questions to be added to the form are somehow a consequence of the hidden label posted, then perhaps you need two forms and two actions: one for the hidden field form and another for the questions.
Ok, the simplest solution I came up with - to my case and considering the really of the code I am currently playing with was to load all the questions I need from the database using a method from my Model (something like fetchQuestions()), them in my controller I go throught the recordset and create the form elements according to the current question of the recordset.
The elements are stacked in an array that is passed to my Form constructor. In the form constructor I read the array and generate all the dynamic elements. I them just echoed the form to the view.
I have not seem why it would be a bad idea to override the Form constructor as I also could not use any of the set/get methods to pass this to my form.
I have a form that is supposed to create a very simple new entry into the database. One of the fields in this table is related to another table. Specifically, there is an event that people attend, and I need to assign people to an event. Each event can have several people attending, and there can be several events.
When an admin user adds members to an event, I don't need them selecting the event on the actual form, this should be passed via the URL. e.g.
event/new/id/1
However, I am really struggling as to how to include that ID in the form. If I try and manually set the field value, I get the error Cannot Update Form Fields
e.g.
$this->['attendanceSuccess_id'] = 1;
If I try and hide the field:
$this->widgetSchema['attendanceSuccess_id'] = new sfWidgetFormInputHidden();
The form shows but obviously no value is passed and I get "that fields is required error"
This seems like a really simple and common thing to do, but I can't find any solutions! How can I pass a URL value into a form where the field points to another class?
Here's what I've done. Basically your form holds a hidden with the id, and your action gets it from the request and puts in into the form as an option. In the form you can also set the relationship to the Doctrine objects.
Your form should have something like (I don't know what your form should extend exactly since you are using Doctrine and mine was in Propel)
class SomethingForm extends BaseSomethingForm {
public function __construct($object = null, $options = array(), $CSRFSecret = null)
{
parent::__construct($object, $options, $CSRFSecret);
if (isset($options['person_id']))
{
$this->getObject()->setPersonId($options['person_id']);
$this->setDefault('person_id', $options['person_id']);
}
}
}
public function configure()
{
$this->setWidget('person_id', new sfWidgetFormInputHidden());
...more stuff...
}
Then your action says:
$this->form = new SomethingForm(null, array(
'person_id' => $request->getParameter('person_id')
));
I would like to validate an embedded form field before it gets saved in the database. Currently it will save an empty value into the database if the form field is empty. I'm allowing empty fields, but I want nothing inserted if the form field is empty.
Also quick question, how to alter field values before validating/saving an embedded form field?
$this->form->getObject works in the action, but $this->embeddedForm->getObject says object not found
I found a really easy solution. The solution is to override your Form's model class save() method manually.
class SomeUserClass extends myUser {
public function save(Doctrine_Connection $conn = null)
{
$this->setFirstName(trim($this->getFirstName()));
if($this->getFirstName())
{
return parent::save();
}else
{
return null;
}
}
}
In this example, I'm checking if the firstname field is blank. If its not, then save the form. If its empty, then we don't call save on the form.
I haven't been able to get the validators to work properly, and this is an equally clean solution.
Symfony gives you a bunch of hooks into the form/object saving process.
You can overwrite the blank values with null pre/post validation using by overriding the the doSave() or processValues() functions of the form.
You can read more about it here: http://www.symfony-project.org/more-with-symfony/1_4/en/06-Advanced-Forms#chapter_06_saving_object_forms