Как вы проверяете / сохраняете встроенную форму на основе значения в родительской форме в Symfony? - PullRequest
2 голосов
/ 26 июля 2010

У меня есть форма Symfony 1.4 с 2 встроенными формами.

В родительской форме есть раскрывающийся список, который определяет, какую из встроенных форм вы заполняете (скрыто / показано на веб-интерфейсе).используя JavaScript).

Проблема заключается в том, что при отправке формы проверка и сохранение выполняются на обеих встроенных формах, что, очевидно, мне не нужно.

Каков наилучший способ изменить родительскую форму, чтобы она только проверяла и сохраняла соответствующую встроенную форму на основе выбора, сделанного в родительской форме?

Спасибо.

Ответы [ 2 ]

1 голос
/ 27 июля 2010

Примечание: Пожалуйста, смотрите ответ Джереми, так как мой основан на его.

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

1.Переопределение doBind ()

При переопределении doBind () возникла проблема, из-за которой было бы выброшено неперехваченное sfValidatorError, если родительское значение не возвращало clean из средства проверки.Я обернул его в try / catch для подавления этого.

Я также изменил его для работы с несколькими встроенными формами, а не только с двумя указанными мной.

protected $selectedTemplate;

public function getTemplateToEmbeddedFormKeyMap()
{
    // An array of template values to embedded forms
    return array(
        'template1' => 'templateform1',
        'template2' => 'templateform2',
        'template3' => 'templateform3',
        'templateN' => 'templateformN'
    );
}

protected function doBind(array $values)
{
    // Clean the "template" value
    try
    {
        $this->selectedTemplate = $this->validatorSchema['template']->clean(array_key_exists('template', $values) ? $values['template'] : NULL);
    }
    catch(sfValidatorError $e) {}

    // For each template embedded form
    foreach($this->getTemplateToEmbeddedFormKeyMap() as $template => $form_key)
    {
        // If there is no selected template or the embedded form is not for the selected template
        if ($this->selectedTemplate == NULL || $this->selectedTemplate != $template)
        {
            // Don't validate it
            $this->validatorSchema[$form_key] = new sfValidatorPass();
        }
    }

    // Parent
    parent::doBind($values);
}

2. NEW STEP Переопределить updateObjectEmbeddedForms ()

Поскольку я отключил проверку некоторых или всех моих встроенных форм, у нас теперь есть некоторые неочищенные данные в массиве $ values.Я не хочу, чтобы эти данные передавались объектам моей модели во встроенных формах, поэтому я переопределил updateObjectEmbeddedForms(), чтобы удалить все данные, связанные со встроенной формой, которая не проверена.

public function updateObjectEmbeddedForms($values, $forms = null)
{
    // For each template embedded form
    foreach($this->getTemplateToEmbeddedFormKeyMap() as $template => $form_key)
    {
        // If there is no selected template or the embedded form is not for the selected template
        if ($this->selectedTemplate == NULL || $this->selectedTemplate != $template)
        {
            // Remove the data
            unset($values[$form_key]);
        }
    }

    // Parent
    parent::updateObjectEmbeddedForms($values, $forms);
}

3.Переопределить saveEmbeddedForms ()

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

public function saveEmbeddedForms($con = null, $forms = null)
{
    // Get the embedded forms
    if ($forms === NULL)
    {
        $forms = $this->getEmbeddedForms();
    }

    // For each template embedded form
    foreach($this->getTemplateToEmbeddedFormKeyMap() as $template => $form_key)
    {
        // If there is no selected template or the embedded form is not for the selected template
        if ($this->selectedTemplate == NULL || $this->selectedTemplate != $template)
        {
            // Remove the form so it isn't saved
            unset($forms[$form_key]);
        }
    }

    // Parent
    parent::saveEmbeddedForms($con, $forms);
}

Еще раз спасибо за ответ, Джереми, я понял, что это работает для моего варианта использования.

0 голосов
/ 27 июля 2010

Ниже приведен обобщенный способ сделать это. Все эти методы могут быть добавлены к BaseFormDoctrine за исключением doBind

1. Добавьте метод, чтобы пропустить формы.

/**
* @param string $name Adds $name to an array of form names to ignore when saving/updating.
*/
protected function skipSavingForm($name)
{
  $this->skipSavingForms[$name] = $name;
  $this->validatorSchema[$name] = new sfValidatorPass();
}

2. Переопределите doBind, чтобы не сохраняемая вами форма не была проверена

Таким образом, даже если форма, которая не была сохранена, отправлена ​​с ошибками, форма по-прежнему проверяется. Это безопасно, так как эти значения не сохраняются. Кроме того, вы можете очистить значения с помощью preValidator. Однако я предпочитаю это решение, так что если пользователь отправляет форму с ошибкой, его значения для обеих форм все еще там.

/**
* Override doBind to skip validation on the form not being saved
* @param array $values
* @see sfForm::doBind
*/
protected function doBind(array $values)
{
  try
  {
    $formDecidingValue = $this->validatorSchema[$values['form_deciding_field']]->clean();
  } catch (sfValidatorError $e) {
     //either create an sfValidatorErrorSchema and throw it or call through to parent here and let parent::doBind throw the error
     return; //either way, we want to stop processing
  }

  $this->skipSavingForm($formDecidingValue ? 'Form1' : 'Form2');
  return parent::doBind($values);
}

3. Добавить метод getFormsToSave

/**
*@return array An array of forms to be saved
*/
public function getFormsToSave()
{
  return array_diff_key($this->getEmbeddedForms(), $this->skipSavingForms);
}

4. Переопределите saveEmbeddedForms и updateObjectEmbeddedForms

Так что пропущенная форма не сохраняется. В качестве альтернативы, если вам не нужно продолжать отображать форму при ошибке, вы можете просто сбросить встроенную форму в doBind.

public function saveEmbeddedForms($con = null, $forms = null)
{
  if (null === $con)
  {
    $con = $this->getConnection();
  }

  if (null === $forms)
  {
    $forms = $this->getFormsToSave();
  }

  foreach ($forms as $form)
  {
    if ($form instanceof sfFormObject)
    {
      $form->saveEmbeddedForms($con);
      $form->getObject()->save($con);
    }
    else
    {
      $this->saveEmbeddedForms($con, $form->getFormsToSave());
    }
  }
}

public function updateObjectEmbeddedForms($values, $forms = null)
{
  if (null === $forms)
  {
    $forms = $this->getFormsToSave();
  }

  foreach ($forms as $name => $form)
  {
    if (!isset($values[$name]) || !is_array($values[$name]))
    {
      continue;
    }

    if ($form instanceof sfFormObject)
    {
      $form->updateObject($values[$name]);
    }
    else
    {
      $this->updateObjectEmbeddedForms($values[$name], $form->getFormsToSave());
    }
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...