Validating only unique values, can be saved into specific set of fields by Custom Field Validator using Lucene with predicates

Posted by

There are lots of blogs floating about custom field validator but our requirement bit different. It was to let only unique values be saved into 10 fields which every content item has. We also wanted to inform the content editor on which item the same value is present so they can decide where it belongs.

Here is the detailed description for a solution to such requisite scenario:

Let’s begin by creating a class which will contain all the fields for which we have to compare the unique value so that we can start indexing those fields.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Sitecore.ContentSearch;
using Sitecore.ContentSearch.SearchTypes;

namespace [namespace]
    public class SearchField : SearchResultItem
    {
        [IndexField("RedirectURL1")]
        public string RedirectURL1 { get; set; }

        [IndexField("RedirectURL2")]
        public string RedirectURL2 { get; set; }

        [IndexField("RedirectURL3")]
        public string RedirectURL3 { get; set; }

        [IndexField("RedirectURL4")]
        public string RedirectURL4 { get; set; }

        [IndexField("RedirectURL5")]
        public string RedirectURL5 { get; set; }

        [IndexField("RedirectURL6")]
        public string RedirectURL6 { get; set; }

        [IndexField("RedirectURL7")]
        public string RedirectURL7 { get; set; }

        [IndexField("RedirectURL8")]
        public string RedirectURL8 { get; set; }

        [IndexField("RedirectURL9")]
        public string RedirectURL9 { get; set; }

        [IndexField("RedirectURL10")]
        public string RedirectURL10 { get; set; }
    }
}

Now we create a setting for configuration setting so as to get start item.

<?xml version="1.0" encoding="utf-8"?>

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
  <sitecore>
    <settings>
      <setting name="SettingName" value="/sitecore/content/Root/Home" />
    </settings>
  </sitecore>
</configuration>

Next we compare whenever the item is being saved which contains modification into above fields.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Web;
using Sitecore.Configuration;
using Sitecore.ContentSearch;
using Sitecore.ContentSearch.Linq.Utilities;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using Sitecore.Data.Validators;
using [namespace].SearchField
using Sitecore.Web.UI.Sheer;

namespace [namespace]
{
    public class FieldValidator : StandardValidator
    {
        public FieldValidator(SerializationInfo info, StreamingContext context)
            : base(info, context)
        { }

        public FieldValidator() { }

        public override string Name
        {
            get { return "Must Have Unique URL"; }
        }

        protected override ValidatorResult GetMaxValidatorResult()
        {
            return GetFailedResult(ValidatorResult.CriticalError);
        }

        protected override ValidatorResult Evaluate()
        {
            Field field = this.GetField();
            if (field == null)
                return ValidatorResult.Valid;

            string str1 = this.ControlValidationValue;
            if (string.IsNullOrEmpty(str1))
                return ValidatorResult.Valid;
            string item = Settings.GetSetting("SettingName");
            Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master");
            Item ContextItem = master.GetItem(item);
            Item Result = null;
            using (var context = ContentSearchManager.GetIndex((SitecoreIndexableItem)ContextItem).CreateSearchContext())
            {
                var predicate = PredicateBuilder.False();
                var Results = context.GetQueryable();
                for (int i = 1; i <= 10; i++)
                {
                    var fieldName = "RedirectURL" + i;
                    predicate = predicate.Or(x => x[fieldName] == str1);
                }

                Result = context.GetQueryable().Where(predicate).Select(i => (Item)i.GetItem()).ToList().FirstOrDefault();
            }

            if (Result != null)
            {
                this.Text = string.Format("Same value exists on item \"{0}\".", Result.DisplayName);
                return GetFailedResult(ValidatorResult.FatalError);
            }
            else
            {
                return ValidatorResult.Valid;
            }
        }
    }
}
Next we needed to register the validator in Sitecore:

1. Create a folder “custom” if not already made under “/sitecore/system/Settings/Validation Rules/Field Rules”.

2. Create an item under “/sitecore/system/Settings/Validation Rules/Field Rules/Custom” with template “/sitecore/templates/System/Validation/Validation Rule”.

3. Provide Type as [Namespace].[Class], [Namespace].

4. Provide parameters as “Result=FatalError” so that item will not be saved.

customfieldvalidator

5. Now expand the template fields you want to validate. Select the fields and in my case I have added custom field validator into validation bar.

customtemplate

When you enter values and try to save the duplicate values, you will get the error message as below:-

error

samevalue

And will get the message at validation bar about the encounter of a duplicated value.

Leave a Reply