Question on Saving a new Record which has many new Records to gether

I need some expert to advice that how to save a record, for example a Invoice table record, which has many Item records.

My problem is, I need to save the Invoice, and also need to save all the Items which has the newly auto generated invoice id by MySQL, I can do the following:




$newInvoice->save();

foreach($items as $item) {

    $item->invoiceId = $newInvoice->id;

    $item->save();

}



I try to make my code more clear by only this:




$newInvoice->arrItems = $items;

$newInvoice->save();



and all the items will saved as well, which means I need to write code inside the Invoice:save() to save all the items. But the problem come,

  1. How can I get the newly generated invoice id?

  2. Validation problem while saving item.

Can some body please advice what is the proper way to do this simple logic… Help is really appreaciated…

How about using afterSave()?

I tried afterSave() but the $newInvoice->save() sound not aware of error happened on the $item->save().

I tried to log some data to yii log, it does call the afterSave(), but the result it only Invoice record are save, Item record are not saved.

Here is my code:




class Invoice extends CActiveRecord

{

	..

	..

	public function afterSave() {

		Yii::log('Entering afterSave() routing..', 'info');

	

		# Save each items

		foreach($this->items as $item) { /* @var $item Item */

			$item->itemId = $this->id; # $this is Invoice

			if(!$item->save()) {

				$this->addError('ITEM_ERROR', 'Error Found on Item');

				return false;

			}

		}

		return parent::afterSave();

	}

	...

	...

}



I has check there is item data validation error, which mean $item->save() is returning false.

Can you please advice how to return false to $newInvoice->save(), if one of the items are not valid? Or am I doing the right way?

You could add a beforeValidate() or afterValidate() where you first validate all your items and add an error to $this if one of them doesn’t validate.

You mean before I can add a beforeValidate in this Invoice ActiveRecord class, inside this function beforeValidate() I can check every items validation, in the case of not valid, then return false. As the result, the code $newInvoice->save() will return false, which is what I want exactly, (correct? is this the way?)




class Invoice extends CActiveRecord

{

	..

	..

	public function afterSave() {

		# Save each items, do not validate here course already done inside beforeValidate()

		foreach($this->items as $item) { /* @var $item Item */

			$item->itemId = $this->id; # $this is Invoice

			$item->save();

		}

		return parent::afterSave();

	}

	...

	public function beforeValidate() {

		# Do validate all items here, return false if one of the items cannot validated.

	}

	...

}



Please correct me if I miss understand. Thanks for your advice. :D

You would do the same as you tried before. Just don’t call save() on items but validate():


        public function beforeValidate() {

                # Validate each items

                foreach($this->items as $item) { /* @var $item Item */

                        if(!$item->validate()) {

                                $this->addError('ITEM_ERROR', 'Error Found on Item');

                                return false;

                        }

                }

                return true; 

        }



Thanks! Super clear now! :D