Symfony2 повторный тип не проверяет
У меня есть два поля пароля. Это дополнительно для подтверждения. И нет сообщения об ошибке, когда оба пусты или пароли не совпадают.
Как включить или отладить эту проверку, которая, как я полагаю, должна работать "из коробки" ( http://symfony.com/doc/current/reference/forms/types/repeated.html)?
class MyType extends AbstractType
{
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'My\\Bundle\\Entity\\User',
));
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
...
$builder->add('password', 'repeated', array(
'invalid_message' => 'Passwords must match.',
'type' => 'password',
'required' => true,
'first_options' => array('label' => 'Password'),
'second_options' => array('label' => 'Repeat Password')
));
form.html.twig
...
<form action="" method="post" novalidate>
...
<tr>
<td>{{ form_label(regForm.password.first) }}</td>
<td>{{ form_widget(regForm.password.first, { 'attr': {'pattern': '.{6,}','title': 'Minimum 6 characters long'} } ) }}</td>
</tr>
<tr>
<td>{{ form_label(regForm.password.second) }}</td>
<td>{{ form_widget(regForm.password.second, { 'attr': {'pattern': '.{6,}', 'title': 'Minimum 6 characters long', 'data-equals': '#register_password_first'} } ) }}</td>
</tr>
Валидаторы, объявленные в validation.yml, похоже, не влияют на проблему.
My\Bundle\Entity\User:
properties:
...
password:
# this one does not work because of "repeated" type in buildForm()???
- NotBlank:
message: "Password is required."
- MinLength:
limit: 6
message: "Password must have at least {{ limit }} characters."
Controller.php (оригинальная версия)
...
if (!$form->isValid()) {
$formFields = $form->all();
foreach ($formFields as $key => $field) {
if ($field->getErrorsAsString()) {
$errors = $field->getErrors();
foreach ($errors as $error) {
$messages[$key][] = $error->getMessage();
}
}
}
var_dump($messages);
РЕДАКТИРОВАТЬ: Теперь поиск ошибок выглядит следующим образом (благодаря alex.dominte):
public static function getFormErrorMessages(\Symfony\Component\Form\Form $form)
{
$messages = array();
foreach ($form->getErrors() as $i => $error) {
$messages[$i] = $error->getMessage();
}
foreach ($form->all() as $child) {
if (!$child->isValid()) {
$messages[$child->getName()] = self::getFormErrorMessages($child);
}
}
return $messages;
}
Модификации, предложенные Pedro Cordeiro, позволяют отбрасывать рекурсию, но также делают имена полей недоступными.
3 ответа
Недостаточно рекурсии
foreach ($formFields as $key => $field) {
if ($field->getErrorsAsString()) {
$errors = $field->getErrors();
foreach ($errors as $error) {
$messages[$key][] = $error->getMessage();
}
}
}
Попробуйте это - должно работать для всех вложенных ошибок:
class FormHelper
{
public static function getErrorMessages($form)
{
$errors = array();
if (!$form->isBound()) return $errors;
foreach ($form->getErrors() as $key => $error) {
$template = $error->getMessageTemplate();
$parameters = $error->getMessageParameters();
foreach ($parameters as $var => $value) {
$template = str_replace($var, $value, $template);
}
$errors[$key] = $template;
}
if ($form->hasChildren()) {
foreach ($form->getChildren() as $child) {
if (!$child->isValid()) {
$name = $child->getConfig()->getOption('title', $child->getName());
$errors[$name] = self::getErrorMessages($child);
}
}
}
return $errors;
}
}
В ваших определениях отсутствуют две вещи:
- 1)
error_bubbling
должен быть установлен вручную наTRUE
на ваших полях, чтобы они могли выдавать ошибки в функции ->getErrors(). - 2)
cascade_validation
являетсяFALSE
по умолчанию вы тоже должны добавить его в родительские формы($builder->add('propertyName', new YourFormNameType(), array('cascade_validation ' => true));
) - Смотрите это
Вы не показываете сообщение об ошибке
{{ form_errors(regForm.password.first) }}
{{ form_errors(regForm.password.second) }}