Я задал этот вопрос и обнаружил, что мы не можем получить сообщение об ошибке, выданное DataTransformer (по словам единственного пользователя, который ответил, возможно, это возможно, я не знаю).
Во всяком случае, теперь, когда я это знаю, я застрял с проблемой проверки. Предположим, что моя модель такая: у меня есть темы, которые содержат несколько участников (пользователей).
<?php
class Thread
{
/**
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @ORM\ManyToMany(targetEntity="My\UserBundle\Entity\User")
* @ORM\JoinTable(name="messaging_thread_user")
*/
private $participants;
// other fields, getters, setters, etc
}
Для создания потока я хочу, чтобы пользователь указал имена пользователей участников в текстовой области, разделенные знаком "\ n".
И я хочу, чтобы, если одно или несколько из указанных имен пользователей не существовало, отображается сообщение с именами пользователей, которых не существует .
Например, «Пользователи titi, tata и toto не существуют».
Для этого я создал DataTransformer, который преобразует необработанный текст в текстовой области в коллекцию ArrayCollection, содержащую экземпляры пользователей. Так как я не могу получить сообщение об ошибке, предоставленное этим DataTransformer (такой позор! Это действительно невозможно?), Я не проверяю существование каждого имени пользователя в DataTransformer, но в Валидаторе.
Вот DataTransformer, который преобразует разделенный \ n список пользователей в ArrayCollection (так, чтобы с DataBinding все было в порядке):
<?php
public function reverseTransform($val)
{
if (empty($val)) {
return null;
}
$return = new ArrayCollection();
// Extract usernames in an array from the raw text
$val = str_replace("\r\n", "\n", trim($val));
$usernames = explode("\n", $val);
array_map('trim', $usernames);
foreach ($usernames as $username) {
$user = new User();
$user->setUsername($username);
if (!$return->contains($user)) {
$return->add($user);
}
}
return $return;
}
А вот мой валидатор:
<?php
public function isValid($value, Constraint $constraint)
{
$repo = $this->em->getRepository('MyUserBundle:User');
$notValidUsernames = array();
foreach ($value as $user) {
$username = $user->getUsername();
if (!($user = $repo->findOneByUsername($username))) {
$notValidUsernames[] = $username;
}
}
if (count($notValidUsernames) == 0) {
return true;
}
// At least one username is not ok here
// Create the list of usernames separated by commas
$list = '';
$i = 1;
foreach ($notValidUsernames as $username) {
if ($i < count($notValidUsernames)) {
$list .= $username;
if ($i < count($notValidUsernames) - 1) {
$list .= ', ';
}
}
$i++;
}
$this->setMessage(
$this->translator->transChoice(
'form.error.participant_not_found',
count($notValidUsernames),
array(
'%usernames%' => $list,
'%last_username%' => end($notValidUsernames)
)
)
);
return false;
}
Эта текущая реализация выглядит некрасиво. Я хорошо вижу сообщение об ошибке, но пользователи в ArrayCollection, возвращаемые DataTransformer, не синхронизируются с Doctrine.
У меня есть два вопроса:
- Может ли мой валидатор изменить значение, указанное в параметре? Чтобы я мог заменить простые экземпляры User в ArrayCollection, возвращенные DataTransformer, на экземпляры, извлеченные из базы данных?
- Есть ли простой и элегантный способ делать то, что я делаю?
Полагаю, самый простой способ сделать это - получить сообщение об ошибке, выданное DataTransformer. В кулинарной книге они выдают это исключение: throw new TransformationFailedException(sprintf('An issue with number %s does not exist!', $val));
, если бы я мог поместить список несуществующих имен пользователей в сообщение об ошибке, было бы круто.
Спасибо!