Сопоставить текстовое поле формы с ArrayCollection объекта

Я использую теги в форме, используя tagsinput :

введите описание изображения здесь

Этот плагин заканчивается одним текстовым полем, содержащим теги, разделенные запятой (например: tag1, tag2, …)

Эти теги в настоящее время управляются в неотображенном поле формы:

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

И, наконец, они хранятся в коллекции ArrayCollection, как это плохая практика для хранения нескольких значений в поле базы данных:

/**
* @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);
}

Но на первый взгляд это выглядит не так.

Мне интересно, как лучше всего сопоставить мою сущность с моей формой, а мою форму — с моей сущностью.

5

Решение

Это сложно, так как вы не просто встраиваете коллекцию форм 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())
)
;

Проверка

Ты можешь использовать @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

Смотрите эти сообщения для некоторых других идей:

Анализ строки, разделенной запятыми, в несколько записей базы данных (например, теги)

Как Symfony 2 находит пользовательские типы форм?

9

Другие решения

Других решений пока нет …