Передача пользовательских параметров в пользовательский параметр ValidationConstraint в Symfony2
Я создаю форму в Symfony2. Форма содержит только одно поле book
, которое позволяет пользователю выбирать между объектами Books
. Мне нужно проверить, принадлежит ли выбранный book
к Author
, который у меня есть в моем контроллере.
public class MyFormType extends AbstractType
{
protected $author;
public function __construct(Author $author) {
$this->author = $author;
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('book', 'entity', array('class' => 'AcmeDemoBundle:Book', 'field' => 'title');
}
// ...
}
Я хочу проверить после отправки формы, что выбранный book
записывается $author
в моем контроллере:
public class MyController
{
public function doStuffAction() {
$author = ...;
$form = $this->createForm(new MyFormType($author));
$form->bind($this->getRequest());
// ...
}
}
К сожалению, я не могу найти способ сделать это. Я попытался создать специальное ограничение валидатора, как описано в Cookbook, но пока я могу передать параметр EntityManager
as, указав валидатор как услугу, Я не могу передать $author
с контроллера на ограничение валидатора.
class HasValidAuthorConstraintValidator extends ConstraintValidator
{
private $entityManager;
public function __construct(EntityManager $entityManager) {
$this->entityManager = $entityManager;
}
public function validate($value, Constraint $constraint) {
$book = $this->entityManager->getRepository('book')->findOneById($value);
$author = ...; // That the data I'm missing
if(!$book->belongsTo($author))
{
$this->context->addViolation(...);
}
}
}
Это решение может быть именно тем, что я искал, но моя форма не привязана к сущности и не должна быть (я получаю данные из метода getData()
).
Есть ли решение моей проблемы? Это должно быть обычным делом, но я действительно не знаю, как его решить.
Ответы
Ответ 1
Я, наконец, понял это с помощью Серада. Чтобы добавить пользовательские параметры, которые необходимо получить из метода ConstraintValidator::validate()
, вам необходимо передать их как параметры в Constraint
.
public class HasValidAuthorConstraint extends Constraint
{
protected $author;
public function __construct($options)
{
if($options['author'] and $options['author'] instanceof Author)
{
$this->author = $options['author'];
}
else
{
throw new MissingOptionException("...");
}
}
public function getAuthor()
{
return $this->author;
}
}
И в ConstraintValidator:
class HasValidAuthorConstraintValidator extends ConstraintValidator
{
private $entityManager;
public function __construct(EntityManager $entityManager) {
$this->entityManager = $entityManager;
}
public function validate($value, Constraint $constraint) {
$book = $this->entityManager->getRepository('book')->findOneById($value);
$author = $this->constraint->getAuthor();
if(!$book->isAuthor($author))
{
$this->context->addViolation(...);
}
}
}
И последнее, но не менее важное: вы должны передать параметр в Validator:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('book', 'entity', array(
'class' => 'AcmeDemoBundle:Book',
'field' => 'title',
'constraints' => array(
new HasValidAuthorConstraint(array(
'author' => $this->author
))
)
));
}
Ответ 2
Начните с добавления метода setAuthor к вашему ограничению и затем настройки метода проверки. Трюк тогда должен определить лучшее место, чтобы назвать это.
Не ясно, как именно вы привязываете валидатор к своей книге. Вы используете validation.yml или что-то делаете внутри формы?
Ответ 3
Ну, я не тот familier с компонентом Form/Validation, но вы можете использовать Скрытое поле с именем /id автор и проверьте, не совпадают ли они:
class MyFormType extends AbstractType
{
protected $author;
public function __construct(Author $author) {
$this->author = $author;
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('book', 'entity', array('class' => 'AcmeDemoBundle:Book', 'field' => 'title');
->add('author_name', 'hidden', array(
'data' => $this->author->getId(),
))
;
}
// ...
}
Ответ 4
Принятый ответ не работал у меня, используя Symfony Framework версия 2.1. Вот как я это решил.
class CustomConstraint extends Constraint
{
public $dependency;
public $message = 'The error message.';
}
class CustomConstraintValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
if (!$constraint->dependency->allows($value)) {
$this->context->addViolation($constraint->message);
}
}
}
class CustomFormType extends AbstractType
{
private $dependency;
public function __construct(Dependency $dependency)
{
$this->dependency = $dependency;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('field', 'type', array(
'constraints' => array(
new CustomConstraint(array('dependency' => $this->dependency))
)
));
}
}