Quantcast
Channel: Brian Pedersen's Sitecore and .NET Blog
Viewing all articles
Browse latest Browse all 285

Sitecore contact facets – Create your own facet

$
0
0

This article describes how to create a simple Sitecore facet consisting of a DateTime and a list of strings.

A contact is made up of facets. Here are all the facets Sitecore uses (you will find the facets in \App_Config\Include\Sitecore.Analytics.Model.Config):

<facets>
  <facet name="Personal" contract="Sitecore.Analytics.Model.Entities.IContactPersonalInfo, Sitecore.Analytics.Model" />
  <facet name="Addresses" contract="Sitecore.Analytics.Model.Entities.IContactAddresses, Sitecore.Analytics.Model" />
  <facet name="Emails" contract="Sitecore.Analytics.Model.Entities.IContactEmailAddresses, Sitecore.Analytics.Model" />
  <facet name="Phone Numbers" contract="Sitecore.Analytics.Model.Entities.IContactPhoneNumbers, Sitecore.Analytics.Model" />
  <facet name="Picture" contract="Sitecore.Analytics.Model.Entities.IContactPicture, Sitecore.Analytics.Model" />
  <facet name="Communication Profile" contract="Sitecore.Analytics.Model.Entities.IContactCommunicationProfile, Sitecore.Analytics.Model" />
  <facet name="Preferences" contract="Sitecore.Analytics.Model.Entities.IContactPreferences, Sitecore.Analytics.Model" />
</facets>

In this example I will add a facet that consists of a date and a list of strings. I will call it “AvailablePublishers“.

This is a real-life example where I needed to store a list of publishers that were available the last time the user was online. Each publisher is just an ID (a string) and I store these as a list on the Contact:

Available Publishers Facet

Available Publishers Facet

It sounds simple, and it is – but there is a lot of code involved. So hang on, lets code.

STEP 1: THE BASIC INTERFACES

The “AvailablePublishers” is a Facet, the list below consists of Elements. So I need to create a IFacet interface and a IElement interface.

Here is the IFacet:

using System;
using Sitecore.Analytics.Model.Framework;

namespace PT.AvailablePublishers
{
  public interface IAvailablePublishersFacet : IFacet
  {
    IElementCollection<IAvailablePublishersElement> AvailablePublishers { get; }
    DateTime Updated { get; set; }
  }
}

The IFacet contains a list (IElementCollection) of my IElement. Here is the IElement:

using Sitecore.Analytics.Model.Framework;

namespace PT.AvailablePublishers
{
  public interface IAvailablePublishersElement : IElement, IValidatable
  {
    string PublisherID { get; set; }
  }
}

STEP 2: THE IMPLEMENTATION

Now we need concrete classes implementing IAvailablePublishersFacet and IAvailablePublishersElement:

Here is the AvailablePublishersFacet class:

using System;
using Sitecore.Analytics.Model.Framework;

namespace PT.AvailablePublishers
{
  [Serializable]
  public class AvailablePublishersFacet : Facet, IAvailablePublishersFacet
  {
    public static readonly string _FACET_NAME = "AvailablePublishers";
    private const string _UPDATED_NAME = "LastUpdated";

    public AvailablePublishersFacet()
    {
      EnsureCollection<IAvailablePublishersElement>(_FACET_NAME);
    }

    public IElementCollection<IAvailablePublishersElement> AvailablePublishers
    {
      get
      {
        return GetCollection<IAvailablePublishersElement>(_FACET_NAME);
      }
    }


    public DateTime Updated
    {
      get
      {
        return GetAttribute<DateTime>(_UPDATED_NAME);
      }
      set
      {
        SetAttribute(_UPDATED_NAME, value);
      }
    }
  }
}

and the AvailablePublishersElement class:

using System;
using Sitecore.Analytics.Model.Framework;

namespace PT.AvailablePublishers
{
  [Serializable]
  public class AvailablePublishersElement : Element, IAvailablePublishersElement
  {
    private const string _PUBLISHERID = "PublisherID";

