Search code examples
phpmysqlsymfonysymfony-formsdql

Symfony Form for ManyToMany Entity using a custom query builder


The error message looks like this:

[Semantical Error] line 0, col 58 near 'events = :eventId': Error: Invalid PathExpression. StateFieldPathExpression or SingleValuedAssociationField expected.

Which is right, since it's a ManyToMany join, with a join table. But how do I have to load those entities?

The problem is in the activity form (at the end). I try to load town's which are assigned with a ManyToMany join to an specific event. Code says more than 1000 words, so take a look (:

So I have three Entities in a Symfony app. Event, Town, Activity

The Event looks like this:

// ...

/**
 * @var string
 *
 * @ORM\Column(name="name", type="string", length=255)
 * @Gedmo\Versioned
 */
private $name;

/**
 * @ORM\ManyToMany(targetEntity="Town", inversedBy="events")
 * @ORM\JoinTable(name="Events_to_Towns")
 **/
private $towns;

/**
 * @ORM\OneToMany(targetEntity="Activity", mappedBy="event")
 */
private $activitys;

// ...

The Town looks like this:

// ...

/**
 * @var string
 *
 * @ORM\Column(name="name", type="string", length=255)
 * @Gedmo\Versioned
 */
private $name;

/**
 * @ORM\ManyToMany(targetEntity="Event", mappedBy="towns")
 */
private $events;

/**
 * @ORM\OneToMany(targetEntity="Activity", mappedBy="town")
 */
private $activitys;

// ...

The Activity looks like this:

// ...

/**
 * @var string
 *
 * @ORM\Column(name="name", type="string", length=255)
 * @Gedmo\Versioned
 */
private $name;

/**
 * @ORM\ManyToOne(targetEntity="Town", inversedBy="activitys")
 * @ORM\JoinColumn(name="town_id", referencedColumnName="id")
 */
private $town;

/**
 * @ORM\ManyToOne(targetEntity="Event", inversedBy="activitys")
 * @ORM\JoinColumn(name="event_id", referencedColumnName="id")
 */
private $event;

// ...

That's all working. However the problem is in the form for an Activity, when I'd like to assign a Town, or multiple. I try to only load towns that are mapped to the event.

// ...

public function __construct($eventId) {
    $this->_eventId = $eventId;
}

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $eventId = $this->_eventId;

    $builder
        // ...

        // this work's as expected!
        ->add('category', 'entity', array(
            'required'      => true,
            'label'         => 'Kategorie',
            'class'         => 'FooEventBundle:Category',
            'property'      => 'name',
            'query_builder' => function(\Foo\EventBundle\Entity\CategoryRepository $er) use ($eventId) {
                return $er->createQueryBuilder('c')
                    ->select('c')
                    ->where('c.event = :eventId')
                    ->setParameter('eventId', $eventId)
                ;
            }
        ))

        // here's the problem!
        ->add('town', 'entity', array(
            'required'      => true,
            'label'         => 'Stadt',
            'class'         => 'FooEventBundle:Town',
            'property'      => 'name',
            'query_builder' => function(\Foo\EventBundle\Entity\TownRepository $er) use ($eventId) {
                return $er->createQueryBuilder('t')
                    ->select('t')
                    ->where('t.events = :eventId')
                    ->setParameter('eventId', $eventId)
                ;
            }
        ))

        // ...

    ;
}

// ...

Solution

  • Something like:

                $er->createQueryBuilder('t')
                ->select('t')
                ->join('t.events', 'e')
                ->where('e.id = :eventId')
                ->setParameter('eventId', $eventId)
    

    Should work.