ThinkPHP场景动态验证

一、缘由

今天在用thinkphp8写东西的时候发现,写验证器规则和场景优点费时间,就算用tinkphp的命令行生成也是生成一个空壳。内容还是要自己填写感觉麻烦。
就突发奇想能不能自动生成验证器,也不能是说自动生成验证器,生成验证其的话还是要生成相关的文件,这块因为没弄过就略过
就是说能写一个公共的动态验证器 然后规则场景啥的手动输入表名,场景规则和需要使用的场景。经过我小半天的尝试,初见成效,话不多说 上代码

二、实现

实现步骤

1、创建正常的验证器的模式

包含rule(规则) message(提示信息) scene(场景)

代码示例



namespace app\services;
use think\Validate;
class AdminValidatee extends Validate
{
    /**
     * 定义验证规则
     * 格式:'字段名' =>  ['规则1','规则2'...]
     *
     * @var array
     */
    protected $rule = [];

    /**
     * 定义错误信息
     * 格式:'字段名.规则名' =>  '错误信息'
     *
     * @var array
     */
    protected $message = [];
}

2、添加验证场景

代码示例

namespace app\services;
use think\Validate;
class AdminValidatee extends Validate
{
    /**
     * 定义验证规则
     * 格式:'字段名' =>  ['规则1','规则2'...]
     *
     * @var array
     */
    protected $rule = [];

    /**
     * 定义错误信息
     * 格式:'字段名.规则名' =>  '错误信息'
     *
     * @var array
     */
    protected $message = [];
    /**
     * 定义验证场景
     * 格式:'场景名' => ["字段1","字段2"]
     *
     * @var array
     */
	protected $scene= [];
}

3、创建一个获取表结构的方法

用户动态获取表的结构,包括字段,字段类型

代码示例

    // 获取表结构信息
        $sql="SELECT COLUMN_NAME ,COLUMN_TYPE ,IS_NULLABLE ,COLUMN_DEFAULT ,COLUMN_COMMENT 
              FROM information_schema.COLUMNS
              WHERE TABLE_SCHEMA = '$databaseName' AND TABLE_NAME ='$tableName'";
        // 获取表结构信息
        $columns = Db::query($sql);
        $rules = [];
        $messages = [];

        foreach ($columns as $column) {
            $field = $column['COLUMN_NAME'];//字段名
            $fieldName = $column['COLUMN_COMMENT'];//注释
            $type = $column['COLUMN_TYPE'];//字段类型
            $isNullable = $column['IS_NULLABLE'] === 'YES' ? true : false;//是不是为null
            // 根据字段类型和表结构自动生成验证规则
            $rule = 'require';

            // 如果字段允许为空,则移除 'require' 规则
            if ($isNullable) {
                $rule = 'nullable';
            }

            if (strpos($type, 'varchar') !== false || strpos($type, 'text') !== false) {
                $rule .= '|length:1,255';  // 字符串类型添加长度验证
            }

            if (strpos($type, 'int') !== false) {
                $rule .= '|number';  // 整数类型字段添加数字验证
            }

            // 针对 email 字段,增加邮箱格式验证
            if ($field == 'email') {
                $rule .= '|email';
            }
            // 添加到验证规则数组
            $rules[$field] = $rule;
            $messages[$field] = ucfirst($fieldName.$field) . ' is required and should be of valid format';
        }
        return ['rules' => $rules, 'messages' => $messages];
   

4、创建验证方法

/**
     * 验证
     * User: MirGao
     * Date: 2024/12/3
     * Time: 14:58
     * @param $param
     * @param $scene
     * @return void
     */
    public function validate($param,$scene){
        if(!self::scene($scene)->check($param)){
            exit(json_encode(['code'=>'203','message'=>Validate::getError(),'data'=>[]]));
        }
    }

5、接收实例化传过来的参数用构造函数进行赋值

//参数为表名和验证场景
    public function __construct($table,$sceneRule)
    {
        parent::__construct();
        //通过表名动态获取表结构
        $data=self::getValidate($table);
        //赋值规则
        $this->rule=$data['rules'];
        //赋值提示信息
        $this->message=$data['messages'];
        //赋值验证场景
        $this->scene=$sceneRule;
    }

6、完整代码


/**
 * Notes:
 * User: 14736
 * Date: 2024/12/3
 * Time: 13:46
 * @return
 */

namespace app\services;

use think\facade\Db;
use think\Validate;

