Does the symfony form fields initialize to null if not visible - forms

I have few fields on the form like name, description, timestamp.
Now in the form I am only displaying name and description but not timestamp.
public function __construct()
{
$this->setTimestamp(new \DateTime());
}
Now in my database, it is coming as null.
Either doctrine is not executing constructor or those fields are set to null when displayed in form.
Even though I am not displaying them.

You need put the timestamp field in your FormType.
If you don't need to show it, just hide the field and set default value.
Something like that:
$builder->add('timestamp', 'hidden', array(
'data' => new \DateTime(),
));
Don't forget {{form_rest(form)}} at end of the twig template to send all hidden fields.

Related

Accessing normalized form data in a controller in Symofny 2

I had to add a form event listener (PRE_SUBMIT) to my FormType in order to set a default value of a field based on the value of another field submitted by the user:
//In my FormType:
public function onPreSubmit(FormEvent $event)
{
$formData = $event->getData();
if (empty($formData['time_until'])) {
$date = new \DateTime($formData['time_from']);
$date->add(new \DateInterval('PT1H'));
$formData['time_until'] = $date->format('Y-m-d H:i');
}
$event->setData($formData);
}
time_unti key is set and later its value is mapped onto the form's time_until field which is of datetime type:
->add('time_until', datetime, [
'required' => false,
'input' => 'datetime',
'widget' => 'single_text',
'format' => 'yyyy-MM-dd HH:mm',
'label' => false,
])
No problem so far. However, I need to have access to the normalized values of the form fields in my controller, and not DateTime objects that are present on the form after the call to $form->handleRequest($request);
By "normalized", I mean I want to be able to do:
$form->get('time_until') and have a string in the form 'yyyy-MM-dd HH:mm' returned, and not the DateTime object stored in the form under time_until key.
Advice would be much appreciated. Thank you!
you could just add some attribute $normalizedTimeUntil in your form type class + add getter getNormalizedTimeUntil() that would return this value. Then in Form event you can set this attribute and in controller you can pull it out of form type object with the getter function
or you can add non-mapped string form field timeUntilString (http://symfony.com/doc/current/reference/forms/types/form.html#mapped) and fill it in form event
or you can add transformer (http://symfony.com/doc/current/cookbook/form/data_transformers.html) to transform this Datetime object into string. This would be convienent if you for example need to store date in string form in the database). Then form field getter would return string in controller (and would get stored in the db in string also)

How to perform add action in a form only one time, after update the record everytime

I have a form element. When I click the submit button it will add the data to the table.
that is working fine. But my need is to add data to the table only the first time, after each submission data should updated.how we can do this?
function add(){
if(!empty($this->data)){
$this->loadModel('Defineroute');
$this->Defineroute->create();
$this->Defineroute->save($route_data); //route_data is data from the form
}
}
I have one more doubts, I have a view.ctp in the controller I have a view() function for that. But in the view.ctp I use one form element.
How we can write function for that element in the controller? When I try to write function, it shows the error missing view..
CakePhp determines if it should update an existing record or insert a new record based on the presence of the primary key ('id') inside the data you're saving;
This will insert a new record:
$route_data = array(
'Defineroute' => array(
'name' => 'I am a new record'
)
);
$this->Defineroute->save($route_data);
And this will update an existing record;
$route_data = array(
'Defineroute' => array(
'id' => 123,
'name' => 'I will update record with ID 123'
)
);
$this->Defineroute->save($route_data);
To accommodate this in a single form, create the form inside your view/element and only add an input for the id field if you're editing an existing record
Also see Saving your data

A set of fields for one property entity in Symfony 2

My Product entity has the following structure:
private $id;
private $title;
/**
* #ManyToOne(targetEntity="Category")
* #JoinColumn(name="cat_id", referencedColumnName="id")
*/
private $category;
Category have nested structure. And each level of nesting is shown in 5 separate fields:
In class form code, I solve it in this way:
$builder
->add('cat_1', 'entity', array(
...
'query_builder' => function() { return someSelectLogic1(); }
))
->add('cat_2', 'entity', array(
...
'query_builder' => function() { return someSelectLogic2(); }
))
->add('cat_3', 'entity', array(
...
'query_builder' => function() { return someSelectLogic3(); }
))
->add('cat_4', 'entity', array(
...
'query_builder' => function() { return someSelectLogic4(); }
))
->add('cat_5', 'entity', array(
...
'query_builder' => function() { return someSelectLogic5(); }
))
Now I need to know which field is filled in the last turn and pass the value of that field in the entity property.
In all that I do not like:
complex logic to determine which field with category was filled at the end
each of these fields is not tied to the entity 'mapped' => false
1) What the right way to organize code of my form?
2) And is there a way to bring these fields into a separate class which will deal with the logic of determining which category was chosen in the end?
I would suggest the following:
1) Create a new custom form field type and put all those entity in there.
This process is not much different from ordinary creation of form type. Just enclose those fields in it's own buildForm() and that should do the trick. Docs.
2) Mark all those entity fields with property "property_path => false".
Clearly you wont be storing these values inside your model.
3) Add two more fields: chosen and lastOne.
Now, this might be tricky: I would either set the chosen to text type (basically, generic type) or would use entity as well. If you go for entity you would need to include all possible answers from all entity fields. As for the lastOne set it to text as it will reflect which field (by name) was selected last.
Either way, those two fields will be invisible. Don't forget to set property_path to false for lastOne field.
4) Finally, add ValueTransformer (docs) which will contain logic to "see" which field was selected last.
Now, I dealt with it only once and don't understand it just quite yet, so your best bet would be trial and error with examples from official docs, unfortunately.
What basically you should do is to, within value-transformer, read the value of field lastOne. This will give you the name of field which was selected last. Then, using that value, read the actual last value selected. Last, set that value (object, if you've went for entity type, or it's ID otherwise) to chosen field.
That should basically do the thing.
As for the JS, I don't know if you're using any framework but I will assume jQuery. You will need to set lastOne field as your selecting items in your form.
$(function(){
$('#myform').find('select').on('change', function(){
var $this = $(this);
$this.closest('form').find('#__ID_OF_YOUR_LASTONE_FIELD').val($this.attr('name'));
});
});
I'm sorry I cannot provide you with code samples for PHP right now. It's a bit late here and will do my best to further update this answer tomorrow.

