Thursday, July 28, 2016

Tapping on to Duplicate Item pipeline - Sitecore

Tapping Duplicate Item Pipeline


One of the latest requirements and challenging request was to tap on to duplicate item pipeline on latest version of Sitecore.  As of this writing, Sitecore 8.1, update 3.
Every time I have a problem on my hand, to come up with a solution, I clearly imprint on my brain what my goal is, this actually helps find different ways to achieve what you want the system on hand to do.
My goal was to tap on to duplicateitem pipeline somehow to do few renaming and change of few references post duplication of a specific item on the content tree.  The key here is specific item, I dont want this custom code to run if the duplication is done on any other item, so, it is important to know where and how I can patch this to successfully instruct sitecore. "Hey! If content author is duplicating this 'xyz' item only, perform a set of operations"
I ran across couple blogs to start understanding what happens behind the scenes.  Not much of help as either these are outdated and probably not close to what I was looking for....
So, time to write it up, so any one who is looking for some direction on how to tap to duplicate pipeline.


Trials and Failure


I went ahead and looked at my "showconfig.aspx", found the below related config section under processors and this felt like perfect place I could patch on to -


<uiDuplicateItem>
<processor mode="on" type="Sitecore.Shell.Framework.Pipelines.DuplicateItem,Sitecore.Kernel" method="CheckPermissions"/>
<processor mode="on" type="Sitecore.Shell.Framework.Pipelines.DuplicateItem,Sitecore.Kernel" method="GetName"/>
<processor mode="on" type="Sitecore.Buckets.Pipelines.UI.ItemDuplicate, Sitecore.Buckets" method="Execute" patch:source="Sitecore.Buckets.config"/>
<processor mode="on" type="Sitecore.Shell.Framework.Pipelines.DuplicateItem,Sitecore.Kernel" method="Execute"/>
</uiDuplicateItem>

I tried patching to most apt looking processor which is "Sitecore.Shell.Framework.Pipelines.DuplicateItem", did not work. :(

It is because of introduction of buckets which I came across while reading related blogs out there. Great read if you have time.

http://jockstothecore.com/a-tale-of-three-friends-close-look-at-three-sitecore-pipelines/

Based on this article, I patched on to before the buckets related pipeline for duplicate 
that is 'Sitecore.Buckets.Pipelines.UI.ItemDuplicate'

The challenge here was the client args in the info object had array of fields under the item that is to be duplicated which I had no way to overwrite. So, it does not achieve my goal, scrap that. 

Then, I thought I will tap SaveItem pipeline, but, I will loose the context of which item is being duplicated and either way's duplicateitem does not trigger save item pipeline, so that would not work. 

I am hitting walls in every direction, but, I need to keep looking and trying...

Voila Moment!!!!!

I was curious what does Sitecore.Buckets Item Duplicate pipeline does with Client Args as that route made most sense.  It seems only thing the code uses from Client Args was the "Name" for the new item. 
While exploring the code on Kernel dll using reflector, I see that it directly calls Context.Workflow.DuplicateItem(item, args["name")).  This is getting interesting, seems like I see light at the end of the tunnel. 

Explored more deeper, chain of methods called from this point one ->

Item.Duplicate(copyName)
this.CopyTo(parent,copyName)
this.CopyTo(more params)
ItemManager.CopyItem(all params)
Provider.CopyItem(params related)

On derived type of copyItem of Provider, I see something that caught my eye. 
It calls GetDataEngine and proceeding with CopyItem on DataEngine.  Dug more deeper..
It calls CopyItemCommand's Execute, Voila!!! I found my answer. Panicking with excitement, I tried extending CopyItemCommand's prototype using the below kind of config edits 


<database id="master" singleInstance="true" type="Sitecore.Data.Database, Sitecore.Kernel">
        <Engines.DataEngine.Commands.CopyItemPrototype>       
          <obj type="Yournamespace.ClassName, DLL" />
        </Engines.DataEngine.Commands.CopyItemPrototype>
      </database>

I followed similar syntax from Sitecore.Buckets.Config to make this work.  There is a catch, always make sure you are overriding CreateInstance method and returning your new class in that method, otherwise it will not consider your class as valid prototype and will take the default one. 
Now extend the class "Sitecore.Data.Engines.DataCommands.CopyItemCommand"

It worked!!!!

I could get the source item, destination item(parent), copy ID(new id to be created) and I can extend the Executed method now to add my own business logic.  

Make sure you you call base.Executed() to ensure the base functionality is still in place. 

Good Reads/Helpful Related articles
https://reasoncodeexample.com/2013/01/13/changing-sitecore-item-references-when-creating-copying-duplicating-and-cloning/

http://jockstothecore.com/a-tale-of-three-friends-close-look-at-three-sitecore-pipelines/

http://www.sitecore.net/learn/blogs/technical-blogs/john-west-sitecore-blog/posts/2010/11/intercepting-item-updates-with-sitecore.aspx

No comments :

Post a Comment