Archive

Archive for August, 2009

Team Development with Sitecore the Easy way

August 28, 2009 8 comments

Most of the Sitecore implementations I’m involved in have me working in a team environment. In fact, this is pretty normal for any IT project. Although a team environment has many benefits, there are also some complexities that need to be addressed in terms of keeping the development environment in sync.

There are two things that need to be synchronised across all the development environments; code and data. The code synchronisation issue has been dealt with long ago by using source control. I wish I could say at this point that I haven’t encountered a team not using source control for a long time, but alas I cannot. Realistically I cannot believe that any professional developer would not use source control these days. This is the number one tool required for easier team development for any project.

I also use source control for 1 person projects. Along with synchronisation, source control provides other benefits such as versioning of the code so you can roll back changes, and providing a central location for all code. New dev comes onto the project? Just get the source from here. Old project needs maintenance? Just get the source from here. Original developer left the company? Just get the source from here.

The other part to the synchronisation issue is the data. I’m a strong believer of putting all database related things in source control. Your development database on a SQL server is just an instance of the structure and data you define in script files. Do not treat the database server as the place where your database lives. It should live as scripts in source control. The database on the database server is just a single instance of that database.

Another benefit of storing your schema and data in source control is the ability for accessing the data without a direct connection to the database server. For example, when working from home or a remote location away from the office. If the database scripts are kept in source control it’s straight forward to get the latest versions of the files and create a local copy to work against.

Although I want my data to live in source control as scripts I also am a strong believer of not accessing proprietry databases directly if an API exists. This is the case for Sitecore. Not to mention the complexity of the data stored in Sitecore.

So when working with Sitecore, how do you get your data to live in source control rather than the database? A common practice for Sitecore projects is to create Sitecore packages of the project specific data. This package can then be put in source control. This can also be seen as common practice through many of the shared source projects for Sitecore. Problem here is the package is a zip file, not text so your source control will not try and merge the package if multiple developers have updated multiple items and updated the package independent of each other.

Sitecore 6 introduced item serialization. This allows you to export item data in a text format at the click of a button to disk. And also to import it at the click of a button. This is a much better approach than the package approach. The only drawback to Sitecore 6 item serialization is that media library items cannot be exported in this way, so you’ll still have to drop back to a package for these.

So now we have the data on disk, we can include it in source control. Well… it depends on your project structure how easy this will be. The item data is placed on disk under the data/serialization folder. I don’t like to write my Sitecore code in the same folder that Sitecore runs. I like to separate my custom code from the system I’m building on top of, so in source control I don’t have the Sitecore root at the same location as my dev root. This makes including the serialized items more difficult.

Now let me step down off my soapbox and confess that although I want my Sitecore items in source control, generally I don’t do this due to the reasons listed above. At Next Digital we normally have a shared development database with each developer running their own instance of Sitecore. This normally works quite well due to the fact that this environment is development and each instance of Sitecore (on the dev’s machine) is restarted due to code changes quite often. This restarting means there are minimal issues with caching of the data.

OK, so now for the easy way. I was privileged enough to be included in the beta program for a new team development tool for Sitecore. I would like to introduce you to “Team Development for Sitecore” (or TDS for short). TDS is developed by Sitecore partner Hedgehog Development in North America. It is a plugin for Visual Studio which allows you to serialize and deserialize Sitecore items for your project directly from within Visual Studio. The items can also be added to source control as the items exist in a custom TDS project as text files. Being text files most source control system should have no problem merging changes.

tds item

You’ll notice from the above screenshot that the text format of an item in your TDS project is the Sitecore 6 item serialization format.

TDS also allows synchronising the items in your project with your Sitecore server. You can also select which items to sync and which ones to leave alone.

tds select items

In general you’ll only want to sync project specific items and leave the Sitecore standard items alone.

tds items in project

There are multiple synchronisation options to determine how TDS should handle such cases as when an item exists in the project but not in Sitecore and when an item exists in Sitecore but not in the project.

Another nice feature of TDS is the item designed. Hedgehog built on the concept of the Visual Studio Class designer to provide a similar tool for viewing the relationship between your templates. This is a huge help, especially as Sitecore supports multiple inheritance through templates which can lead to lengthy investigations when trying to work out which template defines which field on an item.

tds item designer

I find it very useful when designing a solution to design and rework the templates in a UML diagram. The item designer at least gives you the view part of this.

Overall I think TDS is a very good start. There’s heaps of potential there, like making the item designer allow updating of templates and relationships. I’m quite eager to see what Hedgehog do next with TDS. Even so, just having the ability to synchronise Sitecore items across multiple locations is worth the price tag.

Composite Presentation Inheritance

August 11, 2009 3 comments

I have often wanted a way in Sitecore to be able to define most of my pages presentation in a base template but customise that presentation on more specific items.

Sitecore has a facility to inherit default values through the use of data template standard values. This mechanism works for all fields including presentation (__renderings field). Sitecore 6 introduced inheritance through standard values meaning that if a base template defines a particular standard value and the standard value in a derived template is null, the derived template will inherit the standard value for that field from it’s base template.

This is really cool and makes maintenance a lot easier. Rather than having to set the default value per template, I can set the value on a base template and let inheritance through the standard values take care of the rest. For example, let’s say I have a “show on sitemap” checkbox for all page type items. I have a base template called page base and derived templates called article and news. I’ll set the default value for “show on sitemap” to true on the page base template’s standard values. Because I don’t set this on the article or news templates they inherit through their standard values the standard value of the parent template’s field.

This mechanism is also very handy when it comes to defining presentation for your templates. You can define the basic presentation on a base template and then when you come to define the presentation on derived templates you already have a starting point as this initial presentation is inherited from the base template. The problem is, as soon as you adjust the presentation on a derived template you are then overridding the standard values of the base template so changes to this base template will not flow through to the derived templates.

Towards the end of last year I proposed a solution to this problem. But a recent post by Thomas Eldblom gave me an idea of how I might be able to solve this problem. Thomas described to us his “composite renderings” in which he defines a new presentation type which allows him to place a group of controls in presentation as a set. He then updated the renderLayout pipeline to expand the composite renderings when a request was made and the presentation for an item was being built. I could use a similar approach to realise my “Composite Presentation Inheritance”.

Instead of expanding out groups of controls I’ll instead need to pull in presentation from a parent template’s standard values and aggregate them with that of the current item. To specify that composite presentation inheritance is being used, similar to Thomas’ approach I’ll define a special layout to be used on the item.

Let’s start by defining this special layout called “Inherit”.

inherit-layout

It doesn’t matter what is in the ASPX file this layout refers to as it will never be used.

Next we need to ensure the correct layout is used when an item which uses the inherit layout is requested. The best place to do this would be immediately after Sitecore has resolved which layout is being used, and swap out inherit for the layout we need.

The layout is resolved during the httpRequestBegin pipeline by the LayoutResolver processor. So we’ll need to create an HttpRequest processor which we can insert into the pipeline immediately after the layout resolver has run.

The following class shows an implementation for our inheritance layout resolver.

using System;
using System;
using Sitecore;
using Sitecore.Diagnostics;
using Sitecore.Data.Items;
using Sitecore.Pipelines.HttpRequest;

namespace Composite_Presentation_Inheritance
{
  public class InheritLayoutResolver : LayoutResolver
  {
    public override void Process(HttpRequestArgs args)
    {
      if (Context.Item != null)
        ProcessItem(Context.Item, true);
    }

    protected void ProcessItem(Item item, bool contentItem)
    {
      if (item.Visualization.Layout.Name.ToLower() == "inherit")
      {
        var baseTemplates = item.Template.BaseTemplates;
        for (int i = 0; i < baseTemplates.Length; i++)
        {
          if (baseTemplates[i].StandardValues != null)
            ProcessItem(baseTemplates[i].StandardValues, false);
        }
      }
      else if(!contentItem)
      {
        Context.Page.FilePath = item.Visualization.Layout.FilePath;
        Tracer.Info("Swapped inherit layout to " + Context.Page.FilePath);
      }
    }
  }
}

