Skip to content

Commit

Permalink
CONTENTBOX-1398 #resolve
Browse files Browse the repository at this point in the history
Cloning a Page with Children Produces an Error
  • Loading branch information
lmajano committed Mar 17, 2022
1 parent a0a3c7e commit e5dd6ee
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 107 deletions.
176 changes: 92 additions & 84 deletions modules/contentbox/models/content/BaseContent.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,7 @@ component
variables.contentType = "";
variables.showInSearch = true;
variables.renderedContent = "";
variables.children = [];
return this;
}

Expand Down Expand Up @@ -1231,7 +1232,7 @@ component
}

/**
* Prepare a content object for cloning. This processes several things:
* Clones the object and stores it in the database
*
* - Wipe primary key, and descendant keys
* - Prepare for cloning of entire hierarchies
Expand All @@ -1244,108 +1245,113 @@ component
* @originalSlugRoot The original slug that will be replaced in all cloned content
* @newSlugRoot The new slug root that will be replaced in all cloned content
*/
BaseContent function prepareForClone(
BaseContent function clone(
required any author,
required any original,
required any originalService,
required boolean publish,
required any originalSlugRoot,
required any newSlugRoot
){
// Base Content Property cloning
variables.isPublished = arguments.publish;
variables.createdDate = now();
variables.modifiedDate = variables.createdDate;
variables.HTMLKeywords = arguments.original.getHTMLKeywords();
variables.HTMLDescription = arguments.original.getHTMLDescription();
variables.HTMLTitle = arguments.original.getHTMLTitle();
variables.markup = arguments.original.getMarkup();
variables.cache = arguments.original.getCache();
variables.cacheTimeout = arguments.original.getCacheTimeout();
variables.cacheLastAccessTimeout = arguments.original.getCacheLastAccessTimeout();
variables.showInSearch = arguments.original.getShowInSearch();
variables.featuredImage = arguments.original.getFeaturedImage();
variables.featuredImageURL = arguments.original.getFeaturedImageURL();
// remove all comments
variables.comments = [];
// Are we publishing?
if ( arguments.publish ) {
variables.publishedDate = now();
}
// get latest content versioning
var latestContent = arguments.original.getActiveContent().getContent();
// Original slug updates on all content
latestContent = reReplaceNoCase(
latestContent,
"page\:\[#arguments.originalSlugRoot#\/",
"page:[#arguments.newSlugRoot#/",
"all"
);
transaction {
// Base Content Property cloning
variables.isPublished = arguments.publish;
variables.createdDate = now();
variables.modifiedDate = variables.createdDate;
variables.HTMLKeywords = arguments.original.getHTMLKeywords();
variables.HTMLDescription = arguments.original.getHTMLDescription();
variables.HTMLTitle = arguments.original.getHTMLTitle();
variables.markup = arguments.original.getMarkup();
variables.cache = arguments.original.getCache();
variables.cacheTimeout = arguments.original.getCacheTimeout();
variables.cacheLastAccessTimeout = arguments.original.getCacheLastAccessTimeout();
variables.showInSearch = arguments.original.getShowInSearch();
variables.featuredImage = arguments.original.getFeaturedImage();
variables.featuredImageURL = arguments.original.getFeaturedImageURL();
variables.comments = [];
variables.children = [];

// Are we publishing?
if ( arguments.publish ) {
variables.publishedDate = now();
}

// reset versioning, and start with a new one
addNewContentVersion(
content : latestContent,
changelog: "Content Cloned!",
author : arguments.author
);
// get latest content versioning
var latestContent = arguments.original.getActiveContent().getContent();
// Original slug updates on all content
latestContent = reReplaceNoCase(
latestContent,
"page\:\[#arguments.originalSlugRoot#\/",
"page:[#arguments.newSlugRoot#/",
"all"
);

// safe clone custom fields
variables.customFields = arguments.original
.getCustomFields()
.map( function( thisField ){
return variables.customFieldService
.new( {
key : arguments.thisField.getKey(),
value : arguments.thisField.getValue()
} )
.setRelatedContent( this );
} );
// reset versioning, and start with a new one
addNewContentVersion(
content : latestContent,
changelog: "Content Cloned!",
author : arguments.author
);

// clone related content
arguments.original
.getRelatedContent()
.each( function( thisRelatedContent ){
addRelatedContent( arguments.thisRelatedContent );
} );
// safe clone custom fields
variables.customFields = arguments.original
.getCustomFields()
.map( function( thisField ){
return variables.customFieldService
.new( {
key : arguments.thisField.getKey(),
value : arguments.thisField.getValue()
} )
.setRelatedContent( this );
} );

// clone categories
arguments.original
.getCategories()
.each( function( thisCategory ){
addCategories( variables.categoryService.getOrCreate( arguments.thisCategory, getSite() ) );
} );
// clone related content
arguments.original
.getRelatedContent()
.each( function( thisRelatedContent ){
addRelatedContent( arguments.thisRelatedContent );
} );

// now clone children
if ( arguments.original.hasChild() ) {
// clone categories
arguments.original
.getChildren()
.each( function( thisChild ){
// Preapre new Child
var newChild = originalService
.new( {
parent : this,
creator : author,
title : arguments.thisChild.getTitle(),
slug : this.getSlug() & "/" & listLast( arguments.thisChild.getSlug(), "/" ),
site : getSite()
} )
// now deep clone until no more child is left behind.
.prepareForClone(
.getCategories()
.each( function( thisCategory ){
addCategories( variables.categoryService.getOrCreate( arguments.thisCategory, getSite() ) );
} );

// now clone children
if ( arguments.original.hasChild() ) {
// Save the parent first to avoid cascade issues
arguments.originalService.save( this );
// Continue down to clone the original children and attach them
arguments.original
.getChildren()
.each( function( thisChild ){
// Clone the child
var newChild = originalService
.new( {
creator : author,
title : arguments.thisChild.getTitle(),
slug : listLast( arguments.thisChild.getSlug(), "/" ),
site : getSite()
} )
.setParent( this );

// now deep clone until no more children are left behind.
newChild.clone(
author = author,
original = arguments.thisChild,
originalService = originalService,
publish = publish,
originalSlugRoot = originalSlugRoot,
newSlugRoot = newSlugRoot
originalSlugRoot = arguments.thisChild.getSlug(),
newSlugRoot = newChild.getSlug()
);

// now attach it to this piece of content
addChild( newChild );
} );
} );
} else {
arguments.originalService.save( this );
}
}

// evict original entity from hibernate cache, just in case
variables.contentService.evict( arguments.original );
// end of cloning transaction

return this;
}
Expand Down Expand Up @@ -1702,6 +1708,8 @@ component
} else {
// Welcome home papa!
variables.parent = arguments.parent;
// I am a ColdBox Daddy!
arguments.parent.addChild( this );
}

// Update slug according to parent hierarchy
Expand Down
4 changes: 2 additions & 2 deletions modules/contentbox/models/content/ContentStore.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ component
* @originalSlugRoot The original slug that will be replaced in all cloned content
* @newSlugRoot The new slug root that will be replaced in all cloned content
*/
BaseContent function prepareForClone(
BaseContent function clone(
required any author,
required any original,
required any originalService,
Expand All @@ -97,7 +97,7 @@ component
setDescription( arguments.original.getDescription() );
setOrder( arguments.original.getOrder() + 1 );
// do core cloning
return super.prepareForClone( argumentCollection = arguments );
return super.clone( argumentCollection = arguments );
}

}
4 changes: 2 additions & 2 deletions modules/contentbox/models/content/Entry.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ component
* @originalSlugRoot The original slug that will be replaced in all cloned content
* @newSlugRoot The new slug root that will be replaced in all cloned content
*/
BaseContent function prepareForClone(
BaseContent function clone(
required any author,
required any original,
required any originalService,
Expand All @@ -120,7 +120,7 @@ component
setExcerpt( arguments.original.getExcerpt() );
}
// do core cloning
return super.prepareForClone( argumentCollection = arguments );
return super.clone( argumentCollection = arguments );
}

}
4 changes: 2 additions & 2 deletions modules/contentbox/models/content/Page.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ component
* @originalSlugRoot The original slug that will be replaced in all cloned content
* @newSlugRoot The new slug root that will be replaced in all cloned content
*/
BaseContent function prepareForClone(
BaseContent function clone(
required any author,
required any original,
required any originalService,
Expand All @@ -216,7 +216,7 @@ component
setExcerpt( arguments.original.getExcerpt() );
}
// do core cloning
return super.prepareForClone( argumentCollection = arguments );
return super.clone( argumentCollection = arguments );
}

/**
Expand Down
2 changes: 1 addition & 1 deletion modules/contentbox/models/content/PageService.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ component extends="ContentService" singleton {
super.save( arguments.page );

// Update all affected child pages if any on slug updates, much like nested set updates its nodes, we update our slugs
if ( structKeyExists( arguments, "originalSlug" ) AND len( arguments.originalSlug ) ) {
if ( !isNull( arguments.originalSlug ) AND len( arguments.originalSlug ) ) {
var pagesInNeed = newCriteria().like( "slug", "#arguments.originalSlug#/%" ).list();
for ( var thisPage in pagesInNeed ) {
thisPage.setSlug(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -495,20 +495,16 @@ component extends="baseHandler" {
}

// get a clone
var clone = variables.ormService.new( {
title : rc.title,
slug : variables.HTMLHelper.slugify( rc.title ),
creator : prc.oCurrentAuthor,
site : variables.siteService.get( rc.site )
} );

// attach to the original's parent.
if ( original.hasParent() ) {
clone.setParent( original.getParent() ).setSlug( original.getSlug() & "/" & clone.getSlug() );
}
var clone = variables.ormService
.new( {
title : rc.title,
slug : variables.HTMLHelper.slugify( rc.title ),
creator : prc.oCurrentAuthor,
site : variables.siteService.get( rc.site )
} )
.setParent( original.getParent() );

// prepare descendants for cloning, might take a while if lots of children to copy.
clone.prepareForClone(
clone.clone(
author : prc.oCurrentAuthor,
original : original,
originalService : variables.ormService,
Expand All @@ -517,9 +513,6 @@ component extends="baseHandler" {
newSlugRoot : clone.getSlug()
);

// clone this sucker now!
variables.ormService.save( clone );

// relocate
variables.cbMessageBox.info( "#variables.entity# Cloned!" );

Expand Down

0 comments on commit e5dd6ee

Please sign in to comment.