Проверка формы Symfony vs validator service

У меня странная проблема, и я думаю, что что-то не хватает.

Я использую Symfony 2.7, и я работаю над функцией обновления пароля пользователя.

У меня есть пользовательский объект (расширяет пользовательский объект FosUserBundle) с несколькими свойствами. Одним из них является plainPassword (конечно, не сохраняется в DB).

User.php  

...

/**
 * @ORM\Table(name="prefix_users")
 * @ORM\Entity(repositoryClass="UserRepository")
 *
 * @UniqueEntity(fields={"email"}, message="unique", groups={"registration"})
 * @UniqueEntity("username", message="unique", groups={"registration"})
 *
 * @ExclusionPolicy("all")
 */
class User extends BaseUser
{

...

    /* @var string
     *
     * @Assert\NotBlank(message="blank",groups={"accountUpdate", "passwordUpdate"})
     * @Assert\Length(min=8, minMessage="short", max=4096, maxMessage="long")
     */
    protected $plainPassword;

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

Я создал форму

UserUpdatePasswordType.php  

class UserUpdatePasswordType extends AbstractType
{
    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('plainPassword', 'repeated', array(
            'type' => 'password',
            'invalid_message' => 'password_mismatch',
        ));
    }

    /**
     * @param OptionsResolverInterface $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'My\Bundle\UserBundle\Entity\User',
            'csrf_protection' => false,
            'intention' => 'resetting',
            /**
             * Need to add method to prevent this form from bein marked as invalid.
             * @see http://sroze.io/2013/10/30/symfony2-form-patch-requests-and-handlerequest-form-never-valid/
             */
            'method' => 'PATCH'
        ));
    }

Я создаю restful API с FOSRestBundle, и я хотел бы предоставить хороший и чистый вывод, если проверка формы не удалась.

Насколько я знаю, я могу проверить форму двумя способами:

  • $formErrors = $this- > get ('validator') → validate ($ user, null, ['passwordUpdate']);
  • $form- > isValid() и получить ошибки $form- > getErrors()

Теперь появляется странная часть, два вышеописанных метода дают разные ошибки проверки.

Параметры запроса

user_update_password[plainPassword][first]:sffsdfdsfds
user_update_password[plainPassword][second]:fdsfdsfsd

Ответ от $formErrors = $this- > get ('validator') → validate ($ user, null, ['passwordUpdate']); Ответ неправильный, потому что plainPassword не пуст.

{
      "property_path": "plainPassword",
      "message": "blank"
}

Форма ответа $form- > isValid(), которая выглядит лучше.

"form": {
      "children": {
        "plainPassword": {
          "children": {
            "first": {
              "errors": [
                "password_mismatch"
              ]
            },
            "second": {}
          }
        }
      }
    },
    "errors": []

Единственное различие, которое я вижу, - это разница в том, что я не предоставляю имя группы проверки в $form- > isValid().

Почему я получаю разные результаты и что мне делать, чтобы исправить? Могу ли я предоставить имя группы проверки для $form- > isValid(), или я должен исправить проблему с помощью проверки $validator- > validate?

Мне бы хотелось посмотреть, как это управляется в других API на основе Symfony2...

Ответ 1

Есть три причины различия.

  • Вероятно, вы не устанавливаете данные от request до model при проверке службой. Используйте $form->submit($request) как безопасный прокси-сервер данных
  • Вы не используете группы проверки в форме (сделайте это в setDefaults) BTW. Ваш @Assert\Length не будет использоваться до тех пор, пока вы не добавите группы в эту аннотацию или не добавьте группу валидаций Default в service/form массив проверки.
  • Вы использовали тип repeated в форме, у которого есть дополнительные Constraints по сравнению с вашей моделью Constraints. Проверка валидатора проверки для ограничений модели и формы, принадлежащих к пройденным группам проверки (по умолчанию используется группа "По умолчанию" ).

Ответ 2

На самом деле существует другая разница (помимо использования группы проверки). Когда вы используете форму (а не только валидатор), существует 'repeat'.

Проверка

Одной из ключевых особенностей повторяющегося поля является внутренняя валидация (вам не нужно ничего делать, чтобы установить это), что заставляет два поля имеют соответствующее значение. Если два поля не совпадение, пользователю будет отображаться ошибка.

Итак, в одном случае вы используете дополнительное ограничение, а другое - нет. Неудивительно, что валидации дают разные результаты.

Поэтому в вашем случае я, вероятно, сделаю собственную реализацию "повторения" для пароля в объекте "Пользователь" и будет использовать службу проверки.

Другим вариантом, который я вижу, является использование объекта Form для проверки пользователя, но это не чистый и понятный способ создания API.

Ответ 3

Большая разница заключается в том, что один валидатор проверяет модель, а другой проверяет данные формы. Модель требует, чтобы поле не было пустым. FOSUser bundle ChangePasswordFormType добавляет ограничение UserPassword в форму для Проверка. Валидатор UserPassword проверяет правильность отправки значений формы.

Если вы используете данные в форме URL-формы с urlencoded в вашем API, используйте средство проверки формы. Это даст более точные ошибки, поскольку они будут связаны с состоянием данных, представленных не состоянием данных после его преобразования в модель.