I have a date that I'd like to set as the default value the current date and most of the posts suggest to add the 'data' => new \DateTime() but there are two issues with that in Sonata:
if I change the date to a random one or even leave it empty, it will still save in the database the current one
in the edit view it will override the date from the create view and the value will still be the current date
My code:
$form->add('startDate', DateType::class, [
'required' => false,
'label' => 'Starting date',
'data' => new \DateTime("now"),
'constraints' => ...
])
]);
What am I missing?
The data attribute will overwrite data in all cases, as you can read here in DateType Field#data.
What you can do is set a default value in the entity instead as described in What is the best way to set defaults values of a Symfony object?
In the entity, you would have the following:
private $startDate = new \DateTime("now");
The downside of this is that it also adds the default value when the entity is created outside of Sonata.
Related
Here is some code of my Type Class. For one of the property I use a ModelTransform to display what I want :
$builder->add('myProperty', 'text', array(
'label' => 'MyLabel',
'required' => true,
'disabled' => true
));
$builder->get('myProperty')
->addModelTransformer(new CallbackTransformer(
function($propertyFrom) {
return (round($propertyFrom/ 100, 3)) + 1;
},
function($propertyTo) {
return round((($propertyTo- 1) * 100), 3);
}
));
it works good when I display my form in the twig.
I would like to get the entity from my form. I guessed, assuming I have my Form object, I would do like this :
$entity = $form->getViewData()
I wanted to have the entity with the value of the fields passed through the ModelTransform. Though I have the value of field with no transformation.
Finally I wonder what is the difference between $form->getData() and $form->getViewData().
How can I get the entity with the values transformed by my ModelTransformer ?
It is a Symfony bug that does not apply transformer via the getViewData on the object. But it does it on the field.
getViewData vs. getNormData and DataTransformers - different results depending on context
This is a kind of limitation because compound forms having an object or array as underlying data, don't keep their view data synchronized with their children's view data. https://github.com/symfony/symfony/issues/18683#issuecomment-249676768
You can get the difference thus:
// if myProperty value is equal to 23
$form->get('myProperty')->getData(); //output: 23
$form->get('myProperty')->getNormData(); //output: 1.23
$form->get('myProperty')->getViewData(); //output: "1.23"
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)
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.
I have 2 entities in my bundle that are audited via simplethings/entity-audit.
I would like to add a field to REVISIONS table call "reason". Every time a user updates or delete an entity, he/she needs to especicify an reason for doing that (why updating/deleting) via form, and this reason should be associated to the entity revision.
How would you guys do it? I dont have much experience in OOP.
Thank you very much in advance.
for adding field you need to add field in your database like 'ip' next you change your bundle in file "logRevisionsListener.php"
private function getRevisionId()
{
if ($this->revisionId === null) {
$this->conn->insert($this->config->getRevisionTableName(), array(
'timestamp' => date_create('now'),
'username' => $this->config->getCurrentUsername(),
'ip' => $this->config->getCurrentUsername(),(not correct just for test it give me the user name)
), array(
Type::DATETIME,
Type::STRING,
Type::STRING
));
.
.
}
I added here the ip field and change your Revision.php file by adding your field with the getter method
I have added a field on the page_node_form with the following code.
switch($form_id){
case 'page_node_form':
$form['comment_popup'] = array(
'#type' => 'select',
'#title' => t('Comments popup'),
'#options' => array('On' => 'On', 'Off' => 'Off'),
);
}
As the comment form appears on the node so I want when the comment_popup field has the value Off then the subject field should not be displayed in the comment form and when the comment_popup field has the value 'On' then the subject field should be displayed.
I have tried the following code but it did not work.
case 'comment_node_page_form':
if($form_state['comment_popup']['#value'] == 'Off') {
$form['subject']['#access']=FALSE;
}
Any one who can help me?
What you're doing can't work I'm afraid, you're setting an element in one form and then trying to read it from another form which doesn't make sense.
What you need to do is add a submit handler to the page_node_form function which saves the comment_popup value for that node to a custom table. Then in the form alter for `comment_node_page_form' you need to read in the comment_popup data for that particular node, and make the access decisions to the form elements based on that.
Hope that helps