Entity mapping in a Symfony2 choice field with optgroup

Suppose to have an entity in Symfony2 that has a field bestfriend, which is a User entity selected from a list of User entities that satisfy a complex requirement.
You can render this field in a form by specifying that it is an entity field type, i.e.:
$builder->add('bestfriend', 'entity', array(
'class' => 'AcmeHelloBundle:User',
'property' => 'username',
));
This form field is rendered as a <select>, where each one of the displayed values is in the form:
<option value="user_id">user_username</option>
So, one would render the field by using the <optgroup> tags to highlight such special feature of the friends.
Following this principle, I created a field type, namely FriendType, that creates the array of choices as in this answer, which is rendered as follows:
$builder->add('bestfriend', new FriendType(...));
The FriendType class creates a <select> organized with the same <option>s but organized under <optgroup>s.
Here I come to the problem! When submitting the form, the framework recognize that the user field is not an instance of User, but it is an integer. How can I let Symfony2 understand that the passed int is the id of an entity of type User?
Here follows my solution.
Notice that it is not mentioned in the Symfony2 official docs, but it works! I exploited the fact that the entity field type is child of choice.
Hence, you can just pass the array of choices as a param.
$builder->add('bestfriend', 'entity', array(
'class' => 'AcmeHelloBundle:User',
'choices' => $this->getArrayOfEntities()
));
where the function getArrayOfEntities() is a function that fills the choice list with the friends of my friends, organized by my friends:
private function getArrayOfEntities(){
$repo = $this->em->getRepository('AcmeHelloBundle:User');
$friends = $repo->findAllFriendByComplexCriteria(...);
$list = array();
foreach($friends as $friend){
$name = $friend->getUsername();
if(count($friend->getFriends())>0){
$list[$name] = array();
foreach($friend->getFriends() as $ff){
$list[$name][$ff->getUsername()] = $ff;
}
}
}
return $list;
}
I know the example could be meaningless, but it works...
PS: You need to pass the entity manager to let it working...

Symfony : entity field validator and ajax dynamic content

I have 2 entities (A and B) with a Many to One relationship between them.
I create my form with the A entity and i use an entity field (dropdown list) to display the rows in the B entity. I use a query builder to filter them. If don't change the values in the list (ie. with ajax), everything is working fine.
But if I change dynamicly the values in the dropdown, when I submit the form I have this error "This value is invalid"
It's because the submitted value isn't included in the "array" returned by the query builder.
It seems that this validation is automatic in symfony for entity field (I don't use any asserts on this field). I'd like to get rid of this. But how ?
To answer my question a bit more explicitly :
The PRE_BIND form event can be redefined with an event listener in the function BuildForm like this example :
$factory = $builder->getFormFactory();
$builder->addEventListener(FormEvents::PRE_BIND, function($event) use ($factory) {
$form = $event->getForm();
$case = $event->getData();
$id = $case['id'];
if ($case) {
$form->remove('id');
$form->add($factory->createNamed('hidden', 'id',$id, array()));
}
});
For Symfony 2.3 you need to add the auto_initialize = false and change the order of params:
$form->add($factory->createNamed('id', 'hidden', $id, array('auto_initialize' => false)));