XerXes
XerXes

Reputation: 733

Clone entity and all related entities in CakePHP 3

In my CakePHP 3 app, I have a somewhat elaborate tree of entities that I need to clone and save.

The root of the structure is a Questionnaire, a Questionnaire hasMany Questions, each Question hasMany Fields, etc. (it goes deeper). Now I want the user to be able to define a new questionnaire by copying an old one. Then they can change whatever they need.

I can get a dump of what I need to copy by using $questionnaire->$this->Questionnaires->get($id) with the appropriate contain fields. Is there a clever way to save this as a bunch of new entities while preserving the data and the structure between them?

Upvotes: 5

Views: 6021

Answers (5)

Spriz
Spriz

Reputation: 457

I think the best possible way would be following work flow:

  1. Get object you want to clone
  2. Go through the collection and remove all ID's
  3. Convert to array and use that in $this->Questionnaires->newEntity($arrayData, ['associated' => ['Questions', '...']]);
  4. Now save the new entity with all the related data you want to keep

AFAIK there's no "smarter" way of cloning an entity with associations in Cake 3 :-)

Upvotes: 6

Valentin Link
Valentin Link

Reputation: 11

$original = $this->Table->get($id)->toArray();
$copy = $this->Table->newEntity();
$copy = $this->Table->patchEntity($copy, $original);

unset($copy['id']);
// Unset or modify all others what you need

$this->Table->save($copy);

Work perfectly like this :)

Upvotes: 1

Maayan Maltz
Maayan Maltz

Reputation: 11

use EntityInteface toArray() to get all its fields:

$newEtity = $someTable->newEntity($oldEtity->toArray());
unset($newDevice->created);
unset($newDevice->id);
$someTable->save($newEntity);

Upvotes: 1

ᴍᴇʜᴏᴠ
ᴍᴇʜᴏᴠ

Reputation: 5256

Here's the way I did it when I needed something similar (adapted to the Questionnaire example):

// load the models
$this->loadModel('Questionnaire');
$this->loadModel('Questions');
// get the questions to questionnaire association - will need the PK name
$qAssoc = $this->{'Questions'}->associations()->get('Questionnaire');
// get the existing entity to copy
$existingEntity = $this->{'Questionnaire'}->get($id, [
    'contain' => ['Questions'],
]);
// clean up the existing entity
$existingEntity->unsetProperty($this->{'Questionnaire'}->getPrimaryKey());
$existingEntity->unsetProperty('created');
$existingEntity->unsetProperty('modified');
// clean up the associated records of the existing entity
foreach ($existingEntity->questions as &$q) {
    $q->unsetProperty($this->{'Questions'}->getPrimaryKey());
    $q->unsetProperty($qAssoc->getForeignKey());
}
// create a new entity and patch it with source data
$newEntity = $this->{'Questionnaire'}->patchEntity(
        $this->{'Questionnaire'}->newEntity(),
        $existingEntity->toArray()
);
// save the new entity
$result = $this->{'Questionnaire'}->save($existingEntity);

References:

Upvotes: 0

pperejon
pperejon

Reputation: 443

You could also use this plugin. You only have to configure the behavior and it gives you other functionalities, like setting default values or appending text to some field.

Upvotes: 6

Related Questions