What I\'m trying to achieve is a create/edit user tool. Editable fields are:
The workaround solution suggested by Jeppe Marianger-Lam is at the moment the only one working I know of.
I changed my RoleNameType (for other reasons) to:
The problem was my custom type label rendered NAME property as
role name
And since it was not "read only" the FORM component expected to get NAME in POST.
Instead only ID was POSTed, and thus FORM component assumed NAME is NULL.
This lead to CASE 2 (3.2) -> creating association, but overwriting ROLE NAME with an empty string.
This workaround is very simple.
In your controller, before you VALIDATE the form, you have to fetch the posted entity identyficators and get matching entities, then set them to your object.
// example action
public function createAction(Request $request)
{
$em = $this->getDoctrine()->getEntityManager();
// the workaround code is in updateUser function
$user = $this->updateUser($request, new User());
$form = $this->createForm(new UserType(), $user);
if($request->getMethod() == 'POST') {
$form->bindRequest($request);
if($form->isValid()) {
/* Persist, flush and redirect */
$em->persist($user);
$em->flush();
$this->setFlash('avocode_user_success', 'user.flash.user_created');
$url = $this->container->get('router')->generate('avocode_user_show', array('id' => $user->getId()));
return new RedirectResponse($url);
}
}
return $this->render('AvocodeUserBundle:UserManagement:create.html.twig', array(
'form' => $form->createView(),
'user' => $user,
));
}
And below the workaround code in updateUser function:
protected function updateUser($request, $user)
{
if($request->getMethod() == 'POST')
{
// getting POSTed values
$avo_user = $request->request->get('avo_user');
// if no roles are posted, then $owned_roles should be an empty array (to avoid errors)
$owned_roles = (array_key_exists('avoRoles', $avo_user)) ? $avo_user['avoRoles'] : array();
// foreach posted ROLE, get it's ID
foreach($owned_roles as $key => $role) {
$owned_roles[$key] = $role['id'];
}
// FIND all roles with matching ID's
if(count($owned_roles) > 0)
{
$em = $this->getDoctrine()->getEntityManager();
$roles = $em->getRepository('AvocodeUserBundle:Role')->findById($owned_roles);
// and create association
$user->setAvoRoles($roles);
}
return $user;
}
For this to work your SETTER (in this case in User.php entity) must be:
public function setAvoRoles($avoRoles)
{
// first - clearing all associations
// this way if entity was not found in POST
// then association will be removed
$this->getAvoRoles()->clear();
// adding association only for POSTed entities
foreach($avoRoles as $role) {
$this->addAvoRole($role);
}
return $this;
}
Still, I think this workaround is doing the job that
$form->bindRequest($request);
should do! It's either me doing something wrong, or symfony's Collection form type is not complete.
There are some major changes in Form component comeing in symfony 2.1, hopefully this will be fixed.
... please post the way it should be done! I'd be glad to see a quick, easy and "clean" solution.
Jeppe Marianger-Lam and userfriendly (from #symfony2 on IRC). You've been very helpful. Cheers!