Bind data into my form in ZF2 - php

I have a form which I use in my viewscript. My viewscript looks as follows:
<?php
$this->titel = "Arbeitskalender Termine";
$this->headTitle($this->titel);
foreach($this->aktermine as $termin) :
$this->nr=$this->escape($termin->nr);
$this->kopfnr=$this->escape($termin->kopfnr);
$this->datum=$this->escape($termin->datum);
$this->zeit=$this->escape($termin->zeit);
$this->thema=$this->escape($termin->thema);
echo $this->form ;
endforeach;
?>
I get my form (it is a table) I get the same repeats of the form like records in my table. But I don´t see any record in the form fields. What´s wrong? How can I get the values of my dataset objects in each field?
If I use a viewscript in html it works fine.

Use the the form’s bind() method to attach your model to the form. The value for each field will be extracted from the model and displayed in the form.
This is used in two ways:
When displaying the form, the initial values for each element are
extracted from the model.
After successful validation in isValid(), the data from the form is put back into the model.
To use this method you need to implement getArrayCopy() and exchangeArray() in your model Aktermine.
So in your action you'll have something like this:
$form = new YourForm();
$form->bind($aktermine);
Please see the example of Editing an Album, in the documentation.
Read also Binding Objects to Forms
If you are using doctrine, just add getArrayCopy() into your entity like this:
public function getArrayCopy(){
return get_object_vars($this);
}
And then within your controller action :
$form->bind($yourEntity);

Related

Dynamic form (switch entity) symfony2

I'm making a page for adverts. An advert can be of different types and therefore have different data. For instance, a vehicle would have the make and the model as extra data.
Right now, I've got one base doctrine entity Advert which contains the data that every advert requires. Different adverts in turn innherits this data (doctrine2 discriminatormap)
I need to populate the form dynamically (with ajax and symfony2 forms) if the user choose to create a vehicle ad I want to display the options for a vehicle advert. But I also need to change the entity to be of the form AdvertVehicle.
Is this possible? I did read the cookbook entry at the symfony2 homepage
"How to Dynamically Modify Forms Using Form Events":
This should be handled by making an AJAX call back to your application. In that controller, you can submit your form, but instead of processing it, simply use the submitted form to render the updated fields. The response from the AJAX call can then be used to update the view.
I understand how to make an ajax call back to my controller, and i understand how to use the form-events but how do I get the response of a rendered select-box (containing vehicle models for instance) back? With a new AbstractType? or formbuilder?
And then when the user actually submits the form I need to use the entity of the selected advert type. Can I change the entity according to the users choice in the form dynamically?
Edit
I checked the form innheritance out that's great, thank you. I extend the AdvertType and override the buildForm() method and before I add the items I need for the AdvertVehicleType I call the parent method.
Futher Explanation
Every advert entity contains price, description, title and category. Some adverts contains more, such as make and model. They are differentiated by the discriminatormap (doctrine2)
Example:
// -- Entity
class CarAdvert extends Advert {
protected $model;
protected $make;
}
// -- Entity
// -- This uses discriminator mapping
class Advert {
protected $title;
protected $description;
protected $price;
protected $category;
}
if the user selects the category cars I want to use the CarAdvert entity (for validation and persistance) if the user selects the house hold itemcategory I just want to use the normal Advert entity.
One major problem is still that I cannot figure out how to render the extended form via ajax. Any tips on this part? When the user selects car as a category, I want the form to be updated (via jQuery/ajax) but how do I make a controller that retrieves just the extended part of the form and sends the html back as a response (without using twig and rendering it in a view, is this possible)?
Solution:
See answer below!
Solution:
The solution to my problem was to create a few extra functions in the controller to solve the issue where I want to be able to change the entity and form "on the fly" from a selection by the user..
public function indexAction(Request $request)
{
$form = $this->getForm($request);
$form->handleRequest($request);
return array(
'form' => $form->createView(),
'request' => $request->request,
);
}
Where getForm retrieves the form, (e.g AdvertVehicleType for vehicles or AdvertType for a "default" advert).
The getForm method looks like this:
private function getForm(Request $request)
{
$categoryTitle = 'NONE';
$categoryId = $request->request->get('advert', false)['category'];
if ($categoryId) {
$categoryTitle = $this->getDoctrine()->getRepository('Bundle:Category')->find($categoryId)->getTitle();
}
return $this->createForm($this->getFormType($categoryTitle), $this->getEntity($categoryTitle));
}
here I retrieve the categoryID (that is selected in the form in the request) and retreives the formType with getFormTypeand the entity with getEntity.
private function getEntity($categoryTitle)
{
$entity = new Advert();
switch ($categoryTitle) {
case Category::CARS:
$entity = new AdvertCar();
}
return $entity;
}
private function getFormType($categoryTitle)
{
switch ($categoryTitle) {
case Category::CARS:
return new AdvertCarType();
default:
return new AdvertType();
}
}
To be able to update this "on the fly" with ajax (but it also works if the user tries to submit the form) I created another action in the controller.
This action renders the parts of the form that I want to update (on ajax call), I do this by actually picking out what I don't need in the form with twig setting the form objects to rendered like so:
{% do form.title.setRendered %}
(this is just an example I actually do this for all the form objects that I don't want to render.
I then simply just call:
{{ form_rest(form) }}
which will retrieve the "rest" of the form which is different for different categories.
Now let's say you have state and than town to select. First select the state then you render the towns for that state in twig (but then you can actually just render the part you need, e.g {{ form_row(form.towns) }} and you return this rendered template as a json-response and just put it in the div you want with jquery.
$html = $this->renderView('#Bundle/NewAddPage/filter_area.twig', array('form' => $form->createView()));
and then returning the $html variable in the response.
I hope this helps, and that the explanation is good enough, if not just make a comment and I'll update this with my answer!

Processing Zend_Form dynamically generated elements

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.

Pre-load value into field in symfony form, getting error "Cannot Update form fields"

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')
));

Best practise for handling form submission in controllers

Lets say for example I am creating a an online shop. I have a controller called products and within that controller I have a function called create_product. Create_product calls a view that displays a form where users get to enter new products into the database.
When the user fills in the form to create a product, should I send the action back to the create_product controller and handle it with an IF statement? or offload to another function?
Example
<form method="post" action="www.example.dev/products/create_product/add">
//the above form would post back to the original controller
function create_product()
{
if(uri->segment(3) == "add")
{
//call a model to do all the database stuff
}
load->view->create_product_form;
}
Is this the best way to handle this or should I be passing it off to another function?
Don't cram a ton of stuff in one function using the URI segment to filter it. createProduct() can list the products available for creation (in a CRUD format, I assume), and the submission of the form should ping another controller with the POSTed data. Perhaps insertProduct(), where the data is sanitized and sent to the model for insertion to the database.
Separation of concerns! Keep the functions as separate as possible with good descriptors for the names of the functions.
I (personally) would have a function that set the form parameters and "launch" the view with that form, and another function used to validate and call the model to put the values of that form into the database. I believe that is really up to you, but the code would be cleaner if you divide the controller with several functions depending on what they actually do.
I like the way symfony deals with forms & form submission. It is in one function (action)
simplified code:
executeCreate() {
$this->form = new Form()
if($r->isMethod('POST')) {
//handle submission
bind();
save();
}

update/validate embedded forms before saving in symfony

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

Categories