Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
namespace Helix.Skeleton.Foundation.EditorExtensions.Services
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Helix.Skeleton.Foundation.EditorExtensions.Consts.CopyPage;
using Helix.Skeleton.Foundation.EditorExtensions.Models.CopyPage;
using Sitecore;
using Sitecore.Configuration;
using Sitecore.Data;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using Sitecore.Globalization;
using Sitecore.Layouts;
using Sitecore.Rules.ConditionalRenderings;
public class CopyPageService : ICopyPageService
{
private const string ContentFolderName = "Content";
private const string GetItemsByNameAndTemplateQueryFormat = "{0}/*[@@name='{1}' and @@templateid='{2}']";
public Item GetContentFolder(string currentItemPath, string databaseName)
{
var foundContentItems = Factory
.GetDatabase(databaseName)
.SelectItems(string.Format(GetItemsByNameAndTemplateQueryFormat, currentItemPath.Replace("-", "#-#").Replace("$", "#$#"), ContentFolderName, TemplateIDs.Folder.ToString()));
if (foundContentItems.Length > 1)
{
return null;
}
return foundContentItems.FirstOrDefault();
}
public Item CopyLastVersion(Database database, Language language, Item source, Item destinationWithoutVersion)
{
var languageSpecificSource = database.GetItem(source.ID, language);
if (languageSpecificSource.Versions.Count == 0)
{
return null;
}
var languageSpecificDestination = database.GetItem(destinationWithoutVersion.ID, language);
languageSpecificDestination = languageSpecificDestination.Versions.AddVersion();
languageSpecificDestination.Editing.BeginEdit();
languageSpecificSource.Fields.ReadAll();
foreach (Field field in languageSpecificSource.Fields)
{
languageSpecificDestination.Fields[field.ID].SetValue(field.Value, true);
}
languageSpecificDestination.Editing.EndEdit();
languageSpecificDestination.Editing.AcceptChanges();
return languageSpecificDestination;
}
public void AdjustLayout(Database database, Item newItem, Item oldItem, ID layoutFieldId)
{
var allDevices = database.Resources.Devices.GetAll();
var newLayoutField = new LayoutField(newItem.Fields[layoutFieldId]);
var oldDatasources = new List<IOldDatasourceItem>();
foreach (var device in allDevices)
{
var renderingReferences = newLayoutField.GetReferences(device);
if (renderingReferences == null)
{
continue;
}
// Collect datasource references
oldDatasources.AddRange(this.GetOldReferences(database, renderingReferences.Where(r => r != null), r => r.Settings.DataSource));
// Collect personalization references
var conditionalRenderings = renderingReferences
.Where(r => r?.Settings?.Rules?.Rules != null)
.SelectMany(r => r.Settings.Rules.Rules
.SelectMany(rule => rule?.Actions
.Select(a => a as SetDataSourceAction<ConditionalRenderingsRuleContext>).Where(a => a != null)));
oldDatasources.AddRange(this.GetOldReferences(database, conditionalRenderings, c => c.DataSource));
}
var newLayoutDefinition = LayoutDefinition.Parse(newLayoutField.Value);
foreach (var device in newLayoutDefinition.Devices.Cast<DeviceDefinition>())
{
var renderings = device.Renderings.Cast<RenderingDefinition>();
// Set datasource referneces
this.SetNewReferences(
new SetNewReferencesParameters<RenderingDefinition>
{
Database = database,
NewItem = newItem,
OldItem = oldItem,
NewLayout = newLayoutField,
NewLayoutDefinition = newLayoutDefinition,
OldDatasources = oldDatasources,
SourceList = renderings.Where(r => r.Datasource != null),
GetIdValue = r => r.Datasource,
SetIdValue = (r, d) => r.Datasource = d
});
// Set personalization references
var actions = renderings
.Where(r => r?.Rules?.Descendants(RuleAttributeKeys.ActionKey) != null)
.SelectMany(r => r.Rules.Descendants(RuleAttributeKeys.ActionKey)
.Select(a => a.Attribute(RuleAttributeKeys.DatasourceKey))
.Where(a => a != null));
this.SetNewReferences(
new SetNewReferencesParameters<XAttribute>
{
Database = database,
NewItem = newItem,
OldItem = oldItem,
NewLayout = newLayoutField,
NewLayoutDefinition = newLayoutDefinition,
OldDatasources = oldDatasources,
SourceList = actions,
GetIdValue = r => r.Value,
SetIdValue = (r, d) => r.SetValue(d)
});
}
}
private IEnumerable<IOldDatasourceItem> GetOldReferences<T>(Database database, IEnumerable<T> sourceList, Func<T, string> getDatasourceId)
{
var oldDatasources = new List<IOldDatasourceItem>();
if (sourceList == null)
{
return oldDatasources;
}
foreach (var rendering in sourceList)
{
ID oldDatasourceId;
if (!ID.TryParse(getDatasourceId.Invoke(rendering), out oldDatasourceId))
{
continue;
}
var oldDatasource = database.GetItem(oldDatasourceId);
if (oldDatasource == null)
{
continue;
}
// Handle duplicated paths
var oldDatasourcesWithSamePath = database.SelectItems(oldDatasource.Paths.FullPath).ToList();
oldDatasources.Add(
new OldDatasourceItem
{
Id = oldDatasourceId,
Path = oldDatasource.Paths.FullPath,
Index = oldDatasourcesWithSamePath.IndexOf(oldDatasourcesWithSamePath.FirstOrDefault(d => d.ID == oldDatasourceId))
});
}
return oldDatasources;
}
private void SetNewReferences<T>(ISetNewReferencesParameters<T> parameters)
{
foreach (var rendering in parameters.SourceList)
{
var datasource = parameters.GetIdValue.Invoke(rendering);
var matchedOldDatasource = parameters.OldDatasources.FirstOrDefault(d => d.Id.ToString() == datasource);
if (matchedOldDatasource == null)
{
continue;
}
string newDatasourcePath = matchedOldDatasource.Path.ToString().Replace(parameters.OldItem.Paths.FullPath, parameters.NewItem.Paths.FullPath);
var newDatasource = parameters.Database.SelectItems(newDatasourcePath)[matchedOldDatasource.Index];
parameters.SetIdValue.Invoke(rendering, newDatasource.ID.ToString());
parameters.NewItem.Editing.BeginEdit();
parameters.NewLayout.Value = parameters.NewLayoutDefinition.ToXml();
parameters.NewItem.Editing.EndEdit();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment