tobento/service-validation

轻松验证数据。

1.0.2 2024-03-09 16:01 UTC

This package is auto-updated.

Last update: 2024-09-09 17:11:20 UTC


README

验证服务提供了一种轻松验证数据的方法。

目录

入门

运行以下命令添加验证服务的最新版本。

composer require tobento/service-validation

要求

  • PHP 8.0 或更高版本

亮点

  • 框架无关,与任何项目兼容
  • 解耦设计

文档

验证

单值

轻松验证单值。

use Tobento\Service\Validation\Validator;
use Tobento\Service\Validation\ValidatorInterface;
use Tobento\Service\Validation\ValidationInterface;

$validator = new Validator();

var_dump($validator instanceof ValidatorInterface);
// bool(true)

$validation = $validator->validating(
    value: 'foo',
    rules: 'alphaStrict|minLen:2',
    data: [],
    key: null
);

var_dump($validation instanceof ValidationInterface);
// bool(true)

查看验证器了解有关验证器的更多信息。
查看验证了解有关ValidationInterface的更多信息。

参数说明

多值

验证多个值。

use Tobento\Service\Validation\Validator;
use Tobento\Service\Validation\ValidatorInterface;
use Tobento\Service\Validation\ValidationInterface;

$validator = new Validator();

var_dump($validator instanceof ValidatorInterface);
// bool(true)

$validation = $validator->validate(
    data: [
        'title' => 'Product',
        'color' => 'blue',
    ],
    rules: [
        'title' => 'alpha',
        'color' => 'in:blue:red:green',        
    ]
);

var_dump($validation instanceof ValidationInterface);
// bool(true)

查看验证器了解有关验证器的更多信息。
查看验证了解有关ValidationInterface的更多信息。

参数说明

嵌套值

如果传入的值包含“嵌套”数据,您可以在规则中使用“点”语法指定这些属性

use Tobento\Service\Validation\Validator;
use Tobento\Service\Validation\ValidatorInterface;
use Tobento\Service\Validation\ValidationInterface;

$validator = new Validator();

var_dump($validator instanceof ValidatorInterface);
// bool(true)

$validation = $validator->validate(
    data: [
        'title' => 'Product',
        'meta' => [
            'color' => 'blue',
        ],
    ],
    rules: [
        'title' => 'alpha',
        'meta.color' => 'required|in:blue:red:green',        
    ]
);

var_dump($validation instanceof ValidationInterface);
// bool(true)

查看验证器了解有关验证器的更多信息。
查看验证了解有关ValidationInterface的更多信息。

参数说明

规则定义

默认规则解析器支持以下规则定义。
您还可以查看默认规则以了解它提供的规则。
如果您添加具有依赖关系的“懒”规则,您将需要使用AutowiringRuleFactory来解决,请参阅默认规则

字符串定义

use Tobento\Service\Validation\Validator;

$validation = (new Validator())->validate(
    data: [
        'title' => 'Product',
    ],
    rules: [
        'title' => 'minLen:2|alpha',
    ]
);

具有字符串规则的数组定义

如果您需要定义额外的规则参数或自定义错误消息,请将规则包装在数组中

use Tobento\Service\Validation\Validator;

$validation = (new Validator())->validate(
    data: [
        'title' => 'Product',
    ],
    rules: [
        'title' => [
            // single or multiple rules
            'required|alpha',
            
            // using array with string rule and custom parameters.
            ['minLen:3', 'error' => 'Custom error message'],
            
            // using array with string rule but seperate rule parameters and custom parameters.
            ['minLen', [3], 'error' => 'Custom error message'],
        ],
    ]
);

对象规则

您可以通过实现规则接口来定义对象规则

use Tobento\Service\Validation\Validator;
use Tobento\Service\Validation\Rule\Same;

