Copy a Doctrine object with all relations

2020-07-24 03:48发布

问题:

I want to copy a record with all his relations.

I'm trying with:

$o = Doctrine::getTable('Table')->Find(x); 
$copy = $object->copy();
$relations = $o->getRelations();

foreach ($relations as $name => $relation) {
  $copy->$relation = $object->$relation->copy();
} 

$copy->save();

This code doesn't works, but I think it's on the way.

回答1:

I never could get the deep copy function to operate correctly.

I manually coded a deep copy function for one of my models like this

public function copyAndSave ()
{
    $filters = array('id', 'created');

    $survey = $this->copy();

    $survey->Survey_Entries = new Doctrine_Collection("Survey_Model_Entry");
    $survey->Assignment_Assignments = new Doctrine_Collection("Assignment_Model_Assignment");
    $survey->Survey_Questions = new Doctrine_Collection("Survey_Model_Question");

    $survey->save();

    foreach ($this->Survey_Questions as $question)
    {
        $answers = $question->Survey_Answers;
        $newQuestion = $question->copy();
        $newQuestion->survey_surveys_id = $survey->id;
        $newQuestion->save();
        $newAnswers = new Doctrine_Collection("Survey_Model_Answer");

        foreach($answers as $answer)
        {
            $answer = $answer->copy();
            $answer->save();
            $answer->survey_questions_id = $newQuestion->id;
            $newAnswers->add($answer);
        }
        $newQuestion->Survey_Answers = $newAnswers;

        $survey->Survey_Questions->add($newQuestion);
    }
    return $survey->save();
}


回答2:

You can read about copy() here. It takes an optional parameter $deep:

$deep
whether to duplicates the objects targeted by the relations

So

$copy = $object->copy(true);

should do it.



回答3:

Sorry if I'm resurrecting this thread...

I found myself in search of a solution recently where I needed to copy a record and retain the references of the original. A deep copy $record->copy(true) copies the references, which was no good for me. This was my solution:

$record = Doctrine_Core::getTable('Foo')->find(1);
$copy = $record->copy();

foreach($record->getTable()->getRelations() as $relation) {
    if ($relation instanceof Doctrine_Relation_Association) {
        $ids = array();

        foreach ($relation->fetchRelatedFor($record) as $r) {    
            $ids[] = $r->getId();
        }

        $copy->link($relation->getAlias(), $ids);
    }
}

if ($copy->isValid()) {
    $copy->save();
}

Hope this helps :)



回答4:

This is how i done, but some fix is needed.

    $table = $entidade->getTable();
    $relations = $table->getRelations();
    foreach($relations as $relation => $data) {
        try {
            $entity->loadReference($relation);
        } catch(Exception $e) {
            die($e->getMessage());
        }
    }


回答5:

I am using Symfony1.4.1 and that uses Doctrine 1.2.1 (I think).

I have been trying to make a function that did all the above myself, when I found one that already exists.

Try this in any function and look at the results:

  $tmp=$this->toArray(TRUE);
  var_dump($tmp);
  $this->refreshRelated();
  $tmp=$this->toArray();
  var_dump($tmp);
  $tmp=$this->toArray(TRUE);
  var_dump($tmp);
  exit();

I am going to try two different things:

A/ put $this->refreshRelated() into the constructor of all my model objects. B/ write a function that takes an array depicting the object graph that I want populated. Calling the function refereshRelatedGraph($objectGraphArray). With the right structure of the array (having all the appropriate relation names at each level), I could control which relations get populated and which don't. One use for this is to populate only children, not parent relations. The other is for when a ERD/Schema/ObjectGraph has an element that is 'owned' by more than one object (many to many, other special circumstances that I have), I could control which side of the relationships get pre(non lazy) loaded.