Search code examples
formssymfonyentities

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?


Solution

  • 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...