Skip to content

Instantly share code, notes, and snippets.

@janhebnes
Created August 31, 2012 09:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save janhebnes/3550920 to your computer and use it in GitHub Desktop.
Save janhebnes/3550920 to your computer and use it in GitHub Desktop.
Sitecore CMS - Handling Item copying where DataSources are referenced inside the copied structure, to inserted in the Item:Copied event queue.
/// <summary>
/// Class used to update Spot Context Data, when copying trees in Sitecore.
/// </summary>
public class LayoutDataSourceReferenceUpdater
{
#region Properties
/// <summary>
/// Gets or sets the new root Item (source item).
/// </summary>
/// <value>The new root Item.</value>
public Item NewRoot
{
get;
set;
}
/// <summary>
/// Gets or sets the original root Item (destination item).
/// </summary>
/// <value>The original root Item.</value>
public Item OriginalRoot
{
get;
set;
}
#endregion Properties
#region Methods
/// <summary>
/// Updates the references using <see cref="OriginalRoot"/> and <see cref="NewRoot"/>.
/// </summary>
/// <param name="parameters">The parameters.</param>
public void UpdateReferences(object[] parameters)
{
Assert.IsNotNull(OriginalRoot, "OriginalRoot cannot be null");
Assert.IsNotNull(NewRoot, "NewRoot cannot be null");
UpdateTree(OriginalRoot);
}
/// <summary>
/// Finds the corresponding item using <see cref="OriginalRoot"/> and <see cref="NewRoot"/>.
/// </summary>
/// <param name="itemBeingCopied">The item being copied.</param>
/// <returns></returns>
private Item FindCorrespondingItem(Item itemBeingCopied)
{
if (!itemBeingCopied.Axes.IsDescendantOf(OriginalRoot))
{
return null;
}
string relativePath = itemBeingCopied.Paths.FullPath.Substring(OriginalRoot.Paths.FullPath.Length);
string newItemPath = String.Concat(NewRoot.Paths.FullPath, relativePath);
return NewRoot.Database.GetItem(newItemPath, itemBeingCopied.Language, itemBeingCopied.Version);
}
/// <summary>
/// Updates the items Context fields to point to correct references.
/// </summary>
/// <param name="itemBeingCopied">The item being copied.</param>
private void UpdateItemFields(Item itemBeingCopied)
{
LayoutField layoutField = new LayoutField(itemBeingCopied.Fields[Sitecore.FieldIDs.LayoutField]);
if (layoutField.InnerField.HasValue && itemBeingCopied.Languages.Count() > 0)
{
Item newItem = FindCorrespondingItem(itemBeingCopied);
if (newItem == null)
{
Log.Warn(String.Format("Unable to find corresponding item for copied item {0} - root {1}.", itemBeingCopied.Paths.FullPath, OriginalRoot.Paths.FullPath), this);
return;
}
foreach (Language language in itemBeingCopied.Languages)
{
Item versionedItem = itemBeingCopied.Database.GetItem(itemBeingCopied.ID, language,
itemBeingCopied.Version);
if (versionedItem != null && versionedItem.Versions.Count > 0)
{
foreach (var itemVersion in versionedItem.Versions.GetVersions())
{
if (itemVersion != null)
{
// Loop all datasources, if sources is child tree FindCorrespondingItem and replace
layoutField = new LayoutField(itemVersion.Fields[Sitecore.FieldIDs.LayoutField]);
if (!layoutField.InnerField.HasValue)
{
continue;
}
var rawLayout = itemVersion.Fields[Sitecore.FieldIDs.LayoutField].Value;
if (string.IsNullOrWhiteSpace(layoutField.Value))
{
continue;
}
LayoutDefinition layout = LayoutDefinition.Parse(layoutField.Value);
for (int i = 0; i < layout.Devices.Count; i++)
{
DeviceDefinition device = layout.Devices[i] as DeviceDefinition;
for (int j = 0; j < device.Renderings.Count; j++)
{
RenderingDefinition rendering = device.Renderings[j] as RenderingDefinition;
if (!string.IsNullOrEmpty(rendering.Datasource))
{
Item datasourceItem = itemVersion.Database.GetItem(rendering.Datasource);
if (datasourceItem == null)
{
Log.Warn(string.Format("Could not find datasource item {0} while copying item {1}", rendering.Datasource, itemVersion.ID), this);
continue;
}
// Exit if datasource is not a descendend of the item being copied
if (!datasourceItem.Axes.IsDescendantOf(itemBeingCopied))
{
continue;
}
// Find new datasource if it is not under path of parent
Item correspondingItem = FindCorrespondingItem(datasourceItem);
if (correspondingItem == null)
{
Log.Warn(string.Format("Could not find datasource target item {0} while copying item {1}", rendering.Datasource, itemVersion.ID), this);
continue;
}
rawLayout = rawLayout.Replace(datasourceItem.ID.ToString(),
correspondingItem.ID.ToString());
}
}
}
// Replace Layout field on new item
newItem = itemVersion.Database.GetItem(newItem.ID, itemVersion.Language,
itemVersion.Version);
if (rawLayout != newItem.Fields[Sitecore.FieldIDs.LayoutField].Value)
{
// Save updated layout information
newItem.Editing.BeginEdit();
newItem.Fields[Sitecore.FieldIDs.LayoutField].Value = rawLayout;
newItem.Editing.EndEdit();
}
}
}
}
}
}
}
/// <summary>
/// Updates a tree in Sitecore (fixes all references in the tree).
/// </summary>
/// <param name="root">The root Item.</param>
private void UpdateTree(Item root)
{
UpdateItemFields(root);
foreach (Item child in root.GetChildren(ChildListOptions.None))
{
UpdateTree(child);
}
}
/// <summary>
/// Called when the item copied event runs. Will update the Context references contained in the copied tree structure.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="args">The <see cref="System.EventArgs"/> instance containing the event data.</param>
protected void OnItemCopied(object sender, EventArgs args)
{
Item itemThatWasCopied = Event.ExtractParameter(args, 0) as Item;
Item itemRootCreatedByCopy = Event.ExtractParameter(args, 1) as Item;
Error.AssertNotNull(itemThatWasCopied, "No sourceItem in parameters");
Error.AssertNotNull(itemRootCreatedByCopy, "No targetItem in parameters");
LayoutDataSourceReferenceUpdater updater = new LayoutDataSourceReferenceUpdater
{
NewRoot = itemRootCreatedByCopy,
OriginalRoot = itemThatWasCopied
};
ProgressBox.Execute(
Sitecore.Globalization.Translate.Text("Updating context references"),
Sitecore.Globalization.Translate.Text("Updating context references"),
"Applications/16x16/form_blue.png",
new ProgressBoxMethod(updater.UpdateReferences),
new object[]
{
Event.ExtractParameter(args, 0),
Event.ExtractParameter(args, 1)
});
}
#endregion Methods
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment