Datasource Workflow Module

Posted 01/28/2014 by Tauqir Malik

This module was written in a recent Sitecore Hackathon sponsored by NTT Data. The idea was to enhance the functionality of the workflow engine. This module focuses on the validation of Datasource items that are not in the final state. The module has two below components

1-Data Source Workflow Validation Rule

This rule prevents an item from being approved if any of its data source items are not in the final workflow state. Now let's start on how to setup this rule in Sitecore and then write the code for this new rule. First create the rule in sitecore. This rule should be created under /sitecore/system/Settings/Validation Rules/Item Rules/Item. Take an existing rule and duplicate it, then modify the title, description and type field 

Datasource workflow item

The important field to note is the Type field. This is the custom class that we have written which drives the logic of the rule. What this rule does is basically loop throug all the renderings of the item and checks if the rendering has a datasource item assigned. If it has one then it gets that item and checks if it is in final workflow state. If it isn't then it will throw the below sreenshot and will not let the author approve the item.

Datasource workflow validation

The code for this Rule is below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
   [Serializable]
    public class DataSourceWorkflowValidator : Sitecore.Data.Validators.StandardValidator
    {
         
        public DataSourceWorkflowValidator() : base()
        {
        }
        public DataSourceWorkflowValidator(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }
 
        protected override ValidatorResult Evaluate()
        {
            // local cache for Workflow items state
            Dictionary<id,> workflowStateIsFinal = new Dictionary<id,>();
            // Get the current item where validation is bieng applied
            Item item = this.GetItem();
            // get the item renderings
            RenderingReference[] renderings = item.Visualization.GetRenderings(Sitecore.Context.Device, false);
 
            foreach (RenderingReference rendering in renderings)
            {
                if (rendering.Settings != null)
                {
                    Item dataSourceItem = Utility.GetDataSourceItem(rendering.Settings.DataSource, item);
                    if (dataSourceItem != null)
                    {
                        // check the state of the item
                        if (dataSourceItem.Fields[Sitecore.FieldIDs.WorkflowState].HasValue)
                        {
                            // check the state of the item
                            if (! Utility.IsItemInFinalWorkflowState(dataSourceItem, workflowStateIsFinal))
                                return ValidatorResult.Error;
                        }
                    }
                }
            }
             
            return ValidatorResult.Valid;
        }
 
        protected override ValidatorResult GetMaxValidatorResult()
        {
            return ValidatorResult.Warning;
        }
 
        public override string Name
        {
            get { return "DataSourceWorkflow"; }
        }
 
         
    }

The helper function which check if the Item is in final work flow state is below:

  public static  bool IsItemInFinalWorkflowState(Item item, Dictionary workflowStateIsFinal)
        {
            bool finalState = false;
            if (item.Fields[Sitecore.FieldIDs.WorkflowState].HasValue)
            {
                Item workFlowState = null;
                try
                {
                    ID itemId = new ID(item.Fields[Sitecore.FieldIDs.WorkflowState].Value);
                    // check if the work flow state item exists in local cache
                    if (workflowStateIsFinal.ContainsKey(itemId))
                    {
                        finalState = (bool) workflowStateIsFinal[itemId];
                    }
                    else
                    {
                        workFlowState = _master.GetItem(new ID(item.Fields[Sitecore.FieldIDs.WorkflowState].Value));
                        if (workFlowState != null)
                        {
                            CheckboxField finalcheckBox = workFlowState.Fields[Sitecore.WorkflowFieldIDs.FinalState];
                            if (finalcheckBox != null && finalcheckBox.Checked)
                                finalState = true;
                        }
                        // add the work flow item in local cache
                        workflowStateIsFinal.Add(itemId,finalState);
                    }

                }
                catch (Exception ex)
                {
                    Sitecore.Diagnostics.Log.Warn("Error Getting Wrokflow State Item :: DataSourceWorkflowValidator", ex, item);
                }
                
            }
            return finalState;

}

Lastly this new validtion rule needs to be assigned to the template standard values for the Items this has to be applied. The workflow validation rule field needs to mofidied and new rule added there as shown in below sceenshot

standard value item

2-Data Source Workflow Validation Warning in Content Editor

The second part of this component will show a warning message like shown below if the Item is in approved work flow state but one of the dependent Datasource items has not been approved. 
Datasource workflow validation

A custom pipleline was written and added to the Content Editor Warnings pipleline. The pipleline needs to be in the below config section

1
2
3
4
5
<pipelines>
      <getcontenteditorwarnings>
          <processor type="Heisenberg.SCExtensions.Pipelines.GetContentEditorWarnings.DataSourceWorkflowValidatorWarning, Heisenberg.SCExtensions">
    </processor></getcontenteditorwarnings>
</pipelines>

The code for this processor is below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class DataSourceWorkflowValidatorWarning
   {
       protected GetContentEditorWarningsArgs.ContentEditorWarning _contentEditorWarning = null;
       protected Dictionary<ID, bool> workflowStateIsFinal = new Dictionary<ID, bool>();
 
       public void Process(GetContentEditorWarningsArgs args)
       {
           Item item = args.Item;
 
           // check if the current item is in final workflow state and then check for validation errors
           if (! Utility.IsItemInFinalWorkflowState(item, workflowStateIsFinal))
               return;
           // set the warning Title
           _contentEditorWarning = args.Add();
           _contentEditorWarning.Title = Sitecore.Globalization.Translate.Text("If you publish now, the current item may not render properly because the following dependencies have not been moved to a final workflow state. Click the links below to review these items:");
            
           SetValidatorWarningMessages(item, args);
 
       }
     
       protected void SetValidatorWarningMessages(Item item, GetContentEditorWarningsArgs args)
       {
           // get all the rendering at the item
           RenderingReference[] renderings = item.Visualization.GetRenderings(Sitecore.Context.Device, false);
 
           foreach (RenderingReference rendering in renderings)
           {
               if (rendering.Settings != null)
               {
                   Item dataSourceItem = Utility.GetDataSourceItem(rendering.Settings.DataSource, item);
                   if (dataSourceItem != null)
                   {
                       // check the state of the item
                       if (!Utility.IsItemInFinalWorkflowState(dataSourceItem, workflowStateIsFinal))
                         AddWarningOptions(dataSourceItem);
                   }
               }
           }
       }
     
       private void AddWarningOptions(Item dataSourceItem)
       {
           _contentEditorWarning.AddOption(dataSourceItem.Name, string.Format("item:load(id={0},language={1},version={2})", dataSourceItem.ID, dataSourceItem.Language, dataSourceItem.Version.Number));
       }
   }

Share:

Archive

Syndication