mikaelnet
mikaelnet

Reputation: 704

Custom Data Source on Rendering Items

I'm having a Sitecore 8 MVC solution, and I have to extend the behavior of Data Source. It's pretty similar to what other people have done with queryable datasources before (such as http://www.cognifide.com/blogs/sitecore/reduce-multisite-chaos-with-sitecore-queries/ etc), but I've hooked into the <mvc.getXmlBasedLayoutDefinition> pipeline instead. It works fine and my custom data sources are resolved as they are entered in the layouts field on an item or on standard values.

But, when the custom data source is specified as a default data source on a rendering item, things becomes a bit trickier. I could solve it through the same pipeline, but that solution didn't look very nice. It means I'd have to load each rendering that hasn't a data source specified in the layout, and do the processing and resolve it from there. There must be a more natural way of doing this.

Does anyone know where to put such implementation logic for the default data source? (The <resolveRenderingDatasource> pipeline looked promising, but didn't execute in this scenario)

Upvotes: 4

Views: 1517

Answers (1)

Marek Musielak
Marek Musielak

Reputation: 27132

From what I understand, you may want to extend XmlBasedRenderingParser class. Here are the steps that should do the trick:

  1. Create a new file App_Config\include\Sitecore.Mvc.Custom.config:
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>
      <initialize>
        <processor
          patch:after="processor[@type='Sitecore.Mvc.Pipelines.Loader.InitializeRoutes, Sitecore.Mvc']"
          type="My.Assembly.Namespace.RegisterCustomXmlBasedRenderingParser, My.Assembly"/>
      </initialize>
    </pipelines>
  </sitecore>
</configuration>
  1. Create CustomXmlBasedRenderingParser class:
using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Mvc.Extensions;
using Sitecore.Mvc.Presentation;

namespace My.Assembly.Namespace
{
    public class CustomXmlBasedRenderingParser : XmlBasedRenderingParser
    {
        protected override void AddRenderingItemProperties(Rendering rendering)
        {
            RenderingItem renderingItem = rendering.RenderingItem;
            if (renderingItem != null && !rendering.DataSource.ContainsText())
            {
                rendering.DataSource = ResolveRenderingItemDataSource(renderingItem);
            }
            base.AddRenderingItemProperties(rendering);
        }

        private static string ResolveRenderingItemDataSource(RenderingItem renderingItem)
        {
            string dataSource = string.Empty;
            if (renderingItem.DataSource != null && renderingItem.DataSource.StartsWith("query:"))
            {
                string query = renderingItem.DataSource.Substring("query:".Length);
                Item contextItem = Context.Item;
                Item queryItem = contextItem.Axes.SelectSingleItem(query);
                if (queryItem != null)
                {
                    dataSource = queryItem.Paths.FullPath;
                }
            }
            return dataSource;
        }
    }
}
  1. Create RegisterCustomXmlBasedRenderingParser class:
using Sitecore.Mvc.Configuration;
using Sitecore.Mvc.Presentation;
using Sitecore.Pipelines;

namespace My.Assembly.Namespace
{
    public class RegisterCustomXmlBasedRenderingParser
    {
        public virtual void Process(PipelineArgs args)
        {
            MvcSettings.RegisterObject<XmlBasedRenderingParser>(() => new CustomXmlBasedRenderingParser());
        }
    }
}

What is more, if you want your code to be executed for DataSource defined on both Rendering and Presentation Details, you should be able to use the code below:

using System.Xml.Linq;
using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Mvc.Presentation;

namespace My.Assembly.Namespace
{
    public class CustomXmlBasedRenderingParser : XmlBasedRenderingParser
    {
        public override Rendering Parse(XElement node, bool parseChildNodes)
        {
            Rendering rendering = base.Parse(node, parseChildNodes);
            ResolveRenderingItemDataSource(rendering);
            return rendering;
        }

        private static void ResolveRenderingItemDataSource(Rendering rendering)
        {
            if (rendering.DataSource != null && rendering.DataSource.StartsWith("query:"))
            {
                string query = rendering.DataSource.Substring("query:".Length);
                Item contextItem = Context.Item;
                Item queryItem = contextItem.Axes.SelectSingleItem(query);
                if (queryItem != null)
                {
                    rendering.DataSource = queryItem.Paths.FullPath;
                }
            }
        }
    }
}

Please remember that this code is not tested properly and may not work out of the box in your environment. Anyway I hope it will give you at least a good indication where to start.

Upvotes: 2

Related Questions