【问题标题】:Symfony2 Form Builder Select Across Join Table with MetadataSymfony2 表单生成器选择带有元数据的连接表
【发布时间】:2013-07-29 15:56:01
【问题描述】:

我有 3 个实体:

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

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

我想要一个所有类别的列表,其中包含针对会员使用的类别选中的复选框。最终我想添加优先级字段。

会员

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

会员类别

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 中是否有直接的解决方案?

【问题讨论】:

    标签: forms symfony doctrine symfony-2.3


    【解决方案1】:

    这就是我过去解决此问题的方法(应用于您的示例),但这是我想出来的,因此它可能不是 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 为您的成员添加任意数量的类别并每次分配优先级。

    【讨论】:

    • 该文档表明添加和删除类别会很麻烦,甚至涉及客户端代码。是这样还是我误读了文档?
    • 你没看错!我就是这样做的,不确定这是不是最好的方法。我也会看看其他答案,因为我同意你的看法,这是一种常见的模式,官方网站上没有任何明确的文档。
    • 谢谢,Doctrine 文档在docs.doctrine-project.org/projects/doctrine-orm/en/latest/… 中描述了如何从实体方面处理这个问题(参见用例 3)。但是他们没有提供任何关于使用 Symfony 表单的信息。
    【解决方案2】:

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

    $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为例

    【讨论】:

    • 请填写您的答案,因为主要部分已在您的答案中注释掉
    【解决方案3】:

    cheesemacfly 的帖子还不错,但它是调用嵌入形式,管理起来可能很复杂。 实际上,您只需要创建一个“自定义存储库” http://symfony.com/doc/current/book/doctrine.html#custom-repository-classes

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

    1) 在 Bundle 的存储库文件夹中创建一个新存储库

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

    请随时问我问题,我希望这就是您要找的 ;)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-03
      • 1970-01-01
      • 2013-05-11
      相关资源
      最近更新 更多