$validation = (new Validator())->validate(
    data: [
        'title' => 'Product',
    ],
    rules: [
        'title' => [
            // single or multiple rules
            'required|minLen:2',
            
            new Same(),
            
            // using array for custom parameters:
            [new Same(), 'error' => 'Custom error message'],
            
            // using array for lazy rule:
            [[Rule::class], [3], 'error' => 'Custom error message'],
            
            // lazy rule with unresolvable class params:
            // [[Rule::class, ['name' => 'value']], [3], 'error' => 'Custom error message'],
        ],
    ]
);

具有不同验证方法的对象规则

您可以通过定义具有不同验证方法的对象规则

use Tobento\Service\Validation\Validator;
use Tobento\Service\Validation\Rule\Length;

$validation = (new Validator())->validate(
    data: [
        'title' => 'Product',
    ],
    rules: [
        'title' => [
            // single or multiple rules
            'required|alpha',
            
            // calls the min method for validation:
            [[new Length(), 'min'], [3], 'error' => 'Custom error message'],
            
            // lazy rule
            [[Length::class, 'min'], [3], 'error' => 'Custom error message'],
            
            // lazy rule with unresolvable class params:
            [[Length::class, 'min', ['name' => 'value']], [3], 'error' => 'Custom error message'],
            
            // lazy rule with unresolvable class params without method to call:
            // [[Rule::class, ['name' => 'value']], [3], 'error' => 'Custom error message'],
        ],
    ]
);

参数

对于每个规则,您可以定义自定义参数。

use Tobento\Service\Validation\Validator;
use Tobento\Service\Validation\Rule\Length;

$validation = (new Validator())->validate(
    data: [
        'title' => 'Product',
    ],
    rules: [
        'title' => [
            [
                'minLen:3',
                'error' => ':attribute must at least contain :parameters[0] chars',
                
                // you might want a custom value for the attribute:
                ':attribute' => 'The TITLE',
                
                // you might need a custom value:
                ':parameters[0]' => 3,
                
                // global modifier parameters:
                'limit_length' => 100,
            ],
        ],
    ]
);

全局参数

有时您可能需要为所有规则自定义参数。

use Tobento\Service\Validation\Validator;
use Tobento\Service\Validation\Rule\Length;

$validation = (new Validator())->validate(
    data: [
        'title' => 'Product',
    ],
    rules: [
        'title' => [
            // single or multiple rules
            'required|alpha',
            
            // calls the min method for validation:
            [[new Length(), 'min'], [3]],
            
            // global error message:
            'error' => 'Error message',
            
            // global replacement parameters for messages:
            ':attribute' => 'The TITLE',
            
            // global modifier parameters:
            'limit_length' => 100,
        ],
    ]
);

验证器

创建验证器

use Tobento\Service\Validation\Validator;
use Tobento\Service\Validation\ValidatorInterface;
use Tobento\Service\Validation\RulesInterface;
use Tobento\Service\Validation\RulesParserInterface;
use Tobento\Service\Validation\RulesAware;
use Tobento\Service\Message\MessagesFactoryInterface;

$validator = new Validator(
    rules: null, // null|RulesInterface
    rulesParser: null, // null|RulesParserInterface
    messagesFactory: null // null|MessagesFactoryInterface
);

var_dump($validator instanceof ValidatorInterface);
// bool(true)

var_dump($validator instanceof RulesAware);
// bool(true)

参数说明

验证器接口

use Tobento\Service\Validation\ValidatorInterface;
use Tobento\Service\Validation\ValidationInterface;
use Tobento\Service\Collection\Collection;

interface ValidatorInterface
{
    public function validating(
        mixed $value,
        string|array $rules,
        array|Collection $data = [],
        null|string $key = null
    ): ValidationInterface;
    
    public function validate(mixed $data, array $rules): ValidationInterface;
}

查看验证以了解有关方法的更多信息。
查看Collection Service以了解更多信息。

规则感知

use Tobento\Service\Validation\RulesInterface;

