Custom validator rules

We have previously introduced how to use a custom validator, but sometimes we want to extend our validator rules instead of re-customizing a validator. For this scenario, we can also add ourselves more conveniently. Validator rules, please read the detailed steps below

Available: >= v2.0.3

Declaration validator

We declare validator validator basis of the statement of this section, which adds a password field, we use a self-defined validation rules to validate the field.

     /**
     * @AlphaDash(message="Passwords can only be alphabet, numbers, dashes, underscores")
     *
     * @var string
     */
    protected $password; 

As above, we added a password field and used a validation rule of @AlphaDash() , which is the rule we want to customize next. Its function is to verify the format of the field so that it can only be 字母 , 数字 , - , _ .

Thinking that because our validation rules work in an annotated way, defining validation rules is actually equivalent to defining a custom annotation command of our own, which is clear after we continue.

Declaration rule annotation

Note We strongly recommend that you define custom annotations into the App/Annotation path as suggested in the application structure .

Declaration annotation command

 <?php declare(strict_types=1);

namespace App\Annotation\Mapping;

use Doctrine\Common\Annotations\Annotation\Attribute;
use Doctrine\Common\Annotations\Annotation\Attributes;

/**
 * Class AlphaDash
 *
 * @since 2.0
 *
 * @Annotation
 * @Attributes({
 *     @Attribute("message",type="string")
 * })
 */
class AlphaDash 
{
    /**
     * @var string
     */
    private $message = '';

    /**
     * @var string
     */
    private $name = '';

    /**
     * StringType constructor.
     *
     * @param array $values
     */
    public function __construct(array $values)
    {
        if (isset($values['value'])) {
            $this->message = $values['value'];
        }
        if (isset($values['message'])) {
            $this->message = $values['message'];
        }
        if (isset($values['name'])) {
            $this->name = $values['name'];
        }
    }

    /**
     * @return string
     */
    public function getMessage(): string
    {
        return $this->message;
    }

    /**
     * @return string
     */
    public function getName(): string
    {
        return $this->name;
    }
} 

@Annotation

Declare this class as an annotation command

@Attributes

Declarative annotation parameter set

@Attribute

Declare specific parameters

  • Name of the name parameter
  • Type of parameter value

Class attribute method description

$message is the prompt we passed in when we used the annotation. For example @IsString(message="该字段必须是字符串") $name is the $name of the field. If it is empty, the default is the attribute name such as @IsString(name="user_name") $value is the validation rule we need to pass. Some of the data, if you do not need to pass the parameters, you can not define. For example @Enum(values=[1,2,3]) getMessage() , the getName() method must exist. Used to get $message and $name

Statement annotation analysis

At this point, we have defined the annotation command, but if the annotation command is to be executed, we need to define a parser for the annotation command. Below is an annotation parser, which needs to inherit the Swoft\Annotation\Annotation\Parser\Parser class.

 <?php declare(strict_types=1);

namespace App\Annotation\Parser;

use ReflectionException;
use Swoft\Annotation\Annotation\Mapping\AnnotationParser;
use Swoft\Annotation\Annotation\Parser\Parser;
use App\Annotation\Mapping\AlphaDash;
use Swoft\Validator\Exception\ValidatorException;
use Swoft\Validator\ValidatorRegister;

/**
 * Class AlphaDashParser
 *
 * @AnnotationParser(annotation=AlphaDash::class)
 */
class AlphaDashParser extends Parser
{
    /**
     * @param int $type
     * @param object $annotationObject
     *
     * @return array
     * @throws ReflectionException
     * @throws ValidatorException
     */
    public function parse(int $type, $annotationObject): array
    {
        if ($type != self::TYPE_PROPERTY) {
            return [];
        }
        //向验证器注册一个验证规则
        ValidatorRegister::registerValidatorItem($this->className, $this->propertyName, $annotationObject);
        return [];
    }
} 

@AnnotationParser

Declare an annotation command to parse

Parse()

Since we inherit Swoft\Annotation\Annotation\Parser\Parser and it declares a Swoft\Annotation\Annotation\Parser\ParserInterface interface, this method is exactly ParserInterface the interfaces defined by ParserInterface that must be implemented by us. interface. In fact, here is the business logic we have to deal with. After Swoft resolves to an annotation command, it will execute the parse() method in the parser corresponding to this annotation.

Declare a validation rule

After the previous steps we have defined the annotations of the validation rules and its parser, but we have not defined our specific validation rules, so next we will declare our specific validation rules, which is actually very simple, we only Need to implement a Swoft\Validator\Contract\RuleInterface interface.

 <?php declare(strict_types=1);

namespace App\Validator\Rule;

use App\Annotation\Mapping\AlphaDash;
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Validator\Contract\RuleInterface;
use Swoft\Validator\Exception\ValidatorException;

/**
 * Class AlphaDashRule
 *
 * @Bean(AlphaDash::class)
 */
class AlphaDashRule implements RuleInterface
{
    /**
     * @param array $data
     * @param string $propertyName
     * @param object $item
     * @param null $default
     *
     * @return array
     * @throws ValidatorException
     */
    public function validate(array $data, string $propertyName, $item, $default = null): array
    {
        $message = $item->getMessage();
        if (!isset($data[$propertyName]) && $default === null) {
            $message = (empty($message)) ? sprintf('%s must exist!', $propertyName) : $message;
            throw new ValidatorException($message);
        }
        $rule = '/^[A-Za-z0-9\-\_]+$/';
        if (preg_match($rule, $data[$propertyName])) {
            return [$data];
        }
        $message = (empty($message)) ? sprintf('%s must be a email', $propertyName) : $message;
        throw new ValidatorException($message);
    }
} 

@Bean

Since the validator internally gets the validation rules through the Bean container, the code is as follows

     $rule = BeanFactory::getBean($itemClass);//这里通过容器拿到了我们的验证规则
    $data = $rule->validate($data, $propName, $item, $default); 

So here we are going to use @Bean to register our validation rules, the name is the same as our annotation command.

Validate()

This is the method that is specified in the RuleInterface interface. Here is actually writing our specific validation rules.

  • array $data all array $data to be verified
  • string $propertyName the name of the field to be verified
  • $item annotation class object
  • Default value of $default field

    So far we have defined a validator rule.

/docs/2.x/en/validator/customer-rule.html
progress-bar