3

The question is similar to this one, but there is a huge difference: I do not have a fixed number of elements that I want to add.

Beneath is a preview of the form and how it should look like. I have a form for a user entity which includes different application entities and each application entity has several number of user group entities.

The way my form should look like - nested entities

User

class User extends BaseUser
{
...

/**
 * @ORM\ManyToMany(targetEntity="Application", inversedBy="users")
 * @ORM\JoinTable(name="users_applications")
 */
protected $applications;

/**
 * @ORM\ManyToMany(targetEntity="UserGroup", inversedBy="users")
 * @ORM\JoinTable(name="users_groups")
 */
protected $user_groups;

Application

class Application
{
...

/**
 * @ORM\ManyToMany(targetEntity="User", mappedBy="applications")
 */
protected $users;

/**
 * @ORM\OneToMany(targetEntity="UserGroup", mappedBy="application")
 */
protected $user_groups;

User group

class UserGroup
{
...

/**
 * @ORM\ManyToOne(targetEntity="Application", inversedBy="user_groups")
 * @ORM\JoinColumn(name="application_id", referencedColumnName="id")
 */
protected $application;

/**
 * @ORM\ManyToMany(targetEntity="User", mappedBy="user_groups")
 */
protected $users;

UserFormType

class UserFormType extends AbstractType
{
    // Array of applications is generated in the Controller and passed over by the constructor
    private $applications;

public function buildForm(FormBuilderInterface $builder, array $options)
{
    ...

    if ($this->applications && count($this->applications) > 0)
    {
        foreach ($this->applications AS $application)
        {
            $builder->add('applications', 'entity', array
            (
                'class' => 'MyBundle:Application',
                'property' => 'title',
                'query_builder' => function(EntityRepository $er) use ($application)
                {
                    return $er->createQueryBuilder('a')
                        ->where('a.id = :id')
                        ->setParameter('id', $application->getId());
                },
                'expanded' => true,
                'multiple' => true
            ));

            $builder->add('user_groups', 'entity', array
            (
                'class' => 'MyBundle:UserGroup',
                'property' => 'title',
                'query_builder' => function(EntityRepository $er) use ($application)
                {
                    return $er->createQueryBuilder('ug')
                        ->where('ug.application = :application')
                        ->setParameter('application', $application);
                },
                'expanded' => true,
                'multiple' => true
            ));
        }
    }
...

PROBLEM: I have already managed to include the application and user group entities, but since the application entities are added to the formbuilder by a loop, entities are overwritten, such that having multiple applications only one application gets rendered.

2
  • 2
    we have some sort of simmilar setup for nested forms but we use collections, maybe it can be a solution for your problem! symfony.com/doc/current/cookbook/form/form_collections.html Commented Oct 24, 2013 at 9:00
  • You traying to add the same field on each iteration (name applications). Its not possible. I suggest create special type for this field with entity subtypes Commented Nov 1, 2013 at 9:55

1 Answer 1

4
+50

You do want collections. Collections allow for an arbitrary number of elements (which meets your requirements). I think the problem is you should have a UserGroupType so that collections work the way you want.

Here is more or less a complete example of your form types. Namespaces and other things omitted.

Controller (remember, you are passing in the User object to the form, don't do what you were doing with private $applications):

...
$user = ...;
$form = $this->createForm(new UserFormType(), $user);

Changes to UserFormType:

class UserFormType extends AbstractType
{
    // Don't have that $applications member here...

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        //...

        // Your user has many UserGroups, so display each one as a UserGroup field (see UserGroupFormType)
        $builder->add('user_groups', 'collection', array(
            'type'   => new UserGroupFormType()  // I would make this type a service (http://symfony.com/doc/current/book/forms.html#defining-your-forms-as-services)
        ));
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Namespace\Entity\User'
        ));
    }

    // ... getname, etc.
}

New UserGroupFormType:

class UserGroupFormType extends AbstractType
{

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // Each UserGroup has 1 application and multiple users
        // The entity fields allow you to select these

        $builder->add('application', 'entity', array
        (
            'class' => 'MyBundle:Application',
            'property' => 'title',
            'query_builder' => function(EntityRepository $er) use ($application)
            {
                return $er->createQueryBuilder('a')
                    ->where('a.id = :id')
                    ->setParameter('id', $application->getId());
            },
            'expanded' => true,
            'multiple' => false
        ));

        $builder->add('users', 'entity', array
        (
            'class' => 'MyBundle:User',
            'property' => 'title',
            'query_builder' => function(EntityRepository $er) use ($application)
            {
                return $er->createQueryBuilder('ug')
                    ->where('ug.application = :application')
                    ->setParameter('application', $application);
            },
            'expanded' => true,
            'multiple' => true
        ));
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Namespace\Entity\UserGroup'
        ));
    }

    // ... getname, etc.
}

See also http://symfony.com/doc/current/cookbook/form/form_collections.html That shows you how to handle adding new UserGroups in the form (if you want that functionality).

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your efforts! The problem in your solution is that I would not get the hierarchical structure I want: 1. application1; 1.1. group1; 1.2. group2; 2. application2 etc. Second thing is that I edit the user entity and I want to select the app/group - in your solution I would edit the usergroup entity. In the mean time I have splittet the entity-assignment to several forms - but I will mark your answer as accepted.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.