diff --git a/modules/contentbox/models/content/BaseContent.cfc b/modules/contentbox/models/content/BaseContent.cfc index fdf59ce0dd..0e0ea8c91c 100644 --- a/modules/contentbox/models/content/BaseContent.cfc +++ b/modules/contentbox/models/content/BaseContent.cfc @@ -607,6 +607,7 @@ component variables.contentType = ""; variables.showInSearch = true; variables.renderedContent = ""; + variables.children = []; return this; } @@ -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 @@ -1244,7 +1245,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, @@ -1252,100 +1253,105 @@ component 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; } @@ -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 diff --git a/modules/contentbox/models/content/ContentStore.cfc b/modules/contentbox/models/content/ContentStore.cfc index b803ab111b..1c0c847532 100755 --- a/modules/contentbox/models/content/ContentStore.cfc +++ b/modules/contentbox/models/content/ContentStore.cfc @@ -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, @@ -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 ); } } diff --git a/modules/contentbox/models/content/Entry.cfc b/modules/contentbox/models/content/Entry.cfc index 427a048afa..301a446d28 100755 --- a/modules/contentbox/models/content/Entry.cfc +++ b/modules/contentbox/models/content/Entry.cfc @@ -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, @@ -120,7 +120,7 @@ component setExcerpt( arguments.original.getExcerpt() ); } // do core cloning - return super.prepareForClone( argumentCollection = arguments ); + return super.clone( argumentCollection = arguments ); } } diff --git a/modules/contentbox/models/content/Page.cfc b/modules/contentbox/models/content/Page.cfc index 6232cd3e3a..c33cdb79eb 100755 --- a/modules/contentbox/models/content/Page.cfc +++ b/modules/contentbox/models/content/Page.cfc @@ -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, @@ -216,7 +216,7 @@ component setExcerpt( arguments.original.getExcerpt() ); } // do core cloning - return super.prepareForClone( argumentCollection = arguments ); + return super.clone( argumentCollection = arguments ); } /** diff --git a/modules/contentbox/models/content/PageService.cfc b/modules/contentbox/models/content/PageService.cfc index fd6b928922..af6de080e5 100755 --- a/modules/contentbox/models/content/PageService.cfc +++ b/modules/contentbox/models/content/PageService.cfc @@ -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( diff --git a/modules/contentbox/modules/contentbox-admin/handlers/baseContentHandler.cfc b/modules/contentbox/modules/contentbox-admin/handlers/baseContentHandler.cfc index adf8284c15..450b7ec2b7 100644 --- a/modules/contentbox/modules/contentbox-admin/handlers/baseContentHandler.cfc +++ b/modules/contentbox/modules/contentbox-admin/handlers/baseContentHandler.cfc @@ -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, @@ -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!" );