我正在试图找出如何让数据转换器在集合字段上工作。目前,用户可以创建一个Campaign并最多附加三个标签。实际上,每次用户输入标签的字符串(它是开放文本输入)时,都会创建该标签的新条目,无论它是否已存在。我想要做的是创建一个新标签,如果匹配的标签不存在,但如果有,则使用现有的标签。
我已尝试过变压器的各种组合和放置方式,而且很多都会产生各种错误。我最常见的是:
“object,array or empty”类型的预期参数,“string”给出
我已将其置于非错误状态,代码如下,它确实输出了一个文本字段,但它没有为该字段提供Campaign表单的任何属性(id或name)来链接它,因此我不好。
/**
* @ORM\Entity
* @ORM\Table(name="campaigns")
*/
class Campaign
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string")
*/
protected $name;
/**
* @var integer
*
* @ORM\Column(name="length", type="integer")
*/
protected $length;
/**
* @var string
*
* @ORM\Column(name="start_date", type="datetime")
*/
protected $startDate;
/* ... snip ... */
/**
* @ORM\ManyToMany(targetEntity="Tag", inversedBy="campaigns", cascade={"persist"})
* @ORM\JoinTable(name="campaigns_tags")
*/
protected $tags;
/* ... snip ... */
/**
* @ORM\Entity
* @ORM\Table(name="tags")
*/
class Tag
{
use TimestampTrait;
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var string
*
* @ORM\Column(name="tag", type="string")
*/
protected $tag;
/* ... snip ... */
class CampaignFormType extends AbstractType
{
public function __construct(TagFormType $tag_form, SecurityContext $security_context)
{
$this->tag_form = $tag_form;
$this->user = $security_context->getToken()->getUser();
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name', 'text', array(
'label' => 'Campaign Name:'
))
->add('length', 'integer', array(
'label' => 'Length (weeks):'
))
->add('startDate', 'date', array(
'label' => 'Start Date:',
'widget' => 'single_text'
))
->add('tags', 'collection', array(
'type' => $this->tag_form,
'allow_add' => TRUE,
'by_reference' => FALSE
));
/* ... snip ... */
class TagFormType extends AbstractType
{
/**
* @var EntityManager
*/
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$transformer = new TagToStringTransformer($this->em);
$builder->addModelTransformer($transformer);;
}
public function getParent()
{
return 'text';
}
/* ... snip ... */
class TagToStringTransformer implements DataTransformerInterface
{
/**
* @var EntityManager
*/
private $em;
/**
* @param EntityManager $em
*/
public function __construct(EntityManager $em)
{
$this->em = $em;
}
/**
* @param Tag|null $tag
*
* @return string
*/
public function transform($tag)
{
if (empty($value)) {
return "";
}
return $tag->getTag();
}
/**
* @param string $string
*
* @return Tag|null
*/
public function reverseTransform($string)
{
if (empty($string)) {
return NULL;
}
$tag = $this->em->getRepository('AppBundle:Tag')->findOneBy(array('tag' => $string));
// If the tag doesn't exist, create it
if (empty($tag)) {
$tag = new Tag();
$tag->setTag($string);
}
return $tag;
}
}
更新 我挖掘了一些更多的东西,并将TagFormType稍微改为看起来像下面的代码,似乎正确输出具有预期名称/ id属性的字段:
class TagFormType extends AbstractType
{
/**
* @var EntityManager
*/
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$transformer = new TagToStringTransformer($this->em);
$builder->add($builder->create('tag', 'text', array('label' => FALSE))->addModelTransformer($transformer));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'AppBundle\Entity\Tag',
)
);
}
public function getName()
{
return 'tag';
}
}
答案 0 :(得分:1)
我遇到的问题似乎源于我如何创造这个领域。简单地添加字段不能正常工作,但如果我在TagFormType类中切换到$builder->add($builder->create('tag', 'text', array('label' => FALSE))->addModelTransformer($transformer));
,那么它几乎按预期工作。唯一的问题是变换器正在处理标签实体的标签字段,将其转换为Tag对象,而不是将Campaign表单的每个标签转换为已经存在的conuterpart(如果已经存在的conuterpart,则返回一个新标签)它不存在)。
让我按照我需要的方式工作的答案:我在POST_SUBMIT上实现了一个表单事件监听器。我拿每个提交的标签对象并检查它们是否已经存在。如果它们存在,我换掉对象。