sfValidatorDoctrineUnique в контексте обновления / редактирования

Я использую класс формы в двух разных контекстах: как для создания новой записи, так и для редактирования этой записи. Я установил пост-валидатор следующим образом, чтобы убедиться, что поле URL уникально.

$this->validatorSchema->setPostValidator(new sfValidatorAnd(array(
   new sfValidatorDoctrineUnique(array('model' => 'Page', 'column' => array('url')), array('invalid' => 'This URL already exists.'))
)));

Валидатор прекрасно работает, когда я создаю новую запись. Однако при редактировании существующей записи он выдает ошибку, поскольку обнаруживает себя как дубликат. Другими словами, если я редактирую запись, но не изменяю URL-адрес, выдается повторяющаяся ошибка.

Это должно быть распространенной проблемой, поэтому мне интересно, каким образом Symfony будет иметь дело с этим? По сути, я бы хотел, чтобы при сохранении он игнорировался (дубликатов не было), но все же запускал пост-валидатор, чтобы гарантировать отсутствие истинных дубликатов.

2 ответа

Решение

Ситуация с обновлением действительно обрабатывается sfValidatorDoctrineUnique.

В вашем случае, если объект с данным URL уже существует, валидатор проверит, выполняете ли вы операцию обновления. Проверка выполняется с помощью метода sfValidatorDoctrineUnique::isUpdate().

Ваш первичный ключ (и) должен быть в представленных значениях.

По умолчанию первичный ключ является самоанализом. Вы можете предоставить его с параметром *primary_key*, переданным валидатору.

Как отмечено в других ответах, важно убедиться в следующем:

  • Значение PK для обновленного объекта должно присутствовать в представленных значениях формы.
  • sfValidatorDoctrineUnique валидатор должен знать все значения, представленные в форме.

Для этого необходимо выполнить следующие шаги:

  1. Добавьте скрытый ввод, который содержит (обычно) значение PK для вашего объекта:

    class MyModelForm extends BaseMyModelForm
    {
      public function configure(  )
      {
        if( ! $this->isNew() )
        {
          $this->widgetSchema['id']    = new sfWidgetFormInputHidden();
          $this->validatorSchema['id'] = new sfValidatorNumber(array(
              'required' => true
            , 'min'      => 1
          ));
        }
    
        ...
      }
    
      ...
    }
    
    • Обратите внимание, что этот дополнительный ввод необходимо добавлять только при обновлении.
  2. Переместить sfValidatorDoctrineUnique на этапе после проверки:

    class MyModelForm extends BaseMyModelForm
    {
      public function configure(  )
      {
        $this->widgetSchema['unique_column']    = new sfWidgetFormInputText();
        $this->validatorSchema['unique_column'] = new sfValidatorPass();
    
        ...
    
        $this->mergePostValidator(new sfValidatorDoctrineUnique(array(
            'required' => true
          , 'model'    => 'MyModel'
          , 'column'   => 'unique_column'
        )));
      }
    
      ...
    }
    
    • Вам нужно будет использовать $this->mergePostValidator() добавить валидатор к этапу пост-валидации, чтобы все отправленные значения были предоставлены валидатору.

    • Обратите внимание, что вам все равно нужно предоставить валидатор для уникального виджета столбца, иначе вы получите ошибку "Неожиданное дополнительное поле формы" при отправке формы.

  3. Убедитесь, что вы передаете обновляемый объект конструктору вашей формы:

    $this->form = new MyModelForm($this->getRoute()->getObject());
    
Другие вопросы по тегам