Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

General Questions /

General questions about getting started with SilverStripe that don't fit in any of the categories above.

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo, swaiba

Copying Dataobjects (solved sort of)


Go to End


7 Posts   3423 Views

Avatar
cumquat

Community Member, 201 Posts

3 August 2013 at 2:55am

Any got some pointers for me, I have 4 dataobjects, QuoteHeader and QuoteDetail, OrderHeader and OrderDetail (the order tables are copies of their quote counterparts with a couple of extra fields)

QuoteHeader has_many QuoteDetails.
OrderHeader has_many OrderDetails.

This is all good and i have a couple of forms that create the QuoteHeader and then the QuoteDetails, so far so good.
What I want to do now is create a function that on the click of a button it copies the QuoteHeader info to an OrderHeader dataobject and then an QuoteDetails to an OrderDetails dataobject.

Has anyone created a similar function i can look at to tweak for my needs?

Cheers
Mick

Avatar
Sean

Forum Moderator, 922 Posts

5 August 2013 at 11:13am

Edited: 05/08/2013 11:13am

In the context of a Form object, you can always do things like

$quote = new QuoteHeader();
$form->saveInto($quote);

That will save the form contents into the DataObject, provided the names of the field match up to fields on the DataObject's $db definition.

If you wanted to copy a DataObject to another, provided the fields are the same names, you might do something like this:

$data = QuoteHeader::get()->byId(1)->toMap();
$order = new OrderHeader();
$order->update($data);
$order->write();

toMap() returns the internal DataObjects array of db fields and their values, which you can pass into update() called on a new instance of OrderHeader to effectively copy the fields across.

Hopefully that's of some help.

Sean

Avatar
cumquat

Community Member, 201 Posts

5 August 2013 at 11:29pm

Hi Sean,

Thanks for getting back to me, the copying of the dataobject is the way i want to go as i have currently two forms one for header and then one for adding the details. i have tried the code below, without much success, and as ever no error messages it just doesn't seem to make the copy.
I notices when i printed the contents of the array is doesn't list the data for the attached has_many relation is that correct or would you expect that function to copy both the header and details fields and copy those to their respected dataobjects.

function doaddOrder(){
        $quote = QuoteHeader::get()->byId(2)->toMap();
            
        $order = new OrderHeader();

        $order->update($quote);
        //print_r($order);
       
        $order->write();
       // Controller::curr()->redirectBack(); 
    }

class QuoteHeader extends DataObject   {
   
  	public static $db = array(
      'Seq' => 'Int',
      'QuoteNum' => 'Varchar(20)',
      'Date' => 'Date',
      'ExpiryDate' => 'Date',
      'QuoteBy' => 'Varchar(30)',
      'Notes' => 'Text',
      'Status' => 'Varchar(20)'
			
  	);
  	
  
 	public static $has_many =array (
    	'QuoteDetails' => 'QuoteDetail'
	);

----------------------

class QuoteDetail extends DataObject   {
   
  	public static $db = array(
      'PartNum' => 'Varchar()',
      'Name' => 'Varchar()',
      'Qty' => 'int',
      'Price' => 'Currency',
      'Total' => 'Currency'
  	);
  	public static $has_one =array (
  		'QuoteHeader' => 'QuoteHeader'
	);

class OrderHeader extends DataObject   {
   
  	public static $db = array(
      'Seq' => 'Int',
      'OrderNum' => 'Varchar(20)',
      'Date' => 'Date',
      'ExpiryDate' => 'Date',
      'OrderBy' => 'Varchar(30)',
      'Notes' => 'Text',
      'Status' => 'Varchar(20)',

			
  	);
  	
  
 	public static $has_many =array (
    	'OrderDetails' => 'OrderDetail'
	);

-------------------------------
class OrderDetail extends DataObject   {
   
  	public static $db = array(
      'PartNum' => 'Varchar()',
      'Name' => 'Varchar()',
      'Qty' => 'int',
      'Price' => 'Currency',
      'Total' => 'Currency'
  	);
  	public static $has_one =array (
  		'OrderHeader' => 'OrderHeader'
	);

Avatar
martimiz

Forum Moderator, 1391 Posts

6 August 2013 at 9:19am

Edited: 06/08/2013 9:26am

I'm not sure, but it's worth a try: when you map the quoteheader and feed it into the new order, the Orders ID probably gets the value of the QuoteHeader ID as well. Normally the write function will insert if the objects ID is empty, and update on an existing ID.

At this point no record with that ID exists in the OrderHeader table, so it cannot be updated. You could try to set $order->ID = '' before writing. Or, if you want to keep the same ID, set forceInsert to true?

[edit]
write() will not create copies of the details automatically, but write() will return the ID of the newly created order, which you can then use to link a copy of the details to the correct order...

Avatar
cumquat

Community Member, 201 Posts

7 August 2013 at 3:47am

Cheers for response.
I couldn't get the mapping to work so ended up having to sort it manually for now so i can move forward, code below.

function doaddOrder(){
         $theID = $this->request->getVar('quote');

        $quote = QuoteHeader::get()->byId($theID);
        $submission  = new OrderHeader();
        $submission->Seq = $quote->Seq;
        $submission->Date = $quote->Date;
        $submission->Notes = $quote->Notes;
        $submission->QuoteID = $quote->ID;
        $submission->CustomerID = $quote->CustomerID;
        $submission->DeliveryID = $quote->DeliveryID;
        $submission->InvoiceID = $quote->InvoiceID;
        $submission->ContactID = $quote->ContactID;
        $submission ->write();
        
        $QuoteItems = QuoteDetail::get()->filter('QuoteHeaderID' , $theID); 
            foreach($QuoteItems as $QuoteItem){ 
                $sub  = new OrderDetail();
                $sub->PartNum = $QuoteItem->PartNum;
                $sub->Name = $QuoteItem->Name;
                $sub->Qty = $QuoteItem->Qty;
                $sub->Price = $QuoteItem->Price;
                $sub->Total = $QuoteItem->Total;
                $sub->OrderHeaderID = $submission->ID;
                $sub->write();
         
            }
        Controller::curr()->redirectBack();
    }

Avatar
Ben_W

Community Member, 80 Posts

10 June 2014 at 4:53pm

I have come across the same problem, follow the advice here and managed to copy one DataObject to another similar DataObject. Just remember to unset the ID and ClassName from the original DataObject, so that they won't get copied cross which will result in errors. Please see the following code:

$quote = QuoteHeader::get()->byId(2)->toMap();

//Unset ID and ClassName
unset($quote['ID']);
unset($quote['ClassName']);

$order = new OrderHeader();

$order->update($quote);

$order->write();

Avatar
Bonner

Community Member, 21 Posts

11 June 2014 at 2:42am

Would it not be better to write a wrapper and use reflection?