thinkphp 自定义命令生成验证器文件

命令demo 

php think hello(指令) --table 表名 

代码如下

<?php
declare (strict_types=1);

namespace app\command;

use DateTime;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use think\facade\Db;
use think\helper\Str;

class Hello extends Command
{
    protected $rules = [];
    #命名空间
    private $namespace = 'app\\validate';
    #文件名称
    private $fileName = '';

    protected function setFileName()
    {
        $this->fileName = Str::studly($this->table) . "Validate";
    }

    protected function configure()
    {
        // 指令配置
        $this->setName('hello')
            ->addOption('table', null, Option::VALUE_REQUIRED, '表名')
            ->setDescription('自动生成验证器');
    }


    protected function execute(Input $input, Output $output)
    {
        try {
            $this->namespace = 'app\\validate';
            if (!$input->hasOption('table')) {
                throw new \think\Exception('--table参数不能为空', 10006);
            }
            $this->table = $input->getOption('table');
            $this->setFileName();
            $database = config('database.connections.mysql.database');
            $tableArr = Db::query("SELECT TABLE_NAME FROM information_schema.TABLES WHERE  TABLE_SCHEMA = '{$database}' and  TABLE_NAME = '{$this->table}';");
            if (0 === count($tableArr)) {
                throw new \think\Exception($this->table . "表不存在", 10006);
            }
            $comments = Db::query("SHOW FULL COLUMNS FROM `{$this->table}`");
            foreach ($comments as $v) {
                if ('PRI' === $v['Key']) continue;
                $this->rules[$v['Field']] = ['name' => $this->getColumnName($v), "rule" => []];
                $columnFullType = $v['Type'];
                $preg = "/^(\w+)\(?/";
                if (preg_match($preg, $columnFullType, $matches)) {
                    $columnType = $matches[1];
                } else {
                    throw new \think\Exception('未找到字段类型', 10006);
                }
//            if ('NO' === $v['Null']) {
//                $this->rules[$v['Field']]['rule'][] = 'require';
//            }
                $this->rules[$v['Field']]['rule'][] = 'require';
                if ($this->containsPhoneOrMobile($v['Comment'])) {
                    $this->rules[$v['Field']]['rule'][] = 'mobile';
                }

                if ($this->email($v['Comment'])) {
                    $this->rules[$v['Field']]['rule'][] = 'email';
                }

                switch ($columnType) {
                    case 'int':
                    case 'bigint':
                    case 'tinyint':
                        $this->setIntColumnRule($v, $columnType);
                        break;
                    case 'char':
                    case 'varchar':
                        $this->setCharColumnRule($v, $columnType);
                        break;
                    case 'tinytext':
                    case 'text':
                    case 'mediumtext':
                    case 'longtext':
                        $this->setTextColumnRule($v, $columnType);
                        break;
                    case 'float':
                    case 'double':
                        throw new \think\Exception('浮点型只支持decimal类型', 10006);
                    case 'decimal':
                        $this->setFloatColumnRule($v, $columnType);
                        break;
                    case 'date':
                        $this->rules[$v['Field']]['rule'][] = 'checkDateYmd:' . $this->getColumnName($v) . '时间格式不对';
                        break;
                    case 'datetime':
                        $this->rules[$v['Field']]['rule'][] = 'checkDateYmdHis:' . $this->getColumnName($v) . '时间格式不对';
                        break;
                    default:
                        throw new \think\Exception("未找到字段{$columnType}类型请完善", 10006);
                }
            }
            $content = $this->generateValidatorContent();
            !is_dir($this->namespace) && mkdir($this->namespace, 0755, true);

            $pathname = $this->namespace . '\\' . $this->fileName;
            if (is_file($pathname . '.php')) {
                throw new \think\Exception("该文件已经存在" . $pathname. '.php', 10006);
            }

            file_put_contents($pathname . '.php', $content);
            $output->writeln("创建成功");
        } catch (\Throwable $e) {
            $output->writeln($e->getMessage());
        }
    }

