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

Ala*_*blo 5 php forms arraycollection symfony

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

在此输入图像描述

此插件最终包含一个文本字段,其中包含以逗号分隔的标记(例如:tag1,tag2,...)

这些标记目前在非映射表单字段上进行管理:

    $builder
       // ...
       ->add('tags', 'text', array(
               'mapped' => false,
               'required' => false,
       ))
    ;
Run Code Online (Sandbox Code Playgroud)

最后,它们存储在ArrayCollection中,因为在数据库字段中存储多个值是一种不好的做法:

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

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

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

但这看起来是错误的方式.

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

Jas*_*man 9

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

}
Run Code Online (Sandbox Code Playgroud)

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

表格类型

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

FiddleType.php

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

验证

您可以使用@Assert\Count来限制允许的标记数,如果您的FiddleTag实体本身具有一些验证约束,则可以使用@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;
Run Code Online (Sandbox Code Playgroud)

进一步阅读

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

有关其他一些想法,请参阅这些帖子

将逗号分隔的字符串解析为多个数据库条目(例如,标记)

Symfony 2如何找到自定义表单类型?