Symfony2表单生成器选择跨元素的连接表

时间:2013-07-29 15:56:02

标签: forms symfony doctrine symfony-2.3

我有3个实体:

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

就从数据库中获取结果而言,这很有效,但我无法让Form Builder构建正确的表单控件。

我想要一个包含复选框的所有类别的列表,这些复选框会针对成员使用的类别进行检查。最后我想添加优先级字段。

会员

class Member
{
    protected $id;

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

分类

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;
}

表单构建器的明显尝试无效。

如果我使用:

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

我得到一个包含所有类别的选择,但没有在MemberCategory中为此成员选择的那些类别。

如果我使用:

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

我为所有用户选择了所有选定的类别。

有谁知道如何让它工作,这是关系数据中一个明显的常见模式,使用SQL和PHP很容易。

在Symfony 2.3和Doctrine中有直接的解决方案吗?

3 个答案:

答案 0 :(得分:3)

这就是我过去解决这个问题的方法(适用于你的例子),但这是我想出来的,所以它可能不是100%适合你的情况。

首先创建符合您需求的MemberCategory表单类型:

<?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';
    }
}

然后在Member类型表单中添加此表单类型:

<?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';
    }
}

然后,您可以按照the documentation为您的成员添加任意数量的类别,并每次都分配优先级。

答案 1 :(得分:1)

您需要使用表单中的查询构建器

$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
    ));

请参阅文档以了解正确使用方法。 请参阅symfony2 form querybuilder with parameters了解示例

答案 2 :(得分:0)

cheesemacfly的帖子并不是那么糟糕,但是它是嵌入式的形式,并且管理起来很复杂。 事实上,你需要创建一个“自定义存储库”  http://symfony.com/doc/current/book/doctrine.html#custom-repository-classes

它将添加一个新的方法来“抓取”你的ORM对象与Doctrine2,如find()或findBy();

1)在Bundle的Repository Folder中创建一个新的存储库

<?php
  namespace YourVendor\SMWMemberBundle\Repository;
  use Doctrine\ORM\EntityRepository;

  class CategoryRepository extends EntityRepository{

  public function UsedByMember($member){
  return $this
         ->createQueryBuilder('c')
         ->leftJoin('c.Member', 'mc')
         ->where('mc.member = ?1')
         ->setParameter(1, $member);
}

}

2)将您的Cutom存储库附加到您的实体

namespace YourVendor\SMWMemberBundle\Entity;
use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity(repositoryClass="YourVendor\SMWMemberBundle\Entity\ProductRepository")
* @ORM\Table(name="Category") 
*/
class Category{

3)在Form类中添加一个构造函数,并传递de Entity Manager和查询所需的变量:

class CategoryUserForm extends AbstractType
{
   private $em;
   private $member ;


   public function __construct(EntityManager $em, $site, $seed)
   {
       $this->em = $em;
       $this->member = $member;

   }

public function buildForm(FormBuilder $builder, array $options)
{
    $qb = $this->em->getRepository('SMWMemberBundle:Category')->UsedByUsers($this->member);
    $builder->add('categories', 'entity', array(
        'class' => 'SMWMemberBundle:MemberCategory',
        'query_builder'     => $qb,
        'multiple'     => true,
        'expanded'     => true,
        'required' => false
    ));
 }

4)在您的控制器中,您可以像这样创建表单:

$editForm = $this->createForm(new CategoryUserForm($em, $member), $category);

随意问我问题,我希望这是你要找的;)