    protected function setIntColumnRule($v, $columnType)
    {
        if ($this->unsigned($v['Type'])) {
            $this->rules[$v['Field']]['rule'][] = 'egt:0';
            $this->rules[$v['Field']]['rule'][] = 'number';
            $this->rules[$v['Field']]['rule'][] = 'between:' . $this->getIntBetween($columnType, 'unsignen');
        } else {
            $this->rules[$v['Field']]['rule'][] = 'integer';
            $this->rules[$v['Field']]['rule'][] = 'between:' . $this->getIntBetween($columnType, 'signen');
        }
    }

    protected function setTextColumnRule($v, $columnType)
    {
        $this->rules[$v['Field']]['rule'][] = $this->getTextBetween($columnType);
    }

    function containsPhoneOrMobile($str)
    {
        $lowerStr = strtolower($str);
        if (strpos($lowerStr, 'phone') !== false) {
            return true;
        }
        if (mb_strpos($lowerStr, '手机号') !== false) {
            return true;
        }
        return false;
    }


    function email($str)
    {
        $lowerStr = strtolower($str);
        if (strpos($lowerStr, 'email') !== false) {
            return true;
        }
        if (mb_strpos($lowerStr, '邮箱') !== false) {
            return true;
        }
        return false;
    }

    protected function setCharColumnRule($v, $columnType)
    {
        $preg = "/^(?:var)?char\((\d+)\)/";
        if (preg_match($preg, $v['Type'], $matches)) {
            $charLength = $matches[1];
        } else {
            throw new \think\Exception('char未匹配到长度', 10006);
        }

        $this->rules[$v['Field']]['rule'][] = 'length:0,' . $charLength;
    }

    protected function setFloatColumnRule($v, $columnType)
    {
        $preg = "/^decimal\((\d+),(\d+)\)/";
        if (preg_match($preg, $v['Type'], $matches)) {
            if ("2" !== $matches[2]) {
                throw new \think\Exception('decimal必须小数点两位', 10006);
            }
            $float = $matches[1];
        } else {
            throw new \think\Exception('decimal不能正确匹配', 10006);
        }
        $columnName = $this->getColumnName($v);
        if ($this->unsigned($v['Type'])) {
            $this->rules[$v['Field']]['rule'][] = "checkFloat2:{$float}@{$columnName}小数点后面最多两位的数字";
        } else {
            $this->rules[$v['Field']]['rule'][] = "checkUnsignedFloat2:{$float}@{$columnName}小数点后面最多两位的数字";
        }
    }


    public function getIntBetween($type, $unsignen)
    {
        if (isset($this->intArrBetween[$type][$unsignen])) {
            return $this->intArrBetween[$type][$unsignen];
        }
        throw new \think\Exception('未找到' . $type . '字段类型的取值范围', 10006);
    }


    public function getTextBetween($type)
    {
        if (isset($this->textArrBetween [$type])) {
            return $this->textArrBetween [$type];
        }
        throw new \think\Exception('未找到' . $type . '字段类型的取值范围', 10006);
    }


    protected function unsigned($string)
    {
        if (strpos($string, 'unsigned') !== false) return true;
        return false;
    }


    protected function getColumnName($columnData)
    {
        $Comment = $columnData['Comment'];
        $preg = "/^([^-]*)-?/";
        if (preg_match($preg, $Comment, $matches)) {
            return $matches[1] === '' ? $columnData['Field'] : $matches[1];
        } else {
            return $columnData['Field'];
        }
    }

