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) }}
Другие вопросы по тегам