Custom validation in CMS: create vs edit

Silverstripe Version:
4.2.1

Question:

Hi,

I’m trying to apply custom validation to a dataobject class.

The dataobject class is called Tag, and I include the validator class Tag_Validator using

    public function getCMSValidator() {
        return new Tag_Validator();
    }    

In Tag_Validator I check for empty values, and I also check for unique value.
The way I check for unique (and empty first) is with this code:

        if(empty($data['Name'])) {
            $this->validationError('Name', 'Please enter a name for the tag');
            $valid = false;            
        }

        else if(Tag::get()->filter(['Name' => $data['Name']])->first()) {
            $this->validationError('Name', 'The ' . $data['Name'] . ' tag already exists');
            $valid = false; 
        }

This is fine. It works when I create any Tag object.

However, when I edit an existing Tag, but don’t I don’t change the Tag Name, I get a validation error.

I need to be able to distinguish between a create action and an edit action, so that if validation is happening on edit, then I can do something different.

Maybe I could check for $tag->ID while validating, and that would tell me if it was a create or and edit, but I can’t see how to pass data like this into the validator.

Any advice greatly appreciated.

You should be able to use $this->isInDB() to check whether it’s a new record or an existing one. But, you obviously don’t want to skip the name validation entirely if the record is in the database - since you still need to validate the name for duplicates (if the user changed it).

You can use $this->isChanged('Name') to check if the name field has actually changed… so a combination of the this and isInDB() should get you where you want to be.

As an aside, there’s also a getChangedFields() method which will just return all the changes in the record.

1 Like

Can’t you also use $this->exists() (as well as $this->isInDB()?

Thanks for the answers. All of these methods seem to be on the databobject, but the dataobject doesn’t seem to be accessible from the validator.

To try to keep my code need clean, I had split out the validators into their own class files using:

    public function getCMSValidator() {
        return new My_Validator();
    }   

So the problem I have is that the dataobject isn’t accessible from the validator in the code below:

    use SilverStripe\Forms\RequiredFields;

    class My_Validator extends RequiredFields {

        public function php($data) {
            $valid = parent::php($data);

            if(empty($data['Name'])) {
                $this->validationError('Name', 'Please enter a name');
                $valid = false;            
            }

            return $valid;
        }
    }

I guess I can use the validate() function instead but then I don’t get to spit the validation code out into a different file