Hello Symfony fans,

I'm hoping someone can point to the error in my ways.  I am working with
embedded forms and the problem is that the master record is saved to the
database, but not the user date for the detail records.  I have followed the
'more with symphony 1.4 en' example very carefully and have been very
successful with all aspects of the project except getting the save to work.
It's like a Toyota scenario where I have a great car, except for one fatal
flaw.  Hoping you can help.

The schema involves a master record, Transaction Receipt (master form), and
two detail records: PurchaseDetail (Purchases) and PaymentDetail (Payments),
the embedded forms.  For every receipt there must be at least one purchase
and one payment detail.  My validation rules for this work well thanks to
the examples in the tutorial.  The schema is as follows (I left a lot out
except the essentials for readability):

TransactionReceipt:
  connection: doctrine
  tableName: TransactionReceipt
  actAs:  { Timestampable: }
  columns:
    receipt_id:  {  type: integer(4), primary: true, autoincrement: true }
    paid_amount:  { type: 'decimal(5, 2)',  notnull: true }
    paid_date:  { type: timestamp(25), notnull: true }
    Purchases:  { class: PurchaseDetail, local: receipt_id, foreign:
receipt_id, type: many }
    Payments:  { class: PaymentDetail, local: receipt_id, foreign:
receipt_id, type: many }

PurchaseDetail:
  connection: doctrine
  tableName: PurchaseDetail
  actAs:  { Timestampable: }
  columns:
    purchase_id:  { type: integer(4), primary: true, autoincrement: true}
    receipt_id:  { type: integer(4) }
    fee_name:  { type: string(45) }
    fee_description:  { type: string(45) }
    fee_amount:  { type: 'decimal(5, 2)'  }
    quantity:  { type: integer(4) }
  relations:
    TransactionReceipt:  { owningSide: Yes, local: receipt_id, type: one,
foreign: receipt_id, foreignType: many, foreignAlias: Purchases, onDelete:
CASCADE, onUpdate: CASCADE }

PaymentDetail:
  connection: doctrine
  tableName: PaymentDetail
  actAs:  { Timestampable: }
  columns:
    payment_id:  { type: integer(4), primary: true, autoincrement: true }
    receipt_id:  { type: integer(4) }
    payment_type:  { type: string(2) }
    payment_amount:  { type: 'decimal(5, 2)'  }
  relations:
    TransactionReceipt:  { owningSide: Yes, local: receipt_id, type: one,
foreign: receipt_id, foreignType: many, foreignAlias: Payments, onDelete:
CASCADE,  onUpdate: CASCADE }

The YAML dump of the tainted values are taken in TransactionReceiptForm at
the beginning of the saveEmbeddedForms method.
The results demonstrate that the subforms are correctly holding the tainted
values provided by the user.

_csrf_token: 4abd94aee8c8a102c044558e44263726
student_id: '10002'
for_academic_year: '2009'
paid_date: '2010-05-29 18:20:12'
receipt_amount: '20.00'
paid_amount: '20.00'
newPurchases:
  -
    fee_name: 'ACT Pass'
    fee_amount: '20.00'
    quantity: '1'
  -
    fee_name: ''
    fee_amount: ''
    quantity: ''
  -
    fee_name: ''
    fee_amount: ''
    quantity: ''
  -
    fee_name: ''
    fee_amount: ''
    quantity: ''
paid_by: mom
newPayments:
  -
    payment_type: CA
    payment_amount: '20'
  -
    payment_type: ''
    payment_amount: ''

In TransactionReceiptForm the default framework doSave method is called, I
don't override it.  When there are errors in any of the subfields they are
handled correctly.  However, when there are no errors and the doSave can
proceed with saving the data to disk, only the master TransactionReceipt
record is written to disk.  None of the detail records for Payments or
Purchases are written to disk.  If I comment out the 'unset' logic in
TransactionReceiptForm method saveEmbeddedForm, then the detail records with
'null' values are saved but none of the user input is saved too.  Each
detail record does include the receipt_id, so that's a good start.

My TransactionReceiptForm, method configure is as follows:
    . . .
    $collectionForm = new PurchaseDetailCollectionForm(null, array(
      'receipt' => $this->getObject(),
      'count'   => sfConfig::get('app_purchases_per_form'),
    ));
    $this->embedForm('newPurchases', $collectionForm);
    $collectionForm = new PaymentDetailCollectionForm(null, array(
      'receipt' => $this->getObject(),
      'count'   => sfConfig::get('app_payments_per_form'),
    ));
    $this->embedForm('newPayments', $collectionForm);
    $this->embedRelation('Purchases');
    $this->embedRelation('Payments');
    . . .


My collection form is as follows (following the tutorial very carefully):

class PaymentDetailCollectionForm extends BaseForm //sfForm
{
  public function configure()
  {
    if (!$receipt = $this->getOption('receipt'))
    {
      throw new InvalidArgumentException('Error: PaymentDetailCollectionForm
requires a TransactionReceipt object.');
    }
   $count = (Integer)sfConfig::get('app_payments_per_form'); // see app.yml
    for ($i = 0; $i < $this->getOption('count', $count); $i++)
    {
      $paymentDetail = new PaymentDetail();
      $paymentDetail->TransactionReceipt = $receipt;
      $subForm = new PaymentDetailForm($paymentDetail);
      $this->embedForm($i, $subForm);
    }
    $this->mergePostValidator(new PaymentDetailValidatorSchema());
  }
}

After reading the posts, not sure if I'm experiencing the reported bug or if
I must
take care of writing the code to bind the subforms.

Any advice would be greatly appreciated, I've been stuck on this quite a
while.
It's my first Symfony protect.

Thanks
 - Michael

-- 
If you want to report a vulnerability issue on symfony, please send it to 
security at symfony-project.com

You received this message because you are subscribed to the Google
Groups "symfony users" group.
To post to this group, send email to symfony-users@googlegroups.com
To unsubscribe from this group, send email to
symfony-users+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/symfony-users?hl=en

Reply via email to