How to easily duplicate Active Record rows

Hi guys,

What is the easiest way to duplicate an AR instance? Cloning it with PHP, removing the PK ID and calling save()? Could that perhaps become an AR method?

Cheers

Cass

Are you trying to insert new records? If so, you just need to set isNewRecord to true each time after you save a record.

1 Like

Hi Qiang,

No, I am trying to duplicate a record, changing the PK ID.

I created a duplicate() method to AR. How do I send it for your analysis?

Cheers

Cass

Could you paste it here?

There you go:

/**


 * Duplicates the current record.


 * A copy of the record is inserted as another row after its PK having been reset


 * Unique fields need to be informed as parameters in order to append some


 * text to them thus avoiding the constraint.


 *


 * Example:


 *


 *  Create an action in your controller as follows:


 *


 *	public function actionDuplicate()


 *	{


 *


 *	   $property=Property::model()->findByPk($_GET["id"]);


 *


 *     $property->duplicate(array("title"));


 *


 *	   $this->redirect(array('admin'));


 * 	 }


 *


 * @param array of field names to append text to


 * @return boolean whether the duplication succeeds


 * @author Cass Surek <cass@surek.co.uk>


 */


public function duplicate($modifiable=null)


{





	// Making sure our PK is null before inserting it


	$table=$this->getMetaData()->tableSchema;


	$primaryKey=$table->primaryKey;


	$this->$primaryKey = "";





	// We might need to change some fields contents to avoid UNIQUE constraints


	// A few md5() chars should do the trick


	foreach($modifiable as $field){


		$this->$field = $this->$field . " " . substr(md5(time()),0,4);


	}





	// Insert requires it to be flagged as new record


	$this->isNewRecord = true;





	// And finally inserting it


	return $this->insert();





}

Thanks for the code. I think this functionality is perhaps too specialized and is not suitable to put in CActiveRecord. You can also easily achieve the similar functionality using PHP's clone operator.

Hi, I disagree, but respect your opinion.

Thanks

Cass

even if this thread is very old it appears at googling for this subject first…

my solution for this problem was:

(basically without looking at the relations)




public function copy()

{

        Yii::log('Start copy'.$this->id, 'info', 'copy'.__CLASS__);

        $new = new MyClass();

        $data = $this->attributes;

        $data['create_time'] = time();

        $data['update_time'] = time();

        unset($data['id']); //unset id since we want to insert

        $new->setAttributes($data, false);

        $new->insert();

        if (!$new->id)

        {

            Yii::log('Couldn\'t copy', 'info', 'copy'.__CLASS__);

            return null;

        }

        return $new;

}

when copying has_many relations the copy function must be parametrized by the $new->id for example

copying belongs_to is simple just


$newBelong = $this->myBelong->copy();

if ($newBelong !== null)

    $new->myBelongId = $newBelong->id;

so i think it is possible to write generic code for that…

Hi, i’ve done it like below in my project:

In my controller




$anotherModel=AnotherModel::model()->find('id=:ID',array(':ID'=>$id));

$model->attributes=$anotherModel->attributes;

$model->save();



It works for me. Duplicate only 1 row exactly.

Or You can duplicate from any table to any table as you wish on your current controller.

You can also modify attributes value before inserting it.