Seems like there's an issue with the 'sonata_type_collection' type. Let's imagine the following example (this is just a fictional example, but the scenario is exactly the same as what I have in my real application). We have 3 objects:
Now we want to be able, in the Admin, to create a Thread and at the same screen, add comments to that thread. This can be accomplished by doing something like:
// ThreadAdmin.php
protected $form = array(
'title',
'comments' => array(
'edit' => 'inline'
)
);
// CommentAdmin.php
protected $form = array(
'comment',
'user' => array('edit'=>'list')
);
// UserAdmin.php
protected $list = array(
'username' => array('identifier'=>true)
);
If you create a new Thread, you will be allowed to create new comments, inline, at the same screen, because it uses the 'sonata_type_collection'. Each Comment you add to the form will have a User element (ManyToOne relation), that will be rendered using a special widget where you can select a User via a lightbox.
So far so good, but there's a problem in this scenario. When you add a Comment, and then select a User and click save, it successfully save everything into the database, with all the relations. But after page reloads (or if you later go back to edit that Thread), all Comment entries will display BLANK user. If you change the user and save again, it correctly saves into the database, but again, once it reloads, it will be displayed BLANK. If you remove the 'edit'=>'list' and let it render a widget, it works fine.
I tried to debug myself and I tracked the issue back to the "renderFormElement" method of SonataAdminExtension class. At line 181, it calls:
return $this->output($fieldDescription, $template->render(array_merge($params, array(
'admin' => $fieldDescription->getAdmin(),
'object' => $object,
'field_description' => $fieldDescription,
'value' => $this->getValueFromFieldDescription($object, $fieldDescription, $params),
'field_element' => $children,
'base_template' => $fieldDescription->getOption('base_template', $base_template)
))));
getValueFromFieldDescription in turn does:
โฆ
$value = $fieldDescription->getValue($object);
// no value defined, check if the fieldDescription point to an association
// if so, create an empty object instance
// fixme: not sure this is the best place to do that
if (!$value && $fieldDescription->getAssociationAdmin()) {
$value = $fieldDescription->getAssociationAdmin()->getNewInstance();
}
return $value
finally, $fieldDescription->getValue($object) will end up calling $object->getUser(). But while debugging, I noticed that $object variable actually holds a PersistentCollection object instead of a real Comment object, therefore, getUser() getter is not available and we will end up with a brand new Comment instance (with everything blank).
I'm not sure if I'm at the right track, but something is not right in this scenario. Also, there's another problem (maybe related to the 1st one). Say you add two Comments to the Thread, if you set the User for the 2nd Comment and click save, any validation attached to the User entity will fail, as if it's blank.