class ValidateService extends Validate
{
    protected $rule = [];
    protected $message = [];
    protected $scene  = [];
	//参数为表名和验证场景
    public function __construct($table,$sceneRule)
    {
        parent::__construct();
        //通过表名动态获取表结构
        $data=self::getValidate($table);
        //赋值规则
        $this->rule=$data['rules'];
        //赋值提示信息
        $this->message=$data['messages'];
        //赋值验证场景
        $this->scene=$sceneRule;
    }

    /**
     * 获取表结构数据
     * User: MirGao
     * Date: 2024/12/3
     * Time: 14:58
     * @param $tableName 表名
     * @return array[]
     */
    static public function getValidate($tableName){
          // 获取表结构信息
        $sql="SELECT COLUMN_NAME ,COLUMN_TYPE ,IS_NULLABLE ,COLUMN_DEFAULT ,COLUMN_COMMENT 
              FROM information_schema.COLUMNS
              WHERE TABLE_SCHEMA = 'questions' AND TABLE_NAME ='$tableName'";
        // 获取表结构信息
        $columns = Db::query($sql);
        $rules = [];
        $messages = [];
        foreach ($columns as $column) {
            $field = $column['COLUMN_NAME'];
            $fieldName = $column['COLUMN_COMMENT'];
            $type = $column['COLUMN_TYPE'];
            $isNullable = $column['IS_NULLABLE'] === 'YES' ? true : false;
            // 根据字段类型和表结构自动生成验证规则
            $rule = 'require';

            // 如果字段允许为空,则移除 'require' 规则
            if ($isNullable) {
                $rule = 'nullable';
            }

            if (strpos($type, 'varchar') !== false || strpos($type, 'text') !== false) {
                $rule .= '|length:1,255';  // 字符串类型添加长度验证
            }

            if (strpos($type, 'int') !== false) {
                $rule .= '|number';  // 整数类型字段添加数字验证
            }

            // 针对 email 字段,增加邮箱格式验证
            if ($field == 'email') {
                $rule .= '|email';
            }
            // 添加到验证规则数组
            $rules[$field] = $rule;
            $messages[$field] = ucfirst($fieldName.$field) . ' is required and should be of valid format';
        }
        return ['rules' => $rules, 'messages' => $messages];

    }

    /**
     * 验证
     * User: MirGao
     * Date: 2024/12/3
     * Time: 14:58
     * @param $param
     * @param $scene
     * @return void
     */
    public function validate($param,$scene){
        if(!self::scene($scene)->check($param)){
            exit(json_encode(['code'=>'203','message'=>Validate::getError(),'data'=>[]]));
        }
    }
}

三、调用

客户端示例

  <?php
/**
 * Notes:
 * User: 14736
 * Date: 2024/12/3
 * Time: 13:17
 * @return
 */

namespace app\admin\controller;

use app\admin\model\AdminModel;
use app\admin\validate\AdminValidate;
use app\services\JsonResponse;
use app\services\JwtService;
use app\services\ValidateService;
use think\Request;

class LoginController
{
	//定义验证场景
    protected  $sceneRule=[];
    public function __construct(){
    	//根据业务进行添加场景
        $this->sceneRule=[
            'login'=>['admin_account','admin_password']
        ];
    }
    /**
     * 登录
     * User: MirGao
     * Date: 2024/12/3
     * Time: 15:04
     * @param Request $request
     * @param JwtService $jwtService
     * @param AdminModel $adminModel
     * @return \think\response\Json
     */
    public function login(Request $request ,JwtService $jwtService,AdminModel $adminModel){
        $param=$request->post();
        //传入表名 验证场景
        $validate=new ValidateService('system_admin',$this->sceneRule);
        $validate->validate($param,'login');
        $adminId='查询语句';
        if(empty($adminId)){
            return JsonResponse::error('用户不存在');
        }
        $token= $jwtService->getToken($adminId);
        return JsonResponse::successData(['token'=>$token]);
    }
    
}

接口调用示例

ThinkPHP场景动态验证_第1张图片

四、总结

优点

1、写起来简便,完成一个公共验证文件后只需要传入 表明和验证场景并调用验证场景中的相关规则即可完成验证
2、无需关心表的结构变化

缺点

1、每次调用都会去查询数据库性能开销有点大
2、耦合性很高 所有的验证都走这一个方法调试时会比较差异化
3、要求开发者建表时要按照规范,写字段注释

优化

针对于每次验证都需要查询表结构,建议上缓存,查询后把表结构放在缓存里,当表结构发生变化时需要及时更新缓存,如果有更好的想法欢迎交流

你可能感兴趣的:(学习,android,java)