cakephpmodelassociationsduplication

Duplicate model along with it's associations


I came across this post that gave an answer on how to do this but it's not quite working for me.

I have a model called SitePage which has many SitePageGroup which in turn has many SitePageContent

// SitePage Model
public $hasMany = array(
    'SitePageGroup' => array(
        'className' => 'FoCMS.SitePageGroup',
        'foreignKey' => 'site_page_id',
        'dependent' => FALSE,
    ),
);

// SitePageGroup Model
public $belongsTo = array(
    'SitePage' => array(
        'className' => 'FoCMS.SitePage',
        'foreignKey' => 'site_page_id',
    ),
);

public $hasMany = array(
    'SitePageContent' => array(
        'className' => 'FoCMS.SitePageContent',
        'foreignKey' => 'site_page_group_id',
        'dependent' => FALSE,
    ),
);

// SitePageContent Model
public $belongsTo = array(
    'SitePageGroup' => array(
        'className' => 'FoCMS.SitePageGroup',
        'foreignKey' => 'site_page_group_id',
    ),
);

Using the answer in that linked question I am seeing the parent model, SitePage being duplicated, but the associated models are being removed from the original and associated with the new one.

$record = $this->SitePage->find('first', array('condition' => array('SitePage.id' => $id)));
unset($record['SitePage']['id'], $record['SitePageGroup']['id'], $record['SitePageGroup']['SitePageContent']['id'] /* further ids */);
$this->SitePage->create();
$record['SitePage']['name'] = $record['SitePage']['name'].'-copy';
$record['SitePage']['friendly_name'] = $record['SitePage']['friendly_name'].' Copy';
if($this->SitePage->saveAll($record)){
    $this->Session->setFlash('The site page has been saved', 'fo_message');
    $this->redirect(array('action' => 'index'));
}else{
    $this->Session->setFlash('The site page could not be saved. Please, try again.', 'fo_message');
}

Update

Debugging the record that I'm trying to reset I see the following

array(
    'SitePage' => array(
        'name' => 'test',
        'friendly_name' => 'Test',
        'order' => '82',
        'created' => '2015-09-03 19:16:40',
        'modified' => '2015-09-03 19:20:27'
    ),
    'SitePageGroup' => array(
        (int) 0 => array(
            'id' => '55e88087-a4dc-4c37-89dc-f9c172b40463',
            'site_page_id' => '55e88078-16c8-46ce-bf02-fa5372b40463',
            'name' => 'group-1',
            'friendly_name' => 'Group 1',
            'order' => '1',
            'created' => '2015-09-03 19:16:55',
            'modified' => '2015-09-03 19:16:55'
        ),
        (int) 1 => array(
            'id' => '55e8809e-d018-4ebe-a4cf-fbef72b40463',
            'site_page_id' => '55e88078-16c8-46ce-bf02-fa5372b40463',
            'name' => 'group-2',
            'friendly_name' => 'Group 2',
            'order' => '2',
            'created' => '2015-09-03 19:17:18',
            'modified' => '2015-09-03 19:17:18'
        )
    )
)

The way I am getting this result is by doing this

$sitePage = $this->SitePage->find('first', array(
    'conditions' => array(
        'SitePage.id' => $id,
    ),
));

unset($sitePage['SitePage']['id'], $sitePage['SitePageGroup']['id'], $sitePage['SitePageGroup']['SitePageContent']['id'], $sitePage['SitePageGroup']['site_page_id'], $sitePage['SitePageGroup']['SitePageContent']['site_page_group_id'] /* further ids */);
debug($sitePage);
die();

But also also as you can see in the debug output the 3rd level of associated models are not being included, each of the SitePageGroup should also have a SitePageContent

I think a simple loop over the array of SitePageGroup should reset the id's and set the foreign keys to null, but I guess I also need to somehow include the SitePageContent that belongs to the SitePageGroup so I can reset those as well.


Solution

  • You need to ensure that all primary and foreign keys are set to null before saving. You only appear to be resetting the primary keys of your models but Cake needs to know that the foreign keys need generating so that they reference the new records.

    Before calling $record it might be worth using debug($record); to check that everything in that array has been set/reset appropriately to ensure the copy will work as expected.

    Update

    Based on the array contents you've posted in your updated question it appears that you are not removing all the primary and foreign keys from your save data. You need to make sure that these are removed from everything you are about to save including the has many associations.

    If you look at your array you should be able to see that unset($sitePage['SitePageGroup']['id']) will not remove the primary IDs of your SitePageGroup data as what you are unsetting doesn't correspond to array paths in your $sitePage array.

    You can use CakePHP's Hash utility to remove the primary keys from the array like this:-

    $sitePage = Hash::remove($sitePage, 'SitePageGroup.{n}.id');
    

    And similarly for the foreign keys:-

    $sitePage = Hash::remove($sitePage, 'SitePageGroup.{n}.site_page_id');