4

I want to make a item:saving pipeline processor that will perform some operations when a item field is reset. I thought this would be simple, but it turned out to be trickier than I thought. Maybe I'm just missing something.

When the item:saving processor is triggered, I can get the modified fields by savingItem.Fields.Where(f => f.IsModified). I found that, when resetting a field, the fields Value is an empty string, HasValue is true and ResetBlank is false.

I expected the opposite (Value to be null, HasValue to be false and ResetBlank is true) during the item:saving, but the reset operation is eventually performed properly.

How do I distinguish a field reset from storing an empty string in the item:saving pipeline? (This is on Sitecore 9.0.1)

2
  • How are you getting at the savingItem?
    – Mark Cassidy
    Jun 11 '19 at 14:57
  • I get the savingItem from the EventArgs parameter.
    – mikaelnet
    Jun 11 '19 at 17:24
1

You can get this information using reflection mechanism and internal item.GetChanges(true) method:

  1. Get ItemChanges by executing GetChanges(true) with reflection
  2. Get FieldChanges from ItemChanges.
  3. Get underlying _field field from every FieldChange with reflection again
  4. Check if any of the fields has ResetBlank flag set to true.

Code:

public class IsResetEventHandler
{
    private FieldInfo _fieldFieldInfo;
    private FieldInfo FieldFieldInfo
    {
        get
        {
            return _fieldFieldInfo ?? (_fieldFieldInfo = typeof(FieldChange).GetField("_field", BindingFlags.NonPublic | BindingFlags.Instance));
        }
    }

    private MethodInfo _getChangesMethodInfo;
    private MethodInfo GetChangesMethodInfo
    {
        get
        {
            return _getChangesMethodInfo ?? (_getChangesMethodInfo = typeof(Item).GetMethod("GetChanges", BindingFlags.NonPublic | BindingFlags.Instance));
        }
    }

    public void OnItemSaving(object sender, EventArgs args)
    {
        try
        {
            var savedItem = (args as SitecoreEventArgs)?.Parameters[0] as Item;

            if (savedItem == null)
                return;

            var changes = (ItemChanges) GetChangesMethodInfo.Invoke(savedItem, new object[] { true} );

            var fieldChanges = changes.FieldChanges.Cast<FieldChange>().ToList();

            var isReset = fieldChanges.Any(fc => ((Field) FieldFieldInfo.GetValue(fc)).ResetBlank);

        }
        catch (Exception ex)
        {
            Log.Error("Error while checking if it's reset action", ex, this);
        }
    }
}
0

I haven't found any method to get the information about the field reset from the args passed to item:saving pipeline.

There is a "hacky" method you can use - you can use client request form values like:

var resetFields = Context.ClientPage.ClientRequest.Form.AllKeys.Where(key => key != null && key.StartsWith("Reset_")).Select(key => ShortID.DecodeID(StringUtil.Mid(key, 6))).ToList();

This is pretty much the code which is used by the Reset Fields dialog. It gets all the request form keys and filters those starting with Reset_ prefix. Rest of the key is the ID of the field which is reset.

If you need the ids of the fields, you can use the code above. If you need only an information if the item:saving is cause by reset fields command, just check if there is any Reset_*** key.

2
  • Thanks Marek, but that won't be sufficient in my scenario. Fields may be reset by PowerShell scripts, integration jobs and also by users resetting the final layout field. So I need to perform this operations close to the data engine.
    – mikaelnet
    Jun 12 '19 at 8:59
  • @mikaelnet I added another answer using different approach. I hope it's what you need. Jun 12 '19 at 11:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.