Im facing a problem with sitecore item validator when I try to save the data. The purpose of my validator (the class inherit from StandardValidator) is to simply check if, atleast, field A or field B has a value. If not, I prevent the data to be saved by throwing a ValidatorResult.CriticalError

However, sitecore is having a strange behaviour. Instead of doing the validation on the newly inputed data, he's getting the data already saved and trying to perform the validation on them.

I think the purpose of the validator is to validate the new data before saving, but at the moment it try to validate the data already saved. Is this a bug ? Or Am I missing something ?

By the way, here is how I retrieve my fields inside of the Evaluate() function

protected override ValidatorResult Evaluate()
{
    Sitecore.Data.Items.Item item = this.GetItem();
    Sitecore.Data.Fields.MultilistField first = item.Fields[FieldOne_Name];
    Sitecore.Data.Fields.MultilistField second = item.Fields[FieldTwo_Name];
    //Processing code here...
}

Any hint is more than welcome!

Thank's

  • I finally got it working with the help of Marek and Richard. I used the saveUI pipeline where I check in the Process function, the type of template. Then I use ContentDatabase.GetItem to retrieve more informations about the item being processed. From there I can retrieve the fields im looking for to do my logic and abort the pipeline with a message in case the conditions are not fulfilled. – TeKilla Jul 20 '17 at 9:06
up vote 2 down vote accepted

My answer is incorrect. See Richard's answer below. Answer is "use fatal validation result instead of critical". Or use item:saving event like described in my answer.


You can use workflow and not allow to proceed to the final state if any of the validators failed.

Alternatively, you can use item:saving event instead of validation.

Another way is using saveUI pipeline.

You just need to use code like this to prevent item from being saved:

Sitecore.Web.UI.Sheer.SheerResponse.Alert(message, new string[0]); 
args.SaveAnimation = false; 
args.AbortPipeline(); 

More details can be found in John West blog post Intercepting Item Updates with Sitecore

  • 1
    Marek - this is not true - its the return type of the error that is stopping the validator from preventing the save. Change it from Critical to Fatal and it will work as expected. – Richard Seal Jul 19 '17 at 14:16
  • Thank you for the information about the cycle of the validator. Im going to hook the item:saving handler to do the work :) – TeKilla Jul 19 '17 at 14:20
  • 1
    Thanks @RichardSeal . My answer edited. TeKilla please have a look at Richard's answer instead. – Marek Musielak Jul 19 '17 at 14:46

So one thing to note - CriticalError - the user is warned before saving, but the data is still saved. FatalError will stop the item from being saved if validation fails.

But...

What you are trying to do is not possible in a validator.

The this.GetItem() method in the base validator, gets the item from the database. Remember that a validator works on a single field at a time. So it then updates that field in the item to have the new value for that field only.

So you would not be able to use it to get new values for 2 fields to validate those. Your only option there would be the item:saving event. But be careful with that, it will fire for the save of every single item you have, so you can easily make Sitecore run very slow there.

  • I think you didn't understood my problem. Im able to prevent the user from saving when I use FatalError, however it's not the problem. The problem is the data which are being validated. They are not the the ones the user is trying to save, but the ones which are already saved. Thus, the validation is happenning on data which are already saved. – TeKilla Jul 19 '17 at 14:23
  • 1
    Edited to better match your question – Richard Seal Jul 19 '17 at 14:41
  • 1
    No, the data isn't saved. You call base.GetItem, which will return you the proposed new item (but not yet committed to database). If you want the version of the item currently in DB, you need to call Database.GetItem(this.itemUri). – Mark Cassidy Jul 19 '17 at 14:42

What is throwing you off, is the ambiguous labeling of method GetItem().

Here's what it looks like:

protected virtual Item GetItem()
{
  if (this.itemUri == (ItemUri) null)
    return (Item) null;
  Item obj = Database.GetItem(this.itemUri);
  if (obj == null || obj.Versions.Count == 0)
    return (Item) null;
  this.UpdateItem(obj);
  return obj;
}

The thing to note here is, it calls UpdateItem(), which is essentially loading up the proposed new item values into the in-memory copy of your Item.

So when you say you are getting "already saved" values, this actually isn't the case. Not if you abort the validation with a FatalError like described elsewhere here.

If you want to get field values as they are in the database right now, you need to mimic what GetItem() is doing, but avoiding the UpdateItem() functionality.

Like this, for example:

protected virtual Item GetStoredItem()
{
    return Database.GetItem(this.itemUri);
}

(parameter guarding omitted)

And if you then decide to throw a Fatal validation error on your field, the values will be rejected outright and never stored to DB.

  • This point is extremely helpful in understanding how Richard's answer works. Good to know. – Teeknow Jul 19 '17 at 14:53
  • It actually answers your question; "I think the purpose of the validator is to validate the new data before saving, but at the moment it try to validate the data already saved. Is this a bug ? Or Am I missing something ?" – Mark Cassidy Jul 19 '17 at 15:07
  • 1
    I'm not the person who posted the question. We have similar usernames at first glance haha – Teeknow Jul 19 '17 at 15:48
  • Oh. Right hehe ;-) – Mark Cassidy Jul 19 '17 at 15:49

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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