Extend the search functionality

The StructPIM infrastructure supports implementation of custom search fields, allowing you to implement searches in custom data fields or your aggregation of data

What are search fields

When searching products or variants in StructPIM, the user can select between a range of fields to show in the result table, as well as search these fields. Using the StructPIM infrastructure, you can implement your own search field, where you have full control of what to search and what to show.

This article will show an example on how to implement your own search field.


Implementing a search field

In order to implement your own search field, you must create a new class in your Umbraco project, which inherits from FieldDescriptor, which looks like this

public abstract class FieldDescriptor
{
    public abstract List<DataField> GetAvailableFields(ItemType itemType, int languageId);
    public abstract List<string> SearchItemIdsFromDataFieldQuery(ItemType itemType, int languageId, DataFieldQuery dataFieldQuery);
    public abstract Dictionary<string, Dictionary<string, string>> GetValues(List<string> itemIds, List<string> dataFieldUids, ItemType itemType, int languageId, List<DataFieldQuery> dataFieldQueries);
    public abstract List<string> GetSortedItemList(string sortByDataFieldUid, ItemType itemType, List<string> itemIds, int languageId);
}

Below is shown an example of a FieldDescriptor implementation (this is actually the implementation used for the search field "Internal Id", which is shipped with StructPIM).

public class ItemIdFieldDescriptor : FieldDescriptor
{
    public override List<DataField> GetAvailableFields(ItemType itemType, int languageId)
    {
		//Test the item type
        var type = itemType.GetType();
        if (type != typeof(ProductGroupItemType) && type != typeof(ProductItemType) && type != typeof(VariantItemType))
        {
            return new List<DataField>();
        }
		
		//Return a data field which is searchable and sortable
        return new List<DataField>
        {
            new DataField
            {
                Uid = "PIM.ItemId",
                DataFieldName = "Internal Id",
                SupportsSearching = true,
                SupportsSorting = true,
                FieldDescriptor = this
            }
        };
    }

    public override List<string> SearchItemIdsFromDataFieldQuery(ItemType itemType, int languageId, DataFieldQuery dataFieldQuery)
    {
        var type = itemType.GetType();
        if (type != typeof(ProductGroupItemType) && type != typeof(ProductItemType) && type != typeof(VariantItemType))
        {
            return new List<string>();
        }

        var parameters = new DynamicParameters();
        parameters.Add("id", dataFieldQuery.FilterValue);
		
		//Get correct where statement according to QueryOperator
        var query = GetQuery(dataFieldQuery);

        var sql = $@"select a.id from product as a
                     where {query}";

        using (var connection = DBUtility.GetOpenConnection())
        {
            return connection.Query<string>(sql, parameters).ToList();
        }
    }

    public override Dictionary<string, Dictionary<string, string>> GetValues(List<string> itemIds, List<string> dataFieldUids, ItemType itemType, int languageId, List<DataFieldQuery> dataFieldQueries)
    {
        var result = new Dictionary<string, Dictionary<string, string>>();
        foreach (var d in itemIds)
        {
            var val = new Dictionary<string, string> { { dataFieldUids.First(), d } };
            result.Add(d, val);
        }
        return result;
    }

    public override List<string> GetSortedItemList(string sortByDataFieldUid, ItemType itemType, List<string> itemIds, int languageId)
    {
        return itemIds.OrderBy(x => x).ToList();
    }

    private string GetQuery(DataFieldQuery query)
    {
        //Perform EMPTY search (Can never happen)
        if (query.QueryOperator == QueryOperator.IsEmpty)
        {
            return $"(1 = 0)";
        }
        //Perform IS NOT EMPTY (Will always be true)
        if (query.QueryOperator == QueryOperator.IsNotEmpty)
        {
            return $"(1 = 1)";
        }
        //Perform NOT EQUAL search
        if (query.QueryOperator == QueryOperator.NotEquals)
        {
            return $"(not a.Id = @id)";
        }
        //Perform NOT WILDCARD EQUAL search
        if (query.QueryOperator == QueryOperator.NotWildcardEquals)
        {
            return $"(a.Id not like '' + @id + '%')";
        }
        //Perform EQUAL search
        if (query.QueryOperator == QueryOperator.Equals)
        {
            return $"(a.Id = @id)";
        }
        //Perform CONTAINS search
        if (query.QueryOperator == QueryOperator.Contains)
        {
            return query.FilterValue.Length == 0 ?
                ("(1 = 1)") :
                $"(a.Id like '%' + @id + '%')";
        }
        //Perform NOT CONTAINS search
        if (query.QueryOperator == QueryOperator.NotContains)
        {
            return query.FilterValue.Length == 0 ?
                ("(1 = 1)") :
                $"(a.Id not like '%' + @id + '%')";
        }
        //Perform LARGER THAN search
        if (query.QueryOperator == QueryOperator.LargerThan)
        {
            return $"(a.Id > @id)";
        }
        if (query.QueryOperator == QueryOperator.SmallerThan)
        {
            return $"(a.Id < @id)";
        }
        //Perform default WILDCARD search
        return $"(a.Id like '' + @id + '%')";
    }
}

GetAvailableFields

The GetAvailableFields should return a list of DataField's, which each has a globally unique id, a name to show in the search table and an indication whether the field supports searching and sorting. You can limit the availability of your field based on the item type.

 

SearchItemIdsFromDataFieldQuery

This is where the search is performed. If you have set SupportSearching to false for the DataField's returned in GetAvailableFields, this method will never get called. However, if you have allowed searching, this is where you implement the actual search based on the DataFieldUid, QueryOperator and FilterValue in the dataFieldQuery provided to you.

All you need to do is return a list of strings representing the ids of the items which matched your search

 

GetValues

The GetValues method is used by StructPIM to get the actual values to show in the search table. Here you need to return a dictionary with values of the provided dataFieldUids for each of the provided itemIds. In the example above, we know that this FieldDescriptor implementation returns a single DataField. Thus we will never get more than one uid in the dataFieldUids parameter (corresponding to that one). The dataFieldQueries are provided for you, if you need them for building your values (if the values you want to show depends on the actual search performed).

 

GetSortedItemList

This method must return the provided itemIds sorted ascending based on the sortByDataFieldUid. This method will never get called if you set the SupportsSorting to false


© 2024 Struct - All rights reserved.