interface RulesAware
{
    public function rules(): RulesInterface;
}

查看规则接口以了解有关RulesInterface的更多信息。

验证

验证接口

use Tobento\Service\Validation\ValidationInterface;
use Tobento\Service\Validation\RuleInterface;
use Tobento\Service\Message\MessagesInterface;
use Tobento\Service\Collection\Collection;

interface ValidationInterface
{
    public function isValid(): bool;
    
    public function errors(): MessagesInterface;  
    
    public function data(): Collection;
    
    public function valid(): Collection;
    
    public function invalid(): Collection;
    
    public function rule(): null|RuleInterface;
}

方法说明

错误信息

默认情况下,当在错误消息中定义时,规则键用作:attribute 参数。
出于翻译原因,不建议编写像“:attribute 必须……”这样的消息,更好的做法是将“title”添加到:attribute 参数中,因为“the”可能因属性名称而异。

use Tobento\Service\Validation\Validator;
use Tobento\Service\Message\MessagesInterface;

$validation = (new Validator())->validate(
    data: [
        'title' => 'Pr',
        'color' => 'green',
    ],
    rules: [
        'title' => 'minLen:3|alpha',
        'color' => 'in:blue:red',        
    ]
);

$errors = $validation->errors();

var_dump($errors instanceof MessagesInterface);
// bool(true)

获取数据键的第一个错误消息

use Tobento\Service\Message\MessageInterface;

$errors = $validation->errors();

$error = $errors->key('title')->first();

var_dump($error instanceof MessageInterface);
// bool(true)
    
echo $error;
// The title must at least contain 3 chars.

查看消息服务以了解有关消息的更多信息。

检索所有数据键的所有错误消息

use Tobento\Service\Message\MessageInterface;

$errors = $validation->errors();

foreach($errors->key('title')->all() as $error) {
    var_dump($error instanceof MessageInterface);
    // bool(true)
}

查看消息服务以了解有关消息的更多信息。

确定是否存在某个数据键的消息

$errors = $validation->errors();

var_dump($errors->key('title')->has());
// bool(true)

查看消息服务以了解有关消息的更多信息。

自定义错误消息

use Tobento\Service\Validation\Validator;

$validation = (new Validator())->validate(
    data: [
        'title' => 'Pr',
        'color' => 'green',
    ],
    rules: [
        'title' => [
            'alpha',
            ['minLen', [3], 'error' => ':attribute must contain at least :parameters[0] chars!']
        ],
        'color' => 'in:blue:red',        
    ]
);

$errors = $validation->errors();

echo $errors->key('title')->first();
// The title must contain at least 3 chars!

自定义错误消息参数

use Tobento\Service\Validation\Validator;

$validation = (new Validator())->validate(
    data: [
        'title' => 'Pr',
        'color' => 'green',
    ],
    rules: [
        'title' => [
            'alpha',
            [
                'minLen',
                [3],
                ':attribute' => 'The TITLE',
                ':parameters[0]' => 3,
                'error' => ':attribute must contain at least :parameters[0] chars!'
            ]
        ],
        'color' => 'in:blue:red',        
    ]
);

$errors = $validation->errors();

echo $errors->key('title')->first();
// The TITLE must contain at least 3 chars!

全局自定义错误消息参数

您可能需要定义所有规则的全局消息参数

use Tobento\Service\Validation\Validator;

$validation = (new Validator())->validate(
    data: [
        'title' => 'Pr',
        'color' => 'green',
    ],
    rules: [
        'title' => [
            'minLen:3|alpha',
            ':attribute' => 'The TITLE',
            // you might even set a global message for all rules.
            'error' => ':attribute is invalid',
        ],
        'color' => 'in:blue:red',
    ]
);

$errors = $validation->errors();

echo $errors->key('title')->first();
// The TITLE is invalid.

跳过第一个参数

您可能需要通过将其声明为 :parameters[-1] 来跳过参数的第一个值。

