27 January 2015

Get related content by profile keys

So this posts is following directly the previous post.

With this 2nd posts I wanted to illustrate how you could use profile card to retrieve related content. During the Sitecore DMS fundamentals training session, we had a chat about Profile card, Profile keys and how we are assigning those to a content item. The example given there was for a Cycling Shop. We could create some profile keys for "Beginner", "Amateur" and "Professional". Obviously, you will have different product that will be for Professional: Helmets, Bikes and even GoPro (why not...). On previous project, we had similar cases where you then wanted to display related content so when a visitor is viewing a bike he will be display with an helmet and other item that will be tagged with the same category: "Professional". Well we usually create a tree list ex field and let the content author tag the content with the category. Even if I think this is great, I was wondering if we could use DMS and profile for that purpose as we are kind of tagging the content item with a card or a key... So here we go.

Before starting, I just wanted to point you to a few blogs and posts which helped me a lot:
So on the previous post we saw that the Tracking and profile cards information where stored on the item: field = __tracking. Awesome, that means we can index those data and so later on we will be able to retrieve it based on a content profile key...

1- Let's start with indexing content including _tracking

As per the posts listed above, the easiest way to index those data will be to use a computed field. In your search configuration file, you will need to add the following into your configuration section:

       
        
        < fields hint="raw:AddComputedIndexField">
          < field fieldName="dmstracking" returnType="stringCollection">MyProject.Business.Sitecore.Indexing.DmsComputedField,MyProject.Business< /field>
        < /fields>


Now in your solution you want to create the matching class MyProject.Business.Sitecore.Indexing.DmsComputedField

This class should implement the interface: Sitecore.ContentSearch.ComputedFields.IComputedIndexField

You will create something simple such as :

using Sitecore.Analytics.Configuration;
using Sitecore.Analytics.Data;
using Sitecore.ContentSearch;
using Sitecore.ContentSearch.ComputedFields;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using System.Collections.Generic;
using System.Linq;

namespace MyProject.Business.Sitecore.Indexing
{
    public class DmsComputedField : IComputedIndexField
    {
        public string FieldName
        {
            get;
            set;
        }
 
        public string ReturnType
        {
            get;
            set;
        }

        public DmsComputedField()
        {
        }
 
        public object ComputeFieldValue(IIndexable indexable)
        {
            Item item = indexable as SitecoreIndexableItem;
            List profileKeysNames = DmsHelper.GetProfileKeyNames(item,1).ToList();
            return profileKeysNames;
        }
    }
}


Now depending on what you want to index: Profile card Name or Profile Keys, you will need to fill in with your business logic. In this example we will index the list of Profile Keys name. Also note that on the configuration above, we are returning a stringCollection... Using the helpers we have created on the previous post we can retrieve the profile card names doing the following

            List< string> profileKeysNames = DmsHelper.GetProfileKeyNames(item,1).ToList();

Now our search index is configured, we can run the indexer and inspect the index using Luke:


2- Lets start retrieving the related item based on Keys

When the visitor visit a page, which has a profile (profile keys) associated to it, we can get those information through the helper we had on the previous post. from the list of keys for this item, we will be able to run a search against the dmstracking field..

            List< string> profileKeysNames = DmsHelper.GetProfileKeyNames(item,1).ToList();

So we can create a new controller rendering to execute our search


namespace MyProject.Controllers
{
    public class SearchController : SitecoreController
    {
        private readonly ISitecoreContext SitecoreContext;

        public SearchController(ISitecoreContext sitecoreContext)
        {
            this.SitecoreContext = sitecoreContext;
        }

        /// < summary>
        /// This controller action is used to get the related items
        /// < /summary>
        /// < returns>< /returns>
        [System.Web.Mvc.HttpGet]
        public ViewResult GetRelatedItems()
        {
            var searchResultModel = new SearchResult();

            // get the profile cards tagged on the content
            Item item = SitecoreContext.GetCurrentItem< item>();
            List< string> profileKeysNames = DmsHelper.GetProfileKeyNames(item, 1).ToList();

            // get the number of results per page - get only the top 5
            int nbItemPerPage = 5;
            searchResultModel.ResultsPerPage = nbItemPerPage;

            ISearchIndex contentIndex = ContentSearchManager.GetIndex("MyProject_contentsearch_web");
            using (IProviderSearchContext searchContext = contentIndex.CreateSearchContext())
            {
                var listResults =
                    searchContext.GetQueryable< basesearchitem>().Where(p =>
                        profileKeysNames.Contains(p.DmsTracking)
                                ).AsEnumerable().Distinct(new ItemComparer()).ToList();

                searchResultModel.TotalNbResults = listResults.Count();
                searchResultModel.Pages = (int)Math.Ceiling((Decimal)listResults.Count / nbItemPerPage);
                searchResultModel.Results = listResults.Take(nbItemPerPage).ToList();
            }

            return View(@"~/Resources/MyProject/Views/Renderings/Search/SearchResults.cshtml", searchResultModel);
        }
    }
}

There we go, yo can now retrieve all related items which have the same associated Profile Keys...

Also this code was just put together quickly to show some example and surely can be improved but it was just to give a quick start...

No comments:

Post a Comment