    public AvailablePublishersElement()
    {
      EnsureAttribute<string>(_PUBLISHERID);
    }
    
    public string PublisherID
    {
      get
      {
        return GetAttribute<string>(_PUBLISHERID);
      }
      set
      {
        SetAttribute(_PUBLISHERID, value);
      }
    }
  }
}

Both classes are serializable.

Getting and setting properties are done using GetAttribute and SetAttribute methods retrieved from Sitecore.Analytics.Model.Framework.Element and Sitecore.Analytics.Model.Framework.Facet.

Lists are done using IElementCollection or IElementDictionary, provided by Sitecore.

STEP 3: REGISTER FACET IN SITECORE CONFIGURATION

The facets and elements are registered in Sitecore. In the configuration you also register the  IAvailablePublishersFacet as an element, even when it inherits from IFacet.

This is a simplified version of the \App_Config\Include\Sitecore.Analytics.Model.config where I have removed all other elements but my own:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <model>
      <elements>
        <element interface="PT.AvailablePublishers.IAvailablePublishersElement, MyDLL" implementation="PT.AvailablePublishers.AvailablePublishersElement, MyDLL" />
        <element interface="PT.AvailablePublishers.IAvailablePublishersFacet, MyDLL" implementation="PT.AvailablePublishers.AvailablePublishersFacet, MyDLL" />
      </elements>
      <entities>
        <contact>
          <facets>
            <facet name="AvailablePublishers" contract="PT.AvailablePublishers.IAvailablePublishersFacet, MyDLL" />
          </facets>
        </contact>
      </entities>
    </model>
  </sitecore>
</configuration>

So as you can see, both my interfaces are defined in <elements/>. The <elements/> describes the implementation of the interface, just like IOC would do it.

The facet is defined in <facets/> with a unique name. This unique name is the name you use to find the facet when you need to access it.

STEP 4: CALL THE FACET

The facet is now defined. Next step is to use the facet. To retrieve a facet you need a Contact. The contact is usually retrieved from the Sitecore Tracker:

Contact contact = Tracker.Current.Session.Contact;

This is a repository than can get the list of available publishers from a contact, and update the list of available publishers:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using PT.AvailablePublishers;
using Sitecore.Analytics.Tracking;

namespace PT.Forum.Domain.NejTakPlus.Model.Repositories
{
  public class AvailablePublishersRepository
  {
    public IEnumerable<string> Get(Contact contact)
    {
      IAvailablePublishersFacet facet = contact.GetFacet<IAvailablePublishersFacet>(AvailablePublishersFacet._FACET_NAME);
      return facet.AvailablePublishers.Select(element => element.PublisherID);
    }

    public void Set(Contact contact, IEnumerable<string> availablePublisherKeys)
    {
      IAvailablePublishersFacet facet = contact.GetFacet<IAvailablePublishersFacet>(AvailablePublishersFacet._FACET_NAME);
      facet.Updated = DateTime.Now;
      while (facet.AvailablePublishers.Count > 0)
        facet.AvailablePublishers.Remove(0);
      foreach (string availablePublisherKey in availablePublisherKeys)
      {
        facet.AvailablePublishers.Create().PublisherID = availablePublisherKey;
      }
    }
  }
}

Notice the contact.GetFacet<>() method. Here you specify the name of the facet you defined in the <facets/> section of the config file. Luckily you also define the same name in the code, so I can get the facet name from my AvailablePublishersFacet class.

Also notice the Set() method. If you wish to clear the list before inserting, you need to iterate through the list and remove them one by one. There is no Clear() method.

Remember that facets are not written to MongoDB before your session ends. So you cannot see your fact in Mongo before your session is abandoned. You can try calling:

Session.Abandon();

To force Sitecore to write the data to MongoDB.

That’s it. Happy coding.

MORE TO READ:

 



Viewing all articles
Browse latest Browse all 285

Trending Articles