use Tobento\Service\Validation\Validator;

$validation = (new Validator())->validate(
    data: [
        'title' => '',
        'color' => 'green',
    ],
    rules: [
        'title' => [
            'required_ifIn:color:green:red',
            'error' => ':attribute is required as :parameters[0] is in list :parameters[-1].',
        ],
        'color' => 'in:blue:red',
    ]
);

$errors = $validation->errors();

echo $errors->key('title')->first();
// The title is required as color is in list green, red.

已验证数据

use Tobento\Service\Validation\Validator;
use Tobento\Service\Collection\Collection;

$validation = (new Validator())->validate(
    data: [
        'title' => 'Pr',
        'color' => 'green',
    ],
    rules: [
        'title' => 'minLen:3|alpha',
        'color' => 'in:blue:red',        
    ]
);

// all validated data:
var_dump($validation->data() instanceof Collection);
// bool(true)

// all valid data:
var_dump($validation->valid() instanceof Collection);
// bool(true)

// all invalid data:
var_dump($validation->invalid() instanceof Collection);
// bool(true)

查看集合服务以了解有关集合的更多信息。

规则

规则接口

use Tobento\Service\Validation\RulesInterface;
use Tobento\Service\Validation\RuleInterface;
use Tobento\Service\Validation\RuleNotFoundException;
use Tobento\Service\Validation\InvalidRuleException;

/**
 * RulesInterface
 */
interface RulesInterface
{
    /**
     * Add a rule.
     *
     * @param string $name
     * @param mixed $rule
     * @return static $this
     */
    public function add(string $name, mixed $rule): static;

    /**
     * Returns the rule based on the specified rule.
     *
     * @param mixed $rule
     * @return RuleInterface
     *
     * @throws RuleNotFoundException
     * @throws InvalidRuleException
     */
    public function get(mixed $rule): RuleInterface;
}

默认规则

use Tobento\Service\Validation\DefaultRules;
use Tobento\Service\Validation\RulesInterface;
use Tobento\Service\Validation\RuleFactoryInterface;

$rules = new DefaultRules(
    ruleFactory: null, //null|RuleFactoryInterface
);

var_dump($rules instanceof RulesInterface);
// bool(true)

使用自动装配规则工厂

如果您使用依赖关系定义或添加“延迟”规则,则需要自动装配规则工厂。

use Tobento\Service\Validation\DefaultRules;
use Tobento\Service\Validation\AutowiringRuleFactory;

// Any PSR-11 container
$container = new \Tobento\Service\Container\Container();

$rules = new DefaultRules(
    ruleFactory: new AutowiringRuleFactory($container);
);

可用规则

以下规则是默认可用的

添加规则

您可以通过以下方式添加额外的规则。如果您添加具有依赖关系的“延迟”规则,则将需要使用自动装配规则工厂进行解析。

use Tobento\Service\Validation\DefaultRules;
use Tobento\Service\Validation\RulesInterface;
use Tobento\Service\Validation\AutowiringRuleFactory;
use Tobento\Service\Validation\Rule\Same;
use Tobento\Service\Validation\Rule\Type;

// Any PSR-11 container
$container = new \Tobento\Service\Container\Container();

$rules = new DefaultRules(
    ruleFactory: new AutowiringRuleFactory($container);
);

$rules = new DefaultRules();

$rules->add('same', new Same());

// Lazy:
$rules->add('same', Same::class);

// Custom method:
$rules->add('bool', [new Type(), 'bool']);

// Lazy custom method:
$rules->add('bool', [Type::class, 'bool']);

// Lazy custom method with unresolvable parameters:
// $rules->add('rule', [Rule::class, 'bool', ['name' => 'value']]);

// Lazy with unresolvable parameters:
// $rules->add('rule', [Rule::class, ['name' => 'value']]);

自定义规则

您可以编写自己的规则类或调整默认规则以满足您的需求。

