Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2 Form Builder Select Across Join Table with Metadata

I have 3 entities:

[Member] ----OneToMany----> [MemberCategory] ---ManyToOne---> [Category]

This works well as far as fetching results from the database, but I can't get the Form Builder to build a correct form controls.

I want a list of all categories with checkboxes that are checked for those categories that are used by the member. Eventually I want to add the priority field.

Member

class Member
{
    protected $id;

    @ORM\OneToMany(targetEntity="MemberCategory", mappedBy="member")
    protected $categories;
}

Category

class Category
{
    protected $id;

    @ORM\Column(name="category_name", type="string", length=50, nullable=false, unique=true)
    private $categoryName;
}

MemberCategory

class MemberCategory
{
    @ORM\Id
    @ORM\ManyToOne(targetEntity="Member")
    @ORM\JoinColumns({
    @ORM\JoinColumn(name="member_id", referencedColumnName="id", onDelete="CASCADE")
    private $member;

    @ORM\Id
    @ORM\ManyToOne(targetEntity="Category")
    @ORM\JoinColumns({
    @ORM\JoinColumn(name="category_id", referencedColumnName="id", onDelete="CASCADE")
    private $category;

    @ORM\Column(name="priority", type="integer", nullable=true)
    protected $priority;
}

Obvious attempts with the form builder that don't work.

If I use:

$builder->add('categories', 'entity', array(
    'class'        => 'SMWMemberBundle:Category',
    'property'     => 'categoryName',
    'multiple'     => true,
    'expanded'     => true,
    'required'     => false
));

I get a select with all the categories, but none of those selected in MemberCategory for this member.

If I use:

$builder->add('categories', 'entity', array(
    'class'        => 'SMWMemberBundle:MemberCategory',
    'property'     => 'category.categoryName',
    'multiple'     => true,
    'expanded'     => true,
    'required'     => false
));

I get all selected categories for all users.

Does anyone know how to get this to work, this is an obvious common pattern in relational data and would be easy using SQL and PHP.

Is there a straight forward solution in Symfony 2.3 and Doctrine?

like image 742
Peter Wooster Avatar asked Jul 29 '13 15:07

Peter Wooster


2 Answers

This is how I resolved this problem in the past (applied to your example) but this is what I figured out so it might not be 100% right for your case.

First create a MemberCategory form type matching your needs:

<?php    
namespace Company\YourBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class MemberCategoryType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('priority')
            ->add('category', 'entity',
                    array('property' => 'name',
                        'class' => 'CompanyYourBundle:Category'))
        ;
    }

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

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

Then add this form type inside your Member type form:

<?php

namespace Company\YourBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class MemberType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('name')
            ->add('members', 'collection', array(
                'type' => new MemberCategoryType(),
                'allow_add' => true,
                'allow_delete' => true,
                'by_reference' => false,));
        ;
    }

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

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

Then you can follow the documentation to add as many categories as you want to your members and assigning a priority every time.

like image 78
cheesemacfly Avatar answered Nov 12 '22 02:11

cheesemacfly


You will need to use the querybuilder inside your form

$builder->add('categories', 'entity', array(
        'class' => 'SMWMemberBundle:MemberCategory',
        'property'     => 'category.categoryName',
        'query_builder' => function(EntityRepository $er ) use ( ? ) {
           return $er->createQueryBuilder( ? )

          // your query with a left join probably

         }
        'multiple'     => true,
        'expanded'     => true,
        'required' => false
    ));

See documentation for proper use. see symfony2 form querybuilder with parameters for an exmple

like image 1
Pierrito Avatar answered Nov 12 '22 03:11

Pierrito