Custom Sitecore Intel Transformers To Modify Date Format In Experience Profile

Going through the recently published Sitecore StackExchange site, I came across a question regarding modifying the date format of visits in Experience Profile since it shows the dd.mm.yyyy format by default. In case you don't know what I am talking about, here is what it looks like:



It's not just that one view, the default date format seems to apply to other views as well:



My obvious thought here was that there has to be a config setting somewhere that controls this date format. Here is my process of elimination:
  • Eliminated Experience Profile configs since it did not contain any date related settings
  • Looked at showconfig.aspx and found some index fields that contained date formats but eliminated since the default format was yyyy/mm/dd
  • Eliminated the Reporting Database since the data formats were different
  • Looked at the service calls made by Experience Explorer to fetch view data and found this:
     "InteractionStartDateTime":"2016-10-20T15:34:20.449"
    "FormattedInteractionStartDateTime":"20.10.2016 11:34:20 (23hr:31min)"


I was starting to see light at the end of the rabbit hole.
Digging further I found that Sitecore.Cintel.Client.dll is responsible for providing the data for the views, which took me back to Sitecore.ExperienceProfile.Client.config, specifically the following section:

<experienceProfile>
      
      <!-- Provides a hook to modify view results before they are displayed by Experience Profile appliction. -->
      <resultTransformManager>

        <!-- If http request header "X-SC-CintelTransformerClientName" matches clientName element, then the result transformer provider is applied.
             Header value has to be:  X-SC-CintelTransformerClientName: speakClient -->
        <resultTransformProvider clientName="speakClient" type="Sitecore.Cintel.Endpoint.Transfomers.ResultTransformProvider" singleInstance="true">

          <!-- If http request header "X-SC-CintelTransfomerKey" matches a viewName element, then the result transformer is applied.
               For example, header value could read as:  X-SC-CintelTransfomerKey: visits -->
          <intelResultTransformers>
            <add viewName="visits" type="Sitecore.Cintel.Client.Transformers.Contact.VisitResultTransformer, Sitecore.Cintel.Client"/>
            <add viewName="goals" type="Sitecore.Cintel.Client.Transformers.Contact.GoalResultTransformer, Sitecore.Cintel.Client"/>
            <add viewName="campaigns" type="Sitecore.Cintel.Client.Transformers.Contact.CampaignResultTransformer, Sitecore.Cintel.Client"/>
            <add viewName="events" type="Sitecore.Cintel.Client.Transformers.Contact.EventResultTransformer, Sitecore.Cintel.Client"/>
             <add viewName="latest-statistics" type="Sitecore.Cintel.Client.Transformers.Contact.OverviewResultTransformer, Sitecore.Cintel.Client"/> 		
            <add viewName="latest-events" type="Sitecore.Cintel.Client.Transformers.Contact.LatestEventResultTransformer, Sitecore.Cintel.Client"/>
            <add viewName="recent-campaigns" type="Sitecore.Cintel.Client.Transformers.Contact.RecentCampaignsResultTransformer, Sitecore.Cintel.Client"/>
            <add viewName="best-pattern-matches" type="Sitecore.Cintel.Client.Transformers.Contact.BestPatternMatchesResultTransformer, Sitecore.Cintel.Client"/>

            <add viewName="visit-summary" type="Sitecore.Cintel.Client.Transformers.Contact.VisitSummaryResultTransformer, Sitecore.Cintel.Client"/>
            <add viewName="visit-pages" type="Sitecore.Cintel.Client.Transformers.Contact.VisitPagesResultTransformer, Sitecore.Cintel.Client"/>

            <add viewName="visit-internal-searches" type="Sitecore.Cintel.Client.Transformers.Contact.VisitInternalSearchesResultTransformer, Sitecore.Cintel.Client"/>

            <add viewName="profile-info" type="Sitecore.Cintel.Client.Transformers.Contact.ProfilingProfilesResultTransformer, Sitecore.Cintel.Client"/>

            <add viewName="external-keyword-summary" type="Sitecore.Cintel.Client.Transformers.Contact.KeywordResultTransformer, Sitecore.Cintel.Client"/>
            <add viewName="internal-keyword-summary" type="Sitecore.Cintel.Client.Transformers.Contact.InternalKeywordSummaryResultTransformer, Sitecore.Cintel.Client"/>
            <add viewName="paid-keyword-summary" type="Sitecore.Cintel.Client.Transformers.Contact.KeywordResultTransformer, Sitecore.Cintel.Client"/>

            <add viewName="external-keyword-detail" type="Sitecore.Cintel.Client.Transformers.Contact.KeywordDetailResultTransformer, Sitecore.Cintel.Client"/>
            <add viewName="internal-keyword-detail" type="Sitecore.Cintel.Client.Transformers.Contact.KeywordDetailResultTransformer, Sitecore.Cintel.Client"/>
            <add viewName="paid-keyword-detail" type="Sitecore.Cintel.Client.Transformers.Contact.KeywordDetailResultTransformer, Sitecore.Cintel.Client"/>

            <add viewName="latest-visitors" type="Sitecore.Cintel.Client.Transformers.Contact.LatestVisitorsResultTransformer, Sitecore.Cintel.Client"/>

            <add viewName="journey" type="Sitecore.Cintel.Client.Transformers.Contact.JourneyResultTransformer, Sitecore.Cintel.Client"/>
            <add viewName="journey-detail-outcome" type="Sitecore.Cintel.Client.Transformers.Contact.JourneyOutcomeDetailResultTransformer, Sitecore.Cintel.Client"/>
            <add viewName="journey-detail-online-interaction" type="Sitecore.Cintel.Client.Transformers.Contact.JourneyOnlineInteractionDetailResultTransformer, Sitecore.Cintel.Client"/> 
            
            <add viewName="channel-interaction-distribution" type="Sitecore.Cintel.Client.Transformers.Contact.ChannelInteractionDistributionResultTransformer, Sitecore.Cintel.Client"/>
            <add viewName="channel-goal-distribution" type="Sitecore.Cintel.Client.Transformers.Contact.ChannelGoalDistributionResultTransformer, Sitecore.Cintel.Client"/>
            <add viewName="channel-summary" type="Sitecore.Cintel.Client.Transformers.Contact.ChannelSummaryResultTransformer, Sitecore.Cintel.Client"/>
            
            <add viewName="outcome-detail" type="Sitecore.Cintel.Client.Transformers.Contact.OutcomeDetailTransformer, Sitecore.Cintel.Client"/>
          
          </intelResultTransformers>

           <!-- If http request header "X-SC-CintelTransfomerKey" matches key element, then the result transformer is applied.
                Header value has to be:  X-SC-CintelTransfomerKey: default -->
          <contactSearchResultTransformer>
            <add key="default" type="Sitecore.Cintel.Client.Transformers.Contact.ContactSearchResultTransformer, Sitecore.Cintel.Client" />
          </contactSearchResultTransformer>

          <!-- If http request header "X-SC-CintelTransfomerKey" matches key element, then the result transformer is applied.
                Header value has to be:  X-SC-CintelTransfomerKey: default -->
          <contactDetailsTransformer>
            <add key="default" type="Sitecore.Cintel.Client.Transformers.Contact.ContactDetailsTransformer, Sitecore.Cintel.Client" />
          </contactDetailsTransformer>
		  
        </resultTransformProvider>
      </resultTransformManager>
    </experienceProfile>
So here is the Aha moment!
Good news - found what needs to be modified!
Bad news - can't believe Sitecore hardcoded the date formats!
SOLUTION:
  1. Add config setting for date format
  2. Write a custom TimeConverter
  3. Write a custom ClientFactory that provides the custom TimeConverter
  4. Write a custom Transformer that use the custom ClientFactory
NOTE: To fix the timeline view I wrote a custom JourneyOnlineInteractionDetailResultTransformer. Some Transformers actually format the date within the Transform() method itself in which case you can skip steps 1 thru 3, for e.g. OverviewResultTransformer.
Here is the code:
Step 1: Config setting for date format
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <settings>
      <!--  Date format for visit date in Experience Profile
      -->
      <setting name="ExprienceProfile.DateFormat" value="MM.dd.yyyy HH:mm:ss" />
    </settings>
  </sitecore>
</configuration>
Step 2 & 3: Custom TimeConverter and ClientFactory
using Sitecore.Cintel.Client;
using Sitecore.Cintel.Client.Transformers;

namespace Sc.Cintel.Client
{
    public class CustomClientFactory : ClientFactory
    {
        public new static CustomClientFactory Instance { get; set; } = new CustomClientFactory();

        public new ResultSetExtender GetResultSetExtender()
        {
            return new ResultSetExtender(this.GetResultSetHelper(), this.GetTimeConverter(), this.GetTextConverter());
        }
        public new TimeConverter GetTimeConverter()
        {
            return new CustomTimeConverter(this.GetRepository(), this.GetContextUtil());
        }
    }
}
Step 4: Custom Transformer
using Sitecore.Cintel.Client;
using Sitecore.Cintel.Client.Transformers;

namespace Sc.Cintel.Client
{
    public class CustomClientFactory : ClientFactory
    {
        public new static CustomClientFactory Instance { get; set; } = new CustomClientFactory();

        public new ResultSetExtender GetResultSetExtender()
        {
            return new ResultSetExtender(this.GetResultSetHelper(), this.GetTimeConverter(), this.GetTextConverter());
        }
        public new TimeConverter GetTimeConverter()
        {
            return new CustomTimeConverter(this.GetRepository(), this.GetContextUtil());
        }
    }
}
Finally, don't forget to replace the default transformer with your custom one in the config file.

<add viewName="journey-detail-online-interaction" type="Sc.Cintel.Client.Transformers.Contact.CustomJourneyOnlineInteractionDetailTransformer, Sc.Cintel.Client"/>

As always, there is more than one solution to a problem. This was the one I could think of. So, please feel free to leave a comment or suggestion for better approaches.


Comments

Post a Comment

Popular posts from this blog

Is Rendered Item Valid XHtml Document Could not find schema information warnings during publish item Sitecore 7.2

Sitecore Tabbed Select Rendering dialog

RESOLVED: Solr Exceptions - Document contains at least one immense term in field