use Tobento\Service\Validation\DefaultRules;

class CustomDefaultRules extends DefaultRules
{
    protected function getDefaultRules(): array
    {
        $rules = parent::getDefaultRules();
        
        // adding or overwriting rules.
        $rules['bool'] = [\Tobento\Service\Validation\Rule\Type::class, 'bool'];
        
        return $rules;
    }
}

$rules = new CustomDefaultRules();

规则

规则接口

use Tobento\Service\Validation\RuleInterface;

/**
 * RuleInterface
 */
interface RuleInterface
{
    /**
     * Skips validation depending on value and rule method.
     * 
     * @param mixed $value The value to validate.
     * @param string $method
     * @return bool Returns true if skip validation, otherwise false.
     */
    public function skipValidation(mixed $value, string $method = 'passes'): bool;
    
    /**
     * Determine if the validation rule passes.
     * 
     * @param mixed $value The value to validate.
     * @param array $parameters Any parameters used for the validation.
     * @return bool
     */
    public function passes(mixed $value, array $parameters = []): bool;
    
    /**
     * Returns the validation error messages.
     * 
     * @return array
     */
    public function messages(): array;    
}

通过规则

使用Passes规则可以创建任何自定义规则。

use Tobento\Service\Validation\Rule\Passes;

$validation = $validator->validating(
    value: 'foo',
    rules: [
        // rule does pass:
        new Passes(passes: true),
        
        // rule does not pass:
        new Passes(passes: false),
        
        // rule does pass:
        new Passes(passes: fn (mixed $value): bool => $value === 'foo'),
        
        // using static new method:
        Passes::new(passes: true),
    ],
);

Passes参数

以下参数可用

use Tobento\Service\Validation\Rule\Passes;
use Tobento\Service\Validation\ValidatorInterface;
use Tobento\Service\Validation\ValidationInterface;

$rule = new Passes(passes: function(
    mixed $value,
    array $parameters,
    ValidatorInterface $validator,
    ValidationInterface $validation): bool
{
    return true;
});

如果您使用自动装配规则工厂设置了验证器,则 passesskipValidation 可调用项将被自动装配

use Tobento\Service\Validation\Rule\Passes;

$rule = new Passes(passes: function(mixed $value, SomeService $service): bool {
    return true;
});

确保声明闭包类型

默认情况下,声明类型为 $value 参数的闭包将自动验证。如果不匹配输入值类型,则规则将不会通过,并且闭包将永远不会执行。

use Tobento\Service\Validation\Rule\Passes;

$rule = new Passes(passes: fn (string|int $value): bool {
    return true;
});

// you may deactivate it, but then you will need to declare the value type as mixed:
$rule = new Passes(
    passes: fn (mixed $value): bool {
        return true;
    },
    verifyDeclaredType: false,
);

自定义错误消息

您可以指定自定义错误消息

use Tobento\Service\Validation\Rule\Passes;

$rule = new Passes(
    passes: true,
    errorMessage: 'Custom error message',
);

跳过验证

您可以使用 skipValidation 参数在特定条件下跳过验证

$validation = $validator->validating(
    value: 'foo',
    rules: [
        // skips validation:
        new Passes(passes: true, skipValidation: true),
        
        // does not skip validation:
        new Passes(passes: true, skipValidation: false),
        
        // skips validation:
        new Passes(passes: true, skipValidation: fn (mixed $value): bool => $value === 'foo'),
    ],
);

自定义规则

use Tobento\Service\Validation\Rule;

class ListRule extends Rule
{
    /**
     * The error messages.
     */
    public const MESSAGES = [
        'passes' => ':attribute must be in list :parameters',
    ];
    
    /**
     * Determine if the validation rule passes.
     * 
     * @param mixed $value The value to validate.
     * @param array $parameters Any parameters used for the validation.
     * @return bool
     */
    public function passes(mixed $value, array $parameters = []): bool
    {
        return in_array($value, $parameters);
    }
}

