Wow, I haven’t posted anything on my blog for a while. I guess I must be busy. A new baby will have that effect.
Anyway, I’m happy to release an update to my Copyable behavior, which I shared with everyone a few months ago.
Download the new version on the Github repository.
Along with some general bug fixes, this newest version has a couple of significant bug fixes:
- Validation is no longer performed before saving the new record. Validation was causing some issues with deep hasMany associations. I don’t see validation as necessary for copying anyway, since the original record already exists.
- For model associations that can be infinitely nested, such as Page hasMany ChildPage (and then that ChildPage hasMany ChildPage, etc.), copying stops after the first level of containment. These types of associations were causing infinite loops when generating the contain array.
There’s also a new setting, “ignore”, which allows you to specify, via dot (.) notation, contained models that should be ignored.
For example, if a contain array for your model looks like this:
$contain = array(
'Page' => array('Image'),
'Log',
'User' => array('Group' => array('Permission'))
);
You can exclude the “Permission” contain by specifying the ignore setting:
public $actsAs = array('Copyable' => array('ignore' => array('User.Group.Permission')));
Handy for excluding certain assocations that don’t need to be copied, like changelogs and that sort of thing.
Enjoy, and, as always, comments and suggestions welcome!

Very nice, any way to make it go deeper than one level? I’d love it if it would copy all the way down the hierarchy.
David – it should copy as deep as your associations go, with the exception of parent->child relationships within the same table (since that leads to infinite loops when building the contain array). Is it not copying recursively for you as it should?
I like the behavior but it does not work for me in CakePHP 1.3.3 with simple HABTM join tables.
$joinInfo = Set::extract($record[$val['className']], ‘{n}.’.$val['with']);
Using xdebug the $joinInfo does contain the correct number of HABTM associations i.e. keys, but each values is undefined … I found the root cause:
You say in the comment of __convertHabtm() “This is done instead of a simple collection of IDs of the associated records, since HABTM join tables may contain extra information (sorting order, etc).”.
BUT this is only the case if cakephp detects any aditional fields – otherwise in a find returned record no HABTM join table array is added at all.
You can test this by using a join table with only 2 id fields – fails … if you add another 3rd field – works.
Can you fix this? This would make the behaviour even greater!