    protected function generateValidatorContent()
    {
        $ruleStrContent = <<<RULE
    protected \$rule = [
REPLACE
    ];\n
RULE;

        $messageStrContent = <<<CONTENT
    protected \$message = [
REPLACE
    ];\n
CONTENT;


        $ruleStr = '';
        $contentStr = '';
        foreach ($this->rules as $k => $v) {
            $ruleContent = implode("|", $v['rule']);
            $ruleStr .= "\t\t\t'{$k}'  =>  '{$ruleContent}',#{$v['name']}\n";
            foreach ($v['rule'] as $key => $value) {
                $ruleMsg = explode(':', $value);
                $msg = '';
                switch ($ruleMsg[0]) {
                    case 'number':
                        $msg = "必须是正整数";
                        break;
                    case 'date':
                        $msg = "日期格式不对";
                        break;
                    case 'between':
                        $fanwei = str_replace(',', '~', $ruleMsg[1]);
                        $msg = "必须在{$fanwei}内";
                        break;
                    case 'integer':
                        $msg = "必须为整数";
                        break;
                    case 'egt':
                        $msg = "大于等于0";
                        break;
                    case 'require':
                        $msg = "不能为空";
                        break;
                    case 'mobile':
                        $msg = "格式错误";
                        break;
                    case 'email':
                        $msg = "格式错误";
                        break;
                }
                if ($msg) {
                    $contentStr .= "\t\t\t'{$k}.{$ruleMsg[0]}' => '{$v['name']}{$msg}',#{$v['name']}\n";
                }
            }
        }
        $ruleStr = str_replace('REPLACE', $ruleStr, $ruleStrContent);
        $messageStr = str_replace('REPLACE', $contentStr, $messageStrContent);


        return "<?php
namespace $this->namespace;
use DateTime;
use think\Validate;

class " . Str::studly($this->table) . "Validate extends Validate
{
    $ruleStr
    $messageStr
    public function sceneAdd()
    {
    	return \$this->only([]);
    }
    public function sceneEdit()
    {
    	return \$this->only([]);
    }   

    protected function checkFloat2(\$value, \$rule, \$data=[])
    {
        \$arr = explode('@',\$rule);
        \$pattern = '/^(0|[1-9]\d*)(\.\d{1,2})?$/';
        if (!preg_match(\$pattern, \$value)) {
            return \$arr[1];
        }
        if(strlen((int)\$value)>(\$arr[0]-2)){
            return \$arr[1];
        }
        return true;
    }

    protected function checkUnsignedFloat2(\$value, \$rule, \$data=[])
    {
        \$arr = explode('@',\$rule);
        \$pattern = '/^(?:\-)?(0|[1-9]\d*)(\.\d{1,2})?$/';
        if (!preg_match(\$pattern, \$value)) {
            return \$arr[1];
        }
        if(strlen((int)\$value)>(\$arr[0]-2)){
            return \$arr[1];
        }
        return true;
    }
    
        protected function checkDateYmd(\$value, \$rule, \$data = [])
    {
        DateTime::createFromFormat('Y-m-d', \$value);
        \$errors = DateTime::getLastErrors();
        if ((\$errors['warning_count'] + \$errors['error_count']) > 0) {
            return \$rule;
        }
        return true;
    }

    protected function checkDateYmdHis(\$value, \$rule, \$data = [])
    {
        DateTime::createFromFormat('Y-m-d H:i:s', \$value);
        \$errors = DateTime::getLastErrors();
        if ((\$errors['warning_count'] + \$errors['error_count']) > 0) {
            return \$rule;
        }
        return true;
    }


}
";
    }

    private $intArrBetween = [
        'int' => [
            'unsignen' => '0,4294967295',
            'signen' => "-2147483648,2147483647",
        ],
        'bigint' => [
            'unsignen' => '0,12345678901234567890',
            'signen' => "-1234567890123456789,1234567890123456789",
        ]
        ,
        'tinyint' => [
            'unsignen' => '0,255',
            'signen' => "-128,127",
        ]
    ];


    private $textArrBetween = [
        'tinytext' => '0,255',
        'text' => '0,65535',
        'mediumtext' => '0,16777215',
        'longtext' => '0,4294967295',
    ];
}

  

posted @ 2024-12-25 16:51  酷酷的城池  阅读(1)  评论(0编辑  收藏  举报