134 lines
3.7 KiB
PHP
134 lines
3.7 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace Aether;
|
||
|
||
use Aether\Exception\ValidationFailedException;
|
||
use Hyperf\Di\Annotation\Inject;
|
||
use Hyperf\Validation\Contract\ValidatorFactoryInterface;
|
||
use Hyperf\Validation\Validator;
|
||
use Hyperf\Context\ApplicationContext;
|
||
|
||
abstract class AetherValidator
|
||
{
|
||
#[Inject]
|
||
protected ValidatorFactoryInterface $validationFactory;
|
||
|
||
/**
|
||
* 当前场景名
|
||
*/
|
||
public ?string $currentScene = null;
|
||
|
||
/**
|
||
* 待验证数据
|
||
*/
|
||
protected array $data = [];
|
||
|
||
/**
|
||
* 自定义验证规则(子类可通过该属性注册,无需重写registerRules)
|
||
* 格式:['规则名' => 闭包/类方法]
|
||
*/
|
||
protected array $customRules = [];
|
||
|
||
/**
|
||
* 静态快捷验证方法(简化调用)
|
||
*/
|
||
public static function validate(string $scene, array $data = []): array
|
||
{
|
||
// return (new static())->scene($scene, $data)->check();
|
||
// 从容器中获取当前类的实例(确保依赖注入生效)
|
||
$instance = ApplicationContext::getContainer()->get(static::class);
|
||
return $instance->scene($scene, $data)->check();
|
||
}
|
||
|
||
/**
|
||
* 设置验证场景和数据(支持链式调用)
|
||
*/
|
||
public function scene(string $scene, array $data = []): self
|
||
{
|
||
$this->currentScene = $scene;
|
||
$this->data = $data;
|
||
return $this;
|
||
}
|
||
|
||
/**
|
||
* 执行验证(失败抛出异常)
|
||
*/
|
||
public function check(): array
|
||
{
|
||
if (empty($this->currentScene)) {
|
||
throw new \RuntimeException('请先设置验证场景');
|
||
}
|
||
|
||
$scenes = $this->scenes();
|
||
if (!isset($scenes[$this->currentScene])) {
|
||
throw new \RuntimeException("验证场景不存在:{$this->currentScene}");
|
||
}
|
||
|
||
$sceneConfig = $scenes[$this->currentScene];
|
||
return $this->validateData(
|
||
$this->data,
|
||
$sceneConfig['rules'],
|
||
$sceneConfig['messages'] ?? [],
|
||
$sceneConfig['attributes'] ?? []
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 实际执行验证的逻辑(重命名方法名更清晰)
|
||
*/
|
||
protected function validateData(array $data, array $rules, array $messages = [], array $attributes = []): array
|
||
{
|
||
$validator = $this->validationFactory->make($data, $rules, $messages, $attributes);
|
||
$this->registerRules($validator);
|
||
|
||
if ($validator->fails()) {
|
||
throw new ValidationFailedException(
|
||
$validator,
|
||
$this->currentScene ?? '',
|
||
$validator->errors()->first()
|
||
);
|
||
}
|
||
|
||
return $validator->validated();
|
||
}
|
||
|
||
/**
|
||
* 格式化验证错误信息(统一格式,供异常处理器复用)
|
||
*/
|
||
public function formatValidationErrors(Validator $validator): array
|
||
{
|
||
$errors = [];
|
||
$failedRules = $validator->failed();
|
||
$errorMessages = $validator->errors()->getMessages();
|
||
$attributes = $validator->attributes();
|
||
|
||
foreach ($failedRules as $field => $rules) {
|
||
$errors[] = [
|
||
'field' => $field,
|
||
'field_label' => $attributes[$field] ?? $field,
|
||
'message' => $errorMessages[$field][0] ?? '',
|
||
'rules' => array_keys($rules),
|
||
'value' => $validator->getValue($field)
|
||
];
|
||
}
|
||
|
||
return $errors;
|
||
}
|
||
|
||
/**
|
||
* 自动注册自定义规则(优先使用$customRules属性)
|
||
*/
|
||
protected function registerRules(Validator $validator): void
|
||
{
|
||
foreach ($this->customRules as $ruleName => $rule) {
|
||
$validator->extend($ruleName, $rule);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 定义场景验证规则(子类实现)
|
||
*/
|
||
abstract protected function scenes(): array;
|
||
} |