A while ago I presented my Sitecore model auto-generation concept to Sitecore’s UK User Group. One of the perspectives I mentioned in my presentation was using the technique to generate item paths. The idea was that this would eliminate a lot of the magic strings representing paths and IDs.
My initial thought was to generate a list of constants that could be used in conjunction with the item factory. Before I ever got started on this Jason from Lightmaker showed me a much more elegant way of representing the item tree by auto-generating nested static classes. This way you get very nice IntelliSence in Visual Studio when typing what is effectively the path to the desired item.
Example:
Here is my code for the ItemTree.tt (can be dropped into the auto-generation project available on Sitecore’s GitHub):
<#@ template hostspecific="true" debug="false" language="C#" #>
<#@ assembly name="%ProgramFiles%\Hedgehog Development\Team Development for Sitecore (VS2010)\HedgehogDevelopment.SitecoreCommon.Data.dll" #>
<#@ assembly name="%ProgramFiles%\Hedgehog Development\Team Development for Sitecore (VS2010)\HedgehogDevelopment.SitecoreCommon.Data.Parser.dll" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="HedgehogDevelopment.SitecoreCommon.Data" #>
<#@ import namespace="HedgehogDevelopment.SitecoreCommon.Data.Items" #>
<#@ import namespace="HedgehogDevelopment.SitecoreCommon.Data.Fields" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Text.RegularExpressions" #>
//
// This file is auto-generated - do not edit
//
using System;
using Sitecore.Data.Items;
using Herskind.Model.Helper;
using Herskind.Model.Helper.FieldTypes;
namespace Herskind
{
public static class ItemTree
{
private T InstantiateItemWrapper<T>(string id)
{
return ItemFactory.Instance.SelectSinglePath<T>(id);
}
<#
// CONFIGURE: Change this to the the path of your TDS project (relative to current project)
string tdsPath = "..\\Herskind.Tds";
SitecoreDataSource = new SerializedTreeDataSource(this.Host.ResolvePath(tdsPath));
PushIndent("\t");
GenerateClasses(SitecoreDataSource.Items, "");
PopIndent();
#>
}
}
<#+
public void GenerateClasses(IEnumerable<IItem> items, string parentName)
{
PushIndent("\t");
foreach (IItem item in items)
{
var template = SitecoreDataSource.Templates.FirstOrDefault(t => t.Properties["id"].ToLower() == item.Properties["template"].ToLower());
var templateInterfaceName =
template == null ? "global::" + BaseNameSpace + ".Helper.IItemWrapper" : "global::" + FullNamespace(template) + "." + InterfaceName(template.Name);
var className = ParentSafeClassName(parentName, item.Name);
#>
/// <summary>
/// Item path:
/// <#= item.Path #>
/// </summary>
public static class <#= className #>
{
public static <#= templateInterfaceName #> <#= InstancePropertyName(parentName, item, "Instance") #>
{
get { return InstantiateItemWrapper<<#= templateInterfaceName #>>("<#= item.ID.ToString() #>"); }
}
public static string <#= InstancePropertyName(parentName, item, "ItemID") #>
{
get { return "<#= item.ID.ToString() #>"; }
}
<#+
GenerateClasses(item.Children, className);
#>
}
<#+
}
PopIndent();
}
#>
<#+
public string BaseNameSpace = "Herskind.Model";
public SerializedTreeDataSource SitecoreDataSource = null;
public string InstancePropertyName(string parentName, IItem item, string name)
{
if (ParentSafeClassName(parentName, item.Name) != name)
{
return name;
}
return InstancePropertyName(parentName, item, name+"_");
}
public string ParentSafeClassName(string parentName, string name)
{
if (parentName!=ClassName(name))
{
return ClassName(name);
}
return ClassName(name)+"_";
}
public string ClassName(string name)
{
return TitleCase(name);
}
public string InterfaceName(string name)
{
return "I" + TitleCase(name);
}
public string TitleCase(string name)
{
name = Regex.Replace(name, "([a-z](?=[A-Z])|[A-Z](?=[A-Z][a-z]))", "$1 ");
name = CultureInfo.InvariantCulture.TextInfo.ToTitleCase(name);
name = Regex.Replace(name, @"[^a-zA-Z0-9]", String.Empty);
name = Regex.Replace(name, @"(^[0-9])", "_$1");
return name;
}
public string RelativeNamespace(TemplateItem template)
{
var sb = new StringBuilder();
var pathList = new List<string>(template.Path.Split('/'));
try
{
return string.Join(".", pathList.Take(pathList.Count - 1).Skip(3).Select(p => TitleCase(p)));
}
catch
{
}
return "";
}
public string FullNamespace(TemplateItem template)
{
return BaseNameSpace + "." + RelativeNamespace(template);
}
#>