Controlling glass fields from your own code.

I make no secret of Glass Mapper being my current ORM of choice on the Sitecore platform but recently (not for the first time) I came across the need to control the mapping process in a crazier manner than Glass allows out of the box.

Glass provides a good set of structures to allow you to extend its behaviour when it comes to the mapping process and I utilised this to hook in and provide a ‘Delegate’ fluent mapping. This mapping allows you to delegate the behaviour of the mapping process back to code you control using a simple mappingContext.Delegate(x => x.MyField).GetValue(y => GetMeTheField(y.Item)). This is similar to the mappingContext.Field() or mappingContext.SitecoreInfo() methods that Glass Mapper provides out of the box.

Delegating control to your code.

In order to delegate control to code outside of Glass Mapper, I have created a SetValue and GetValue method on the property builder that handles the delegate mapping

    using System;
    using System.Linq.Expressions;

    using Glass.Mapper.Sc;
    using Glass.Mapper.Sc.Configuration.Fluent;

    public class SitecoreDelegate : AbstractPropertyBuilder
    {
        public SitecoreDelegate(Expression<Func> ex)
            : base(ex)
        {
        }
        public SitecoreDelegate SetValue(Action mapAction)
        {
            this.Configuration.MapToCmsAction = mapAction;
            return this;
        }

        public SitecoreDelegate GetValue(Func mapFunction)
        {
            this.Configuration.MapToPropertyAction = mapFunction;
            return this;
        }
    }

The Delegate Mapper

In order for anything in Glass to be mapped successfully, you need to define a mapper object, this is done simply by inheriting from the AbstractDataMapper class or one of its derivatives. In this case we are inheriting to allow it handle the return from out delegated functionality.

    using Glass.Mapper;
    using Glass.Mapper.Configuration;
    using Glass.Mapper.Sc;

    using Sitecore.Exceptions;

    public class SitecoreDelegateMapper : AbstractDataMapper
    {
        public override void MapToCms(AbstractDataMappingContext mappingContext)
        {
            SitecoreDelegatePropertyConfiguration config = this.Configuration as SitecoreDelegatePropertyConfiguration;
            SitecoreDataMappingContext context = mappingContext as SitecoreDataMappingContext;
            if (config == null)
            {
                throw new InvalidTypeException("A delegate property configuration was expected");
            }

            if (context == null)
            {
                throw new InvalidTypeException("A sitecore data mapping context was expected");
            }

            if (config.MapToCmsAction == null)
            {
                return;
            }

            config.MapToCmsAction(context);
        }

        public override object MapToProperty(AbstractDataMappingContext mappingContext)
        {
            SitecoreDelegatePropertyConfiguration config = this.Configuration as SitecoreDelegatePropertyConfiguration;
            SitecoreDataMappingContext context = mappingContext as SitecoreDataMappingContext;
            if (config == null)
            {
                throw new InvalidTypeException("A delegate property configuration was expected");
            }

            if (context == null)
            {
                throw new InvalidTypeException("A sitecore data mapping context was expected");
            }

            return config.MapToPropertyAction == null
                ? null
                : config.MapToPropertyAction(context);
        }

        public override bool CanHandle(AbstractPropertyConfiguration configuration, Context context)
        {
            return configuration is SitecoreDelegatePropertyConfiguration;
        }
    }

The Delegate Property Configuration

In order to configure properties in Glass Mapper, a property configuration is required. This allows you to define properties etc governing how the implementation of that property takes place during the mapping process.

    using System;

    using Glass.Mapper;
    using Glass.Mapper.Configuration;

    public class DelegatePropertyConfiguration : AbstractPropertyConfiguration where T : AbstractDataMappingContext
    {
        public Action MapToCmsAction { get; set; }

        public Func MapToPropertyAction { get; set; }
    }

    using Glass.Mapper.Sc;

    public class SitecoreDelegatePropertyConfiguration : DelegatePropertyConfiguration
    {
    }

Making it work with Glass Fluent Configuration

In order for us to be able to get at the lovely new delegate functionality, we need to extend Glass Mapper’s default behaviour to include a new Delegate method.

    using System;
    using System.Linq.Expressions;

    using Glass.Mapper.Sc.Configuration.Fluent;

    public static class SitecoreTypeExtensions
    {
        public static SitecoreDelegate Delegate(this SitecoreType type, Expression<Func> ex)
        {
            SitecoreDelegate sitecoreDelegate = new SitecoreDelegate(ex);
            type.Config.AddProperty(sitecoreDelegate.Configuration);
            return sitecoreDelegate;
        }
    }

Fluent Configuration

mySitecoreType.Delegate(x => x.Field).GetValue(y => MyMethod() // get the value from elsewhere);
Advertisements

3 thoughts on “Controlling glass fields from your own code.

  1. Pingback: Glass Mapper – Introducing Glass Maps | CardinalCore

  2. Brilliant! Thanks a lot! For the sake of Glass beginners, you might want to add that SitecoreDelegateMapper needs to be registered in the container along with other/built-in Mappers. I don’t know if Glass has changed since you wrote this, but in current version (3.2.1.42) your code needs slight alterations to fit in. I’ve thrown up a Gist of the changes if anyone is interested. https://gist.github.com/bredstrup/1a7bed56a0360883fea3

    Thanks again, Nat, this is a really awesome addon to Glass Mapper!

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