How to load only a subset of a OneToMany associati

2019-05-21 19:02发布

I have two entities: A and B. A is associated to B through a OneToMany association:

class A
{
    // ...
    /**
     * @ORM\OneToMany(targetEntity="..\AcmeBundle\Entity\B", mappedBy="A", fetch="EXTRA_LAZY")
     */
    private $things;

    public function __construct()
    {
        $this->things = new ArrayCollection();
    }

    // ...
    // addThing(), removeThing() and getThings() are properly defined

I have a Form class for the A entity:

class AThingsType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('things', 'collection', array(
                'type' => new BType()
            ))
            ->add('send', 'submit')
        ;
    }

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

    public function getName()
    {
        return 'a_things';
    }
}

The BType class contains fields to define the forms of B, there is nothing particular in it.

And I use this form from my controller:

$a = $em->getRepository('AcmeBundle:A')->getAWithSubsetOnly($A_id);

$form = $this->createForm(new AThingsType (), $a /* instance of A*/);

Then the form is rendered in the Twig template.

It will add one BType for each element in A->things but I want to display only a subset of the A->strings values, because the current user doesn't have the rights to modify all the A->things, he can only update some of these B entities. I don't know how to do this, because the whole collection of A->things is loaded automatically (even if a do a ->innerJoin() to fetch only a subset of the things) so the form display all the BType whereas I only want to display some of them (based on a SQL query).

Now the fields are hidden by calling {% do form.contenu.setRendered %} in Twig but I hope there may be a better solution.

1条回答
冷血范
2楼-- · 2019-05-21 19:17

The problem is likely you're not explicitly selecting the entities you want in your DQL/QueryBuilder call in your getAWithSubsetOnly repository method.

For example, this will get a user and if I wanted to display all its logs as a collection in my form, will lazy load all logs regardless of my criteria:

$userData = $this->getEntityManager()
    ->createQueryBuilder()->select('u') // constraint ignored
    ->from('SomeUserBundle:User', 'u')
    ->join('u.logs', 'l')
    ->where('l.id < 20880')
    ->andWhere('u.id = 7')
    ->getQuery()->getSingleResult();

If you explicity tell doctrine to fetch the sub entity at join like below, it won't lazy load the collection & you will get your filtered collection subset:

$userData = $this->getEntityManager()
    ->createQueryBuilder()->select('u, l') // constraint taken into account as
                                           // logs not lazy loaded
    ->from('SomeUserBundle:User', 'u')
    ->join('u.logs', 'l')
    ->where('l.id < 20880')
    ->andWhere('u.id = 7')
    ->getQuery()->getSingleResult();

You'll also save yourself a lot of lazy loading SQL queries with this approach.

查看更多
登录 后发表回答