Что такое и как создать преобразователь данных в Symfony2

Не нравится его предшественник (Symfony 1.4) при вставке сущности в вашу базу данных с помощью Doctrine, если у вашей сущности есть отношения один ко многим, вы можете легко создать ее с помощью пары строк:

Учитывая отношение «один ко многим» между ролью и пользователем:

$user = new User();
$user->setName('Joe');
$user->setAge(28);
$user->setRoleId(1);
$user->save();

Но начиная с Symfony 2, если вы попытаетесь сделать это:

$em = $this->getDoctrine()->getManager();
$user = new User();
$user->setName('Joe');
$user->setAge(28);
$user->setRole(1);
$em->persist($user);
$em->flush();

Ошибка будет выдана, потому что ваш setRole Метод пытается сохранить только число вместо объекта роли, вам нужно вставить оригинальный объект роли в объект пользователя

$em = $this->getDoctrine()->getManager();
$roleEntity = $em->getRepository('ourcodeworldBundle:Roles')->find(1);
$user = new User();
$user->setName('Joe');
$user->setAge(28);
$user->setRole($roleEntity);
$em->persist($user);
$em->flush();

Так легко объект будет успешно сохранен.

Использование дататрансформаторов

Теперь преобразователи данных используются для перевода из сущности в виджеты формы, представьте, что продукт сущности имеет отношение один ко многим. Если вы создадите CRUD, будет создан виджет выбора, чтобы выбрать роль для продукта в форме.

Но что делать, если в выборке более 200 категорий? неудобным способом выбора категории не является? Вам предлагается разработать простой способ выбора категории с простым номером, который знает пользователь.

Здесь, когда преобразователи данных вступают в действие, они автоматически переводят число в сущность, а сущность — в число.

Если вы не используете преобразователь данных, вы, скорее всего, увидите эти ошибки при создании CRUD из существующей базы данных с отношениями один-ко-многим:

Catchable Fatal Error: Аргумент 1, передаваемый в xxxxxxxxxxxxx :: setRole (), должен быть экземпляром xxxxxxxxxxxxxxx \ Role, заданной строки, вызываться в xxxxxxxxx в строке xxxx и определяться в строке xxxxxx
Предполагается, что данные представления формы являются экземпляром класса xxxxxxxxxxxxx, но представляют собой строку (n). Вы можете избежать этой ошибки, установив для параметра data_class значение null или добавив преобразователь представления, который преобразует строку (n) в экземпляр xxxxxxxxxxx

1) Создайте преобразователь в новой папке с именем DataTransformer в папку Form пакета.

Создайте файл php в папке формы объекта и вставьте следующий код

// src/AppBundle/Form/DataTransformer/IssueToNumberTransformer.php
namespace AppBundle\Form\DataTransformer;
use AppBundle\Entity\Issue;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
class IssueToNumberTransformer implements DataTransformerInterface
{
private $manager;
public function __construct(ObjectManager $manager)
{
$this->manager = $manager;
}
/**
* Transforms an object (issue) to a string (number).
*
* @param  Issue|null $issue
* @return string
*/
public function transform($issue)
{
if (null === $issue) {
return '';
}
return $issue->getId();
}
/**
* Transforms a string (number) to an object (issue).
*
* @param  string $issueNumber
* @return Issue|null
* @throws TransformationFailedException if object (issue) is not found.
*/
public function reverseTransform($issueNumber)
{
// no issue number? It's optional, so that's ok
if (!$issueNumber) {
return;
}
$issue = $this->manager
->getRepository('AppBundle:Issue')
// query for the issue with this id
->find($issueNumber)
;
if (null === $issue) {
// causes a validation error
// this message is not shown to the user
// see the invalid_message option
throw new TransformationFailedException(sprintf(
'An issue with number "%s" does not exist!',
$issueNumber
));
}
return $issue;
}
}

Измените очевидные параметры, которые должны быть заменены, такие как пакет, пространство имен и свойство, которое необходимо заменять при каждом запуске преобразователя.

2) Добавьте преобразователь данных в конструктор форм нашей организации.

Нам нужно применить предыдущий преобразователь данных в построителе форм (расположен вне папки, которую мы создали)

// src/AppBundle/Form/TaskType.php
namespace AppBundle\Form\Type;
use AppBundle\Form\DataTransformer\IssueToNumberTransformer; // We include the datatransformer created previously
use Doctrine\Common\Persistence\EntityManager;
// ...
class TaskType extends AbstractType
{
private $entityManager;
public function __construct(EntityManager $entityManager) // Create the constructor if not exist and add the entity manager as first parameter (we will add it later)
{
$this->entityManager = $entityManager;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('description', 'textarea')
->add('issue', 'text', array(
// validation message if the data transformer fails
'invalid_message' => 'That is not a valid issue number',
));
// ...
$builder->get('issue')
->addModelTransformer(new IssueToNumberTransformer($this->entityManager)); // finally we apply the transformer
}
// ...
}

3) Мы отправляем требуемый EntityManager $ entityManager в контроллере в taskType

Необходимо предоставить менеджер сущностей в преобразователе данных (менеджер доктрины), который будет передан в качестве первого аргумента в нашем объявлении formType в контроллере (newAction, editAction)

// e.g. in a controller somewhere
$manager = $this->getDoctrine()->getManager();
$form = $this->createForm(new TaskType($manager), $task);

Таким образом, наш длинный выбор с более чем 200 опциями будет заменен текстовым вводом, в котором пользователь будет вводить только идентификатор (или ваш пользовательский идентификатор) роли вместо загрузки 200 строк нашей базы данных.

Ссылка на основную публикацию
Adblock
detector