phpvalidationrespect-validation

Multiple rules/error messages inside a custom rule in Respect\Validation?


Say you have a custom rule like this:

<?php

class CheckFoo extends \Respect\Validation\Rules\AbstractRule
{
    public function validate($input)
    {
        if ($input == 'foo')
            return true;
        else
            return false;       
    }
}

class CheckFooException extends \Respect\Validation\Exceptions\ValidationException
{
    public static $defaultTemplates = [
        self::MODE_DEFAULT => [
            self::STANDARD => '{{name}} must be foo',
        ],
        self::MODE_NEGATIVE => [
            self::STANDARD => '{{name}} must not be foo',
        ],
    ];
}

This works fine but is it possible to add additional rules inside this rule? To illustrate, is something like this possible:

class CheckFoo extends \Respect\Validation\Rules\AbstractRule
{
    public function validate($input)
    {
        if (strlen($input) != 3)
            return false;

        if ($input == 'foo')
            return true;
        else
            return false;
    }
}

How can I define a custom error message inside CheckFooException if (strlen($input) != 3) is triggered?


Solution

  • Inspecting the library you are using, especially the ValidationException class and the implementation for AttributeException, it should be possible to access a property declared on your rule class during validation via ValidationException::getParam($propertyName) from your Exception class. Like so:

    class CheckFoo extends \Respect\Validation\Rules\AbstractRule
    {
        public $reason;
    
        public function validate($input)
        {
            if (strlen($input) != 3) {
                $this->reason = 'length';
                return false;
            }
    
            if ($input !== 'foo') {
                $this->reason = 'content';
                return false;
            }
            return true;
    
        }
    }
    

    Then access it implementing/overriding the method ValidationException::chooseTemplate, like so:

    class CheckFooException extends \Respect\Validation\Exceptions\ValidationException
    {
        const INVALID_LENGTH = 0;
        const INVALID_NAME = 1;
    
        public static $defaultTemplates = [
            self::MODE_DEFAULT => [
                self::INVALID_NAME => '{{name}} must be foo',
                self::INVALID_LENGTH => '{{name}} must be 3 characters long',
            ],
            self::MODE_NEGATIVE => [
                self::INVALID_NAME => '{{name}} must not be foo',
                self::INVALID_LENGTH => '{{name}} must not be 3 characters long',
            ],
        ];
    
        public function chooseTemplate()
        {
            return 'length' === $this->getParam('reason')
                ? self::INVALID_LENGTH
                : self::INVALID_NAME;
        }
    }
    

    Test:

    v::checkFoo()->check('FOO'); // => "FOO" must be foo
    v::checkFoo()->check('foox'); // => "foox" must be 3 characters long
    

    Alternatively, you could combine 2 different rules with dedicated messages (or, for sth. trivial as length, use the one provided by the library already).