Zapisywanie osadzonych formularzy w Symfony

Zapisywanie osadzonych formularzy w Symfony działa inaczej niż intuicyjnie zakładałem. Co ciekawsze, już raz się z tym kiedyś zetknąłem, ale było to na tyle dawno, że zapomniałem rozwiązania.

Załóżmy, że w zwykłym formularzu dziedziczącym z klasy sfForm osadzam formularz oparty na modelu z bazy danych czyli dziedziczący z sfFormDoctrine.

class OnePageCheckoutForm extends sfForm
{
  public function configure()
  {
    $this->widgetSchema['same_address'] = new sfWidgetFormInputCheckbox();
    $this->validatorSchema['same_address'] = new sfValidatorBoolean();

    $this->embedForm('customer', new CustomerForm());
    $this->embedForm('shipment_address', new AddressForm());
    $this->getWidgetSchema()->setNameFormat('checkout_form[%s]');
  }
}

W kontrolerze chcę zapisać dane z osadzonych formularzy, ale oczywiście klasa OnePageCheckoutForm nie ma metody save(). W pierwszym odruchu napisałem mniej więcej coś takiego:

public function executeCheckout(sfWebRequest $request)
{
  if (!$this->getUser()->hasCart())
  {
    return $this->redirect('@cart');
  }
  $this->cart = $this->getUser()->getCart();

  $this->form = new OnePageCheckoutForm();
  if ($request->getMethod() == 'POST')
  {
    $this->form->bind($request->getParameter($this->form->getName()), $request->getFiles($this->form->getName()));
    if ($this->form->isValid())
    {
      $values = $this->form->getValues();
      $this->form->getEmbeddedForm('customer')->save();
      $this->form->getEmbeddedForm('shipment_address')->save();

      $this->cart->setCustomerId($this->form->getEmbeddedForm('customer')->getObject()->getId());
      $this->cart->save();
      $this->redirect('@cart_payment_process');
    }
  }
}

Ku memu zaskoczeniu zobaczyłem wyjątek, z którego wynikało, że zapis formularza customer się nie powiódł, bo formularz nie zawiera danych. Dla pewności wrzuciłem w kod kilka var_dumpów:

// wynik: dane dla całego formularza łącznie z osadzonymi
var_dump($this->form->getValues());
// wynik: false
var_dump($this->form->getEmbeddedForm('customer')->isBound());
// wynik: pusta tablica
var_dump($this->form->getEmbeddedForm('customer')->getObject()->toArray());

Jak się okazało, formularz klasy sfForm nie aktualizuje obiektów w osadzonych formularzach, trzeba to wykonać samemu:

$this->form->getEmbeddedForm('customer')
  ->updateObject($this->form->getValue('customer'));

Można to zrobić w kontrolerze, ja ze względów konwencjonalno-estetycznych dopisałem do klasy OnePageCheckoutForm metody updateEmbeddedForms() i saveEmbeddedForms(), które są z grubsza kopią tak samo nazwanych metod z klasy sfFormObject.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *