Customize Glass.Mapper T4 Templates for Sitecore TDS CodeGen

If you are using glass.mapper with TDS and say Sitecore MVC, and have in the past created your models manually, you know that glass codegen is a godsend!

Glass basically provides us with t4 template files and dlls, based on the items included in the TDS project, the code is generated using the t4 templates.

We have used TDS with glass for 3-4 projects now and there were a few customizations that we have had to do in the t4 template files to tailor the code gen files to our needs.

Know your t4 template files:
While enabling glass.mapper to auto generate code for your tds items (models and item properties), you will provide 2 templates

  • Transform File (glassv3header.tt) – for the common header and will appear only once in your generated code file – this includes the namespace using statements / base interface / class for all models.
  • Base Project Transform File (glassv3item.tt) – The other template file will be used in a repetitive manner for every item that code (class / model) is generated for.

2015-09-19_172200

In addition to this, we also use the Code Generation Template (itempaths.tt) file to generate item properties for any items we would want. The properties generated per item, is again decided by the template file itself, but out of the box, contains properties such as the item id, item path, template name and template id.

2015-09-19_172313

Add TemplateId to all codegen classes

One thing we noticed right off the bat, was the lack of a property for the template id in the models! We needed this for many situations, like deciding a separate html rendering based on the template id of the item etc. So we updated the t4 template (glassv3header.tt) to include the template id for every model, including the appropriate sitecore attributes on them to get them to populate as expected. (line below)

Item Name vs a Name field

The header template for the common code for your code gen file, has a property mapped to the item name ‘Name’. We came across a situation where we were working with Sitecore Commerce Connect templates, and the main product template there had a Name field. When we tried generating code for that template, we ran into conflicts! We couldn’t change the name of the field in the Commerce Connect template, so had to update the t4 template (glassv3header.tt) instead to change the ‘Name’ property to ‘ItemName’ (line below)

Error with codegen for System Language template

When we tried adding the sitecore system template ‘/sitecore/templates/System/Language’ into TDS and generating code for it, but we again ran into conflicts here! This is why we again updated the t4 template (glassv3header.tt) to explicitly specify the namespace of the Language property. (line below)

<#@ template language="C#"  #>
<#@ assembly name="System.Core" #>

<#@ include file="Helpers.tt" #>
<#@ include file="StringExtensions.tt" #>
<#@ include file="GeneralExtensions.tt" #>
<#@ include file="Inflector.tt" #>

<#@ import namespace="System" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="HedgehogDevelopment.SitecoreProject.VSIP.CodeGeneration.Models" #>

<#@ parameter name="Model" type="HedgehogDevelopment.SitecoreProject.VSIP.CodeGeneration.Models.ProjectHeader" #>
<#@ parameter name="DefaultNamespace" type="System.String" #>

#pragma warning disable 1591
#pragma warning disable 0108
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by Team Development for Sitecore.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

using System;   
using System.Collections.Generic;   
using System.Linq;
using System.Text;
using Glass.Mapper.Sc.Configuration.Attributes;
using Glass.Mapper.Sc.Configuration;
using Glass.Mapper.Sc.Fields;
using Sitecore.Globalization;
using Sitecore.Data;
using SystemSpecialized = System.Collections.Specialized;


<#
// Calculate the top leve namespace as configured in the target project and
// base namespace as defined in the TDS project
string fullNamespace = JoinNamespaces(DefaultNamespace, Model.BaseNamespace);
#>

namespace <#=fullNamespace #>
{

	public partial interface IGlassBase{
		
		[SitecoreId]
		Guid Id{ get; }

		[SitecoreInfo(SitecoreInfoType.Name)]
		string ItemName { get; }

		[SitecoreInfo(SitecoreInfoType.Language)]
		Sitecore.Globalization.Language Language{ get; }

        [SitecoreInfo(SitecoreInfoType.Version)]
        int Version { get; }

		[SitecoreInfo(SitecoreInfoType.Url)]
		string Url { get; }
	}

	public abstract partial class GlassBase : IGlassBase{
		
		[SitecoreId]
		public virtual Guid Id{ get; private set;}

		[SitecoreInfo(SitecoreInfoType.Name)]
        public string ItemName { get; private set; }

		[SitecoreInfo(SitecoreInfoType.Language)]
		public virtual Sitecore.Globalization.Language Language{ get; private set; }

        [SitecoreInfo(SitecoreInfoType.Version)]
        public virtual int Version { get; private set; }

		[SitecoreInfo(SitecoreInfoType.Url)]
        public virtual string Url { get; private set; }
	}
}

Add a new sitecore field type to enable codegen create the right custom field property types

For various reasons, we have had to add custom fields in Sitecore. For these new fields, by default glassmapper will general Object properties unless we provide a hint to the type of data this new custom field will contain.
For example, the Single Select with SearchSingle Select Tree fields are link fields and contain a single guid, while Multisite Multilist with Search is a list field and contains a list of guids. So we need to map the intended property type in the GetGlassFieldType() method of glassv3item.tt template file:

public static string GetGlassFieldType(SitecoreField field)
{
	if (field != null && field.Type != null)
    {
		// Pull out any 'type' param from the custom data field on the field in TDS
		string customType = GetCustomProperty(field.Data, "type");
		string generic = GetCustomProperty(field.Data, "generic");
		
		if (customType != "")
		{
			if (generic != "")
			{
				return string.Format("{0}<{1}>", customType, generic);
			}
			else
			{
				return customType;
			}
		}

		switch(field.Type.ToLower())
		{
			case "tristate":
				return "TriState";
			case "checkbox":
				return "bool";

			case "date":
			case "datetime":
				return "DateTime";

			case "number":
				return "float";

			case "integer":
				return "int";

			case "treelist with search":
			case "treelist":
			case "treelistex":
			case "treelist descriptive":
			case "checklist":
			case "multilist with search":
			case "multisite multilist with search":
			case "multilist":
	            return string.Format("IEnumerable<{0}>", string.IsNullOrEmpty(generic) ? "Guid" : generic);

			case "grouped droplink":
			case "droplink":
			case "lookup":
			case "droptree":
			case "reference":
			case "tree":
			case "single select with search":
			case "multisite single select with search":
				return "Guid";

			case "file":
				return "File";

			case "image":
				return "Image";

			case "general link":
			case "general link with search":
				return "Link";
			
			case "password":
			case "icon":
			case "rich text":
			case "html":
			case "single-line text":
			case "multi-line text":
			case "frame":
			case "text":
			case "memo":
			case "droplist":
			case "grouped droplist":
			case "valuelookup":
				return "string";
			case "attachment":
			case "word document":
				return "System.IO.Stream";	   
			case "name lookup value list":
			case "name value list":
				return "SystemSpecialized.NameValueCollection";                                                                                                                         
			default:
				return "object /* UNKNOWN */";
		}
	}
	else 
	{
	   throw new Exception("There is no 'Type' field on the " + field.Name + " field.");
	}
}
Advertisements

, , , , , ,

  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: