-
-
Save Ninodeluxe/5d1507a35b8f796ddbbb3535d7f57475 to your computer and use it in GitHub Desktop.
Use an attribute to create facets for an EPiServer Find query and extract facets from the search results
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Enum MyFacetCategory | |
/// </summary> | |
public enum MyFacetCategory | |
{ | |
CategoryOne = 1, | |
CategoryTwo = 2, | |
CategoryThree = 3, | |
CategoryFour = 4, | |
CategoryFive = 5 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Facet((int)MyFacetCategory.CategoryOne, FacetType.TermsFacetFor)] | |
public virtual string TermsFacetExample { get; set; } | |
[Facet((int)MyFacetCategory.CategoryTwo, 20)] | |
public virtual string TermsFacetExampleTwo { get; set; } | |
IClient searchManager = Client.CreateFromConfig(); | |
ITypeSearch<StandardPage> queryTest = searchManager.Search<StandardPage>().For("test"); | |
queryTest = queryTest.AddFacets(); | |
IContentResult<StandardPage> results = queryTest.GetContentResult(); | |
Dictionary<int, TermsFacet> facetResults = results.GetFacets(); | |
IEnumerable<string> categoryOneTerms = facetResults.ExtractFacetTermsFor((int)MyFacetCategory.CategoryOne); | |
IEnumerable<string> categoryTwoTerms = facetResults.ExtractFacetTermsFor((int)MyFacetCategory.CategoryTwo); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Class FacetAttribute. This class cannot be inherited. | |
/// </summary> | |
[AttributeUsage(AttributeTargets.Property)] | |
public sealed class FacetAttribute : Attribute | |
{ | |
/// <summary> | |
/// Initializes a new instance of the <see cref="FacetAttribute"/> class. | |
/// </summary> | |
/// <param name="index">The index.</param> | |
/// <param name="facetType">Type of the facet.</param> | |
/// <param name="size">The number of facets</param> | |
public FacetAttribute(int index, FacetType fascetType, int size) | |
{ | |
this.Index = index; | |
this.FacetType = fascetType; | |
this.Size = size; | |
} | |
/// <summary> | |
/// Initializes a new instance of the <see cref="FacetAttribute"/> class. | |
/// </summary> | |
/// <param name="index">The index.</param> | |
/// <param name="size">The number of facets</param> | |
public FacetAttribute(int index, int size) | |
{ | |
this.Index = index; | |
this.FacetType = FacetType.TermsFacetFor; | |
this.Size = size; | |
} | |
/// <summary> | |
/// Initializes a new instance of the <see cref="FacetAttribute"/> class. | |
/// </summary> | |
/// <param name="index">The index.</param> | |
public FacetAttribute(int index) | |
{ | |
this.Index = index; | |
this.FacetType = FacetType.TermsFacetFor; | |
this.Size = 10; | |
} | |
/// <summary> | |
/// Initializes a new instance of the <see cref="FacetAttribute"/> class. | |
/// </summary> | |
public FacetAttribute() | |
{ | |
this.Index = 0; | |
this.FacetType = FacetType.TermsFacetFor; | |
this.Size = 10; | |
} | |
#region Public Properties | |
/// <summary> | |
/// Gets the index. | |
/// </summary> | |
/// <value>The index.</value> | |
public int Index { get; } | |
/// <summary> | |
/// Gets the type of the facet. | |
/// </summary> | |
/// <value>The type of the facet.</value> | |
public FacetType FacetType { get; } | |
/// <summary> | |
/// Gets the number of facets. | |
/// </summary> | |
/// <value>The facet size</value> | |
public int Size { get; } | |
/// <summary> | |
/// Gets a value indicating whether the property is used as a facet in EPiServer Find. | |
/// </summary> | |
/// <value><c>true</c> if [used as a facet in EPiServer Find]; otherwise, <c>false</c>.</value> | |
public static bool Facet | |
{ | |
get | |
{ | |
return true; | |
} | |
} | |
#endregion | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Enum FacetType | |
/// </summary> | |
public enum FacetType | |
{ | |
TermsFacetForWordsIn, | |
TermsFacetFor | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Class FindExtensions. | |
/// </summary> | |
public static class FindExtensions | |
{ | |
/// <summary> | |
/// Adds facets to a Find query base on an attribute. | |
/// </summary> | |
/// <typeparam name="T">The content type to add the facets for.</typeparam> | |
/// <param name="query">The query.</param> | |
/// <returns>ITypeSearch<T>.</returns> | |
public static ITypeSearch<T> AddFacets<T>(this ITypeSearch<T> query) where T : IContent | |
{ | |
foreach (PropertyInfo propertyInfo in GetPropertiesSortedByIndex<T>()) | |
{ | |
FacetAttribute facetAttribute = Attribute.GetCustomAttribute(propertyInfo, typeof(FacetAttribute)) as FacetAttribute; | |
if (facetAttribute == null) | |
{ | |
continue; | |
} | |
ParameterExpression expParam = Expression.Parameter(typeof(T), "x"); | |
MemberExpression expProp = Expression.Property(expParam, propertyInfo); | |
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), propertyInfo.PropertyType); | |
dynamic expression = Expression.Lambda(delegateType, expProp, expParam); | |
//set facet Size | |
Action<TermsFacetRequest> facetRequestAction = (x) => | |
{ | |
x.Size = facetAttribute.Size; | |
}; | |
try | |
{ | |
switch (facetAttribute.FacetType) | |
{ | |
case FacetType.TermsFacetFor: | |
query = TypeSearchExtensions.TermsFacetFor(query, expression, facetRequestAction); | |
break; | |
case FacetType.TermsFacetForWordsIn: | |
query = TypeSearchExtensions.TermsFacetForWordsIn(query, expression); | |
break; | |
default: | |
query = TypeSearchExtensions.TermsFacetFor(query, expression, facetRequestAction); | |
break; | |
} | |
} | |
catch (Exception) | |
{ | |
} | |
} | |
return query; | |
} | |
/// <summary> | |
/// Returns a Dictionary from IHasFacetResults based on an attribute | |
/// </summary> | |
/// <typeparam name="T">The content type to add the facets for</typeparam> | |
/// <param name="results">The result IHasFacetResults</param> | |
/// <returns>Dictionary<int, TermsFacet></returns> | |
public static Dictionary<int, TermsFacet> GetFacets<T>(this IHasFacetResults<T> results) | |
where T : IContent | |
{ | |
var termsFacetsDictionary = new Dictionary<int, TermsFacet>(); | |
foreach (PropertyInfo propertyInfo in GetPropertiesSortedByIndex<T>()) | |
{ | |
var facetAttribute = propertyInfo.GetFacetAttribute(); | |
if (facetAttribute == null) | |
{ | |
continue; | |
} | |
ParameterExpression expParam = Expression.Parameter(typeof(T), "x"); | |
MemberExpression expProp = Expression.Property(expParam, propertyInfo); | |
Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), typeof(object)); | |
dynamic expression = Expression.Lambda(delegateType, expProp, expParam); | |
Expression<Func<T, object>> fieldSelector = expression; | |
try | |
{ | |
var termsFacet = FacetResultExtraction.TermsFacetFor(results, fieldSelector); | |
if (termsFacet != null) | |
{ | |
termsFacetsDictionary.Add(facetAttribute.Index, termsFacet); | |
} | |
} | |
catch (Exception) | |
{ | |
//add logging | |
} | |
} | |
return termsFacetsDictionary; | |
} | |
/// <summary> | |
/// Example how to e.g. get an IEnumerable of strings from the GetFacets dictionary object | |
/// </summary> | |
/// <typeparam name="dict">The dictionary</typeparam> | |
/// <returns>IEnumerable<string></returns> | |
public static IEnumerable<string> ExtractFacetTermsFor(this Dictionary<int, TermsFacet> dict, int index) | |
{ | |
return dict.Where(x => x.Key.Equals(index).SelectMany(y => y.Value.Terms.Select(t => t.Term).OrderBy(t => t))); | |
} | |
/// <summary> | |
/// Gets the properties that has the FacetAttribute sorted by the index. | |
/// </summary> | |
/// <typeparam name="T">The type to get the properties for.</typeparam> | |
/// <returns>IEnumerable<PropertyInfo>.</returns> | |
private static IEnumerable<PropertyInfo> GetPropertiesSortedByIndex<T>() where T : IContent | |
{ | |
PropertyInfo[] allProperties = typeof(T) | |
.GetProperties() | |
.Where(HasAttribute<FacetAttribute>) | |
.Select(x => new | |
{ | |
Property = x, | |
Attribute = (FacetAttribute)Attribute.GetCustomAttribute(x, typeof(FacetAttribute), true) | |
}) | |
.OrderBy(x => x.Attribute != null ? x.Attribute.Index : -1) | |
.Select(x => x.Property) | |
.ToArray(); | |
return allProperties; | |
} | |
/// <summary> | |
/// Determines whether the specified property has the specified attribute. | |
/// </summary> | |
/// <typeparam name="T">The attribute type.</typeparam> | |
/// <param name="propertyInfo">The propertyInfo.</param> | |
/// <returns><c>true</c> if the specified self has attribute; otherwise, <c>false</c>.</returns> | |
private static bool HasAttribute<T>(PropertyInfo propertyInfo) where T : Attribute | |
{ | |
T attr = default(T); | |
try | |
{ | |
attr = (T)Attribute.GetCustomAttribute(propertyInfo, typeof(T)); | |
} | |
catch (Exception) | |
{ | |
} | |
return attr != null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment