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
.
1 2 3 4 5 6 7 8 9 10 11 12 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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:
1 2 3 4 5 6 | var_dump( $this ->form->getValues());
var_dump( $this ->form->getEmbeddedForm( 'customer' )->isBound());
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:
1 2 | $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
.