【问题标题】:Map a form's text field to an entity's ArrayCollection将表单的文本字段映射到实体的 ArrayCollection
【发布时间】:2014-12-28 22:51:06
【问题描述】:

我正在使用tagsinput 的表单上使用标签:

这个插件以一个包含用逗号分隔的标签的文本字段结束(例如:tag1、tag2、...)

这些标签目前在一个非映射的表单域上管理:

    $builder
       // ...
       ->add('tags', 'text', array(
               'mapped' => false,
               'required' => false,
       ))
    ;

最后,它们存储在一个 ArrayCollection 中,如 this is a bad practice to store multiple values in a database field

/**
 * @var ArrayCollection[FiddleTag]
 *
 * @ORM\OneToMany(targetEntity="FiddleTag", mappedBy="fiddle", cascade={"all"}, orphanRemoval=true)
 */
protected $tags;

要将我的表单映射到我的实体,我可以在我的控制器中执行一些代码,如下所示:

    $data->clearTags();
    foreach (explode(',', $form->get('tags')->getData()) as $tag)
    {
        $fiddleTag = new FiddleTag();
        $fiddleTag->setTag($tag);
        $data->addTag($fiddleTag);
    }

但乍一看,这似乎是错误的方式。

我想知道将我的实体映射到我的表单并将我的表单映射到我的实体的最佳做法是什么。

【问题讨论】:

    标签: php forms symfony arraycollection


    【解决方案1】:

    这很棘手,因为您不只是嵌入标签表单的集合,也就是说,所有单独的文本字段。我想你可以通过一些技巧来做到这一点,但是使用数据转换器呢?您可以将逗号分隔的标签列表转换为 ArrayCollection 并将其传递回表单,另一方面,获取集合并将标签作为逗号分隔的字符串返回。

    数据转换器

    FiddleTagsTransformer.php

    <?php
    
    namespace Fuz\AppBundle\Transformer;
    
    use Doctrine\Common\Collections\ArrayCollection;
    use Symfony\Component\Form\DataTransformerInterface;
    use Fuz\AppBundle\Entity\FiddleTag;
    
    class FiddleTagTransformer implements DataTransformerInterface
    {
    
        public function transform($tagCollection)
        {
            $tags = array();
    
            foreach ($tagCollection as $fiddleTag)
            {
                $tags[] = $fiddleTag->getTag();
            }
    
            return implode(',', $tags);
        }
    
        public function reverseTransform($tags)
        {
            $tagCollection = new ArrayCollection();
    
            foreach (explode(',', $tags) as $tag)
            {
                $fiddleTag = new FiddleTag();
                $fiddleTag->setTag($tag);
                $tagCollection->add($fiddleTag);
            }
    
            return $tagCollection;
        }
    
    }
    

    注意:您不能将 ArrayCollection 类型指定为 public function transform($tagCollection),因为您的实现应该与接口匹配。

    表单类型

    第二步是替换你的表单字段声明,这样它就会透明地使用数据转换器,你甚至不需要在你的控制器中做任何事情:

    FiddleType.php

    $builder
       // ...
       ->add(
            $builder
                ->create('tags', 'text', array(
                        'required' => false,
                ))
                ->addModelTransformer(new FiddleTagTransformer())
       )
    ;
    

    验证

    您可以使用@Assert\Count 来限制允许的标签数量,如果您的 FiddleTag 实体本身有一些验证约束,则可以使用@Assert\Valid

    小提琴.php

    /**
     * @var ArrayCollection[FiddleTag]
     *
     * @ORM\OneToMany(targetEntity="FiddleTag", mappedBy="fiddle", cascade={"all"}, orphanRemoval=true)
     * @Assert\Count(max = 5, maxMessage = "You can't set more than 5 tags.")
     * @Assert\Valid()
     */
    protected $tags;
    

    进一步阅读

    请参阅 Symfony2 关于数据转换器的文档:http://symfony.com/doc/current/cookbook/form/data_transformers.html

    查看这些帖子了解其他一些想法:

    Parsing comma separated string into multiple database entries (eg. Tags)

    How does Symfony 2 find custom form types?

    【讨论】:

    • data transformer 正是我所需要的。直到现在我才知道,谢谢。
    • 没问题 - 我很快就把代码拼凑在一起了,所以如果有什么古怪的东西不起作用,请告诉我。
    • 如果我发现任何问题,我会在工作完成后编辑您的答案,没问题。你给了我正确的方向。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多