You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
4.9 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Helper;
use App\Annotation\Validation\After;
use App\Exception\BusinessException;
use App\Exception\ValidationException;
use Hyperf\Contract\ValidatorInterface;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\Contracts\MessageBag;
use Hyperf\Validation\Contract\ValidatorFactoryInterface;
class Form implements Logic
{
/**
* @Inject
* @var ValidatorFactoryInterface
*/
protected $validationFactory;
protected $_data = [];
protected $scene;
protected $isCheckScene;
protected $scenes = [];
/**
* @var ValidatorInterface $validator
*/
protected $validator;
/**
* @param array $data 表单数据
*/
public function __construct(array $data = [])
{
foreach ($this->defaults() as $key => $value) {
if (isset($data[$key])) {
if (empty($value) && empty($data[$key])) {
$data[$key] = $value;
}
} else {
$data[$key] = $value;
}
}
$this->_data = $data;
}
/**
* 设置表单参数默认值,暂不支持多维数组
* @return array
*/
public function defaults(): array
{
return [];
}
public function rules(): array
{
return [];
}
public function messages(): array
{
return [];
}
public function attributes(): array
{
return [];
}
protected function before()
{
}
protected final function handleBefore()
{
$this->before();
$this->checkScene();
}
protected function getRules()
{
$rules = $this->rules();
$scene = $this->getScene();
if ($scene && isset($this->scenes[$scene]) && is_array($this->scenes[$scene])) {
$newRules = [];
foreach ($this->scenes[$scene] as $field) {
if (array_key_exists($field, $rules)) {
$newRules[$field] = $rules[$field];
}
}
return $newRules;
}
return $rules;
}
public final function validate($throwException = true)
{
$this->handleBefore();
$this->validator = $this->validationFactory->make($this->_data, $this->getRules(), $this->messages(), $this->attributes());
$this->handleAfter();
$fails = $this->validator->fails();
if ($throwException && $fails) {
throw new BusinessException($this->getErrorMessage());
}
return !$fails;
}
protected function after()
{
}
protected final function handleAfter()
{
$this->validator->after(function ($validator) {
$items = Annotation::getMethodsByAnnotationAndClass(After::class, static::class);
foreach ($items as $item) {
if (empty($item['annotation']->scenes) || in_array($this->scene, $item['annotation']->scenes)) {
$this->{$item['method']}();
}
}
});
$this->after();
}
public function addError($field, $message)
{
$this->validator->errors()->add($field, $message);
}
public function errors(): MessageBag
{
return $this->validator->errors();
}
public function getErrorMessage($isAll = false): string
{
if ($this->errors()->count() > 0) {
$messages = $this->errors()->all();
return $isAll ? implode('', $messages) : $messages[0];
}
return '';
}
public final function getData()
{
return $this->_data;
}
public final function getSceneData()
{
$scene = $this->getScene();
if ($scene && isset($this->scenes[$scene]) && is_array($this->scenes[$scene])) {
$newData = [];
foreach ($this->scenes[$scene] as $field) {
if (array_key_exists($field, $this->_data)) {
$newData[$field] = $this->_data[$field];
}
}
return $newData;
}
return $this->_data;
}
/**
* @param string $scene 场景名称
* @param bool $isCheckScene 是否检查场景是否存在
*/
public final function setScene(string $scene, bool $isCheckScene = true): void
{
$this->scene = $scene;
$this->isCheckScene = $isCheckScene;
}
protected final function checkScene()
{
if ($this->getScene() && $this->isCheckScene && !isset($this->scenes[$this->scene])) {
throw new BusinessException('Scene undefined!');
}
}
public final function getScene()
{
return $this->scene;
}
public function __get($key)
{
return isset($this->_data[$key]) ? $this->_data[$key] : null;
}
public function __set($key, $value)
{
$this->_data[$key] = $value;
}
public function __isset($key)
{
return $this->__get($key);
}
}