Note above how I recursively call the process item method with the item’s base templates standard values. I use a recursive method to make sure we could support any number of inheritance levels through layout. If the layout of the current item (whether that be the item itself or a set of standard values) uses the inherit layout, continue the recursion path, otherwise bail out. We also need to do checks to ensure we only process if we’re requesting content. This same resolver will run for any requests made for the Sitecore interfaces themselves, so this check makes sure we don’t upset normal Sitecore behavior.

That’s the layout done, now we need to aggregate the presentation controls. The presentation for the page being requested in build in the renderLayout pipeline by the InsertRenderings processor. We need to create a renderLayout pipeline processor which will recursively aggregate our presentation through each set of standard values in the template hierarchy of the current item, but only while the layout of the standard values is our special inherit layout. The following class shows an implementation for this.

using System;
using Sitecore.Pipelines.RenderLayout;
using Sitecore;
using Sitecore.Data.Items;

namespace Composite_Presentation_Inheritance
{
  public class PresentationAggregator : RenderLayoutProcessor
  {
    public override void Process(RenderLayoutArgs args)
    {
      if(Context.Item != null)
        process item(Context.Item, false);
    }

    protected void process item(Item item, bool addRenderings)
    {
      if (item.Visualization.Layout.Name.ToLower() == "inherit")
      {
        var baseTemplates = item.Template.BaseTemplates;
        for (int i = 0; i < baseTemplates.Length; i++)
        {
          if(baseTemplates[i].StandardValues != null)
            process item(baseTemplates[i].StandardValues, true);
        }
      }

      if (addRenderings)
      {
        var renderings = 
          item.Visualization.GetRenderings(Context.Device, true);
        for (int i = 0; i < renderings.Length; i++)
        {
          Context.Page.AddRendering(renderings[i]);
} } } } }

Note how we do the recursive call before we add the renderings. This will have the effect of adding the standard values renderings from the very base template down through the hierarchy to our more specific templates. I also have a condition to check if the renderings should be added as we want to leave the adding of the item’s renderings to the default processor. The default processor also takes care of adding in other controls to support the Sitecore interfaces.

Now all that’s left is to configure our installation to use these new components. Jump into your web.config and find the httpRequestBegin pipeline and the LayoutResolver processor in that pipeline. We want to insert our composite presentation inheritance layout resolver immediately after it in the pipeline to allow us to swap the layout if the inherit layout is used.

<processor 
  type="Composite_Presentation_Inheritance.InheritLayoutResolver, 
  Composite Presentation Inheritance" />

Next we need to add our presentation aggregator into the renderLayout pipeline just before the InsertRenderings processor.

<processor 
  type="Composite_Presentation_Inheritance.PresentationAggregator, 
  Composite Presentation Inheritance" />

Our processor is inserted before the default processor to ensure our inherited renderings are placed into the layout before the item specific renderings.

And that’s it. We now have an implementation of a composite presentation inheritance. I can now define presentation on a base template and make it more specific by adding specific renderings for derived templates.

I’ll illustrate this by adding a new “specific page” template to good old Nicam which will inherit from simple page. The purpose of this new template is to provide a “related pages” field and rendering. All I need for the presentation for this new template is to add a new related pages rendering after the main content area. Let’s review the simple page presentation.

simple page presso

I want my related links rendering to be inserted after the SimpleText rendering above which is bound into the /phcontent/phcenter placeholder. So in my “specific page” presentation I need to use the inherit layout so we inherit the base templates presentation and then add in the related links rendering.

specific page pres

And now, requesting an item based on the “specific page” template I get the presentation combined.

specific page

One consideration if you use this technique in production is to keep in mind that the rendering now takes more time as it’s doing more. A potential performance tweak to address this concern would be to supplement the pipeline processors with an event handler that would aggregate the presentation on composite presentation inheritance layouts and store the resulting presentation into the item itself inside the publishing target databases when a publish operation finished. You still need the pipeline processors to allow content authors to preview their content appropriately and the publish:end event handler to enhance performance when using this technique.

Categories: Sitecore
Follow

Get every new post delivered to your Inbox.