使用多个验证方法

查看Rule\Strings的示例。

需要验证进行验证

查看Rule\Arr的示例。

需要验证器进行验证

查看Rule\Arr的示例。

在Passes时跳过验证

查看规则示例。

规则解析器

规则解析器的角色是解析规则定义

默认规则解析器

有关更多详细信息,请参阅规则定义

自定义规则解析器

您可以根据需要实现以下接口来编写自己的解析器。

use Tobento\Service\Validation\RulesParserInterface;
use Tobento\Service\Validation\ParsedRule;
use Tobento\Service\Validation\RulesParserException;

interface RulesParserInterface
{
    /**
     * Parses the rules.
     * 
     * @param string|array $rules
     * @return array<int, ParsedRule>
     *
     * @throws RulesParserException
     */
    public function parse(string|array $rules): array;
}

消息

消息用于验证错误消息
查看消息服务以了解有关消息的更多信息。

消息工厂

使用消息工厂,您可以完全控制消息的创建和修改。

use Tobento\Service\Validation\Message\MessagesFactory;
use Tobento\Service\Message\MessagesFactoryInterface;
use Tobento\Service\Message\MessageFactoryInterface;
use Tobento\Service\Message\ModifiersInterface;
use Psr\Log\LoggerInterface;

$messagesFactory = new MessagesFactory(
    messageFactory: null, // null|MessageFactoryInterface
    modifiers: null, // null|ModifiersInterface
    logger: null, // null|LoggerInterface
);

var_dump($messagesFactory instanceof MessagesFactoryInterface);
// bool(true)

$modifiers = $messagesFactory->modifiers();

var_dump($modifiers instanceof ModifiersInterface);
// bool(true)

参数说明

默认修饰符

如果您未在工厂上设置修饰符,则会添加以下修饰符

use Tobento\Service\Message\Modifiers;
use Tobento\Service\Validation\Message\RuleParametersModifier;
use Tobento\Service\Message\Modifier\ParameterReplacer;

$modifiers = new Modifiers(
    // maps :attribute, :value, :parameters
    // based on the rule parameters
    new RuleParametersModifier(),
    
    // Default parameter replacer
    new ParameterReplacer(),
);

消息翻译

如果您想翻译消息,则可以使用翻译修饰符
但是,您首先需要安装翻译服务

use Tobento\Service\Validation\Validator;
use Tobento\Service\Validation\Message\MessagesFactory;
use Tobento\Service\Validation\Message\RuleParametersModifier;
use Tobento\Service\Translation;
use Tobento\Service\Message\Modifier\Translator;
use Tobento\Service\Message\Modifier\ParameterTranslator;
use Tobento\Service\Message\Modifiers;
use Tobento\Service\Message\Modifier\ParameterReplacer;

$translator = new Translation\Translator(
    new Translation\Resources(
        new Translation\Resource('*', 'de', [
            'The :attribute must only contain letters [a-zA-Z]' => ':attribute muss aus Buchstaben [a-zA-Z] bestehen.',
            'title' => 'Titel',
        ]),       
    ),
    new Translation\Modifiers(),
    new Translation\MissingTranslationHandler(),
    'de',
);

$messagesFactory = new MessagesFactory(
    modifiers: new Modifiers(
        new Translator(translator: $translator, src: '*'),
        new RuleParametersModifier(),
        new ParameterTranslator(
            parameters: [':attribute'],
            translator: $translator,
            src: '*'
        ),
        new ParameterReplacer(),
    )
);

$validator = new Validator(messagesFactory: $messagesFactory);

$validation = $validator->validate(
    data: [
        'title' => 'P3',
    ],
    rules: [
        'title' => 'alpha',      
    ]
);

$errors = $validation->errors();

var_dump($errors->key('title')->first()->message());
// string(44) "Titel muss aus Buchstaben [a-zA-Z] bestehen."

致谢