将表单的文本字段映射到实体的ArrayCollection

时间:2014-12-28 22:51:06

标签: php forms symfony arraycollection

我使用tagsinput在表单上使用代码:

enter image description here

此插件以单个文本字段结束,其中包含以逗号分隔的标记(例如: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);
    }

但这看起来错误的方式。

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

1 个答案:

答案 0 :(得分:9)

这很棘手,因为您不仅仅是嵌入了Tag表单的集合,也就是所有单独的文本字段。我想你可以用一些技巧来做到这一点,但是如何使用数据转换器呢?您可以将逗号分隔的标记列表转换为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())
   )
;

验证

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

Fiddle.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?