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

标签 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;

为了将我的表单映射到我的实体,我可以在我的 Controller 中编写一些代码,如下所示:

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

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

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

最佳答案

这很棘手,因为您不只是嵌入一组标签表单,也就是说,所有单独的文本字段。我想你可以通过一些技巧来做到这一点,但是使用数据转换器呢?您可以将逗号分隔的标签列表转换为 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),因为您的实现应该与接口(interface)匹配。

表单类型

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

FiddleType.php

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

验证

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

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?

关于php - 将表单的文本字段映射到实体的 ArrayCollection,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27681395/

相关文章:

php - 图像根据其大小的动态位置

php - 无法使Google Analytics(分析)事件跟踪正常工作

php - PHP可以重启Apache吗?

php - 回显已发布 ID 的行名称,用于预选的表单值

javascript - 提交前验证表单

jquery - 使用 jquery 进行表单验证 - 返回 false

symfony - 在 Doctrine 中生成 getter 和 setter,无需注释

php - Symfony2 中的“网站正在维护”页面

php - mysql查询返回0

php - 多对多关系学说