123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605 |
- <?php
- namespace Qii\Driver\Entity;
- use Qii\Driver\Model;
- use Qii\Driver\Response;
- /**
- * 通过数据表生成 entity
- * 使用方法:
- * use Qii\Driver\Entity\Entity;
- * $entity = new Entity();
- * $class = $entity->generateProperties($table);
- * file_put_contents('entity/'. $table . '.php', $class);
- *
- * $fields = $entity->generateField('\entity\'. $table);
- * print_r($fields);
- *
- * entity 生成规则:
- * 首字母、下划线+字母 -> 大写字母
- */
- class Entity {
- /**
- * @var bool $ucFirst 首字母是否大写
- */
- public $ucFirst = true;
- public $namespace = "entity";
- public function __construct(){
- }
- public function db() {
- return _loadClass('\Qii\Driver\Model');
- }
- /**
- * 设置 entity 的名字空间
- * @param string $namespace 名字空间
- * @return void
- */
- public function setNamespace($namespace) {
- $this->namespace = $namespace;
- }
- /**
- * 通过 Entity 获取数据表的字段
- *
- * @param $class
- * @return array
- * @throws \ReflectionException
- */
- public function generateField($class) {
- if(!$class) {
- throw new \Exception('Class is null');
- }
- if(class_exists($class, false)) {
- throw new \Exception('Class '. $class .' does not exist');
- }
- $method = new \ReflectionClass($class);
- $properties = $method->getProperties();
- $fields = [];
- foreach($properties as $property) {
- if($property->isPublic()) {
- $fields[] = $this->convertToField($property->getName());
- }
- }
- return $fields;
- }
- /**
- * 将数据表生成entity
- *
- * @param string $table 表名
- * @return string
- * @throws \Exception
- */
- public function generateProperties($table, $className = '') {
- $db = $this->db();
- $tableInfo = $db->getTableInfo($table);
- if($db->isError()) {
- throw new \Exception($db->getError());
- }
- if(!$tableInfo || empty($tableInfo['fields'])) {
- throw new \Exception($table . ' does not have any field');
- }
- $properties = [];
- $docs = [];
- $defaults = [];
- foreach ($tableInfo['fields'] as $field) {
- $comment = $tableInfo['comment'][$field] ?? '';
- $convertField = $this->convertToProperty($field);
- $comment = strlen($comment) > 0 ? " ". $comment : "";
- $doc = [];
- if(($tableInfo['rules']['int'] && isset($tableInfo['rules']['int'][$field])) ||
- ($tableInfo['rules']['number'] && isset($tableInfo['rules']['number'][$field]))
- ) {
- $doc[] = "\t/**";
- $doc[] = "\t * @var int ". $convertField . $comment;
- $doc[] = "\t */";
- } else if (($tableInfo['rules']['maxlength'] && isset($tableInfo['rules']['maxlength'][$field]))
- || ($tableInfo['rules']['text'] && in_array($field, $tableInfo['rules']['text']))
- ) {
- $doc[] = "\t/**";
- $doc[] = "\t * @var string ". $convertField . $comment;
- $doc[] = "\t */";
- } else if ($tableInfo['rules']['timestamp'] && in_array($field, $tableInfo['rules']['timestamp'])) {
- $doc[] = "\t/**";
- $doc[] = "\t * @var datetime ". $convertField . $comment;
- $doc[] = "\t */";
- } else if($tableInfo['rules']['float'] && isset($tableInfo['rules']['float'][$field])) {
- $doc[] = "\t/**";
- $doc[] = "\t * @var float ". $convertField . $comment;
- $doc[] = "\t */";
- }else if($tableInfo['rules']['decimal'] && isset($tableInfo['rules']['decimal'][$field])) {
- $doc[] = "\t/**";
- $doc[] = "\t * @var decimal ". $convertField . $comment;
- $doc[] = "\t */";
- }
- if($tableInfo['rules']['default'] && isset($tableInfo['rules']['default'][$field])) {
- $default = $tableInfo['rules']['default'][$field];
- $defaults[$convertField] = $default;
- }
- if(count($doc) > 0) {
- $docs[$convertField] = join("\n", $doc);
- }
- $properties[] = $convertField;
- }
- $class = $className != '' ? $this->convertToProperty($className) : $this->convertToProperty($table);
- $classAndProperty = [];
- $classAndProperty[] = "<?php";
- $classAndProperty[] = "namespace ". $this->namespace . ";";
- $classAndProperty[] = "\n";
- $classAndProperty[] = "use Qii\Driver\Entity\Inf;";
- $classAndProperty[] = "use Qii\Driver\Entity\Base;";
- $classAndProperty[] = "use Qii\Driver\Response;";
- $classAndProperty[] = "\n";
- $classAndProperty[] = <<<DOC
- /**
- * @method \$this setWhereHooker(callable \$func)
- * @method \$this setOrderHooker(callable \$func)
- * @method \$this setLimitHooker(callable \$func)
- * @method \$this setCacheHooker(callable \$func)
- * @method \$this setQueryFieldsHooker(callable \$func)
- * @method \$this clear()
- * @method array properties()
- * @method bool exit()
- * @method \$this get()
- * @method Response info()
- * @method Response add()
- * @method Response remove()
- * @method Response update()
- * @method Response updateFields()
- * @method Response incr()
- * @method Response first()
- * @method Response last()
- * @method array lists(int \$page, int \$pageSize)
- * @method array listAll()
- * @method Object rs()
- * @method Response valids
- * @method array initPages(array \$data, int \$count, int \$page, int \$pageSize)
- */
- DOC;
- $classAndProperty[] = 'class '. $class . ' extends Base implements Inf{';
- $dynamicProperty = [];
- foreach ($properties as $property) {
- if(isset($docs[$property])) {
- $classAndProperty[] = $docs[$property];
- }
- /*if(isset($defaults[$property])) {
- $default = $defaults[$property];
- if($default == 'CURRENT_TIMESTAMP') {
- $dynamicProperty[$property] = $default;
- }
- $classAndProperty[] = "\t". 'public $'. $property . " = '". $default . "';\n";
- }else{
- $classAndProperty[] = "\t". 'public $'. $property . ";";
- }*/
- $classAndProperty[] = "\t". 'public $'. $property . ";";
- if(isset($defaults[$property])) {
- $dynamicProperty[$property] = $defaults[$property];
- }
- }
- if(count($dynamicProperty)) {
- $classAndProperty[] = <<<DOC
- /**
- * 动态变化的日期,初始化的时候赋值
- */
- DOC;
- $classAndProperty[] = "\tpublic function __construct(){";
- $classAndProperty[] = "\n";
- $classAndProperty[] = "\t}";
- $classAndProperty[] = "\t/**";
- $classAndProperty[] = "\t * 设置默认值";
- $classAndProperty[] = "\t */";
- $classAndProperty[] = "\tpublic function defaultFieldsValue(){";
- $classAndProperty[] = "\t\t\$defaultValue = [];";
- foreach ($dynamicProperty as $property => $dynamic) {
- if($dynamic == 'CURRENT_TIMESTAMP') {
- $classAndProperty[] = "\t\t" . '$defaultValue[\''. $property ."'] = date('Y-m-d H:i:s');";
- }else{
- $classAndProperty[] = "\t\t" . '$defaultValue[\''. $property ."'] = '". str_replace("'", "\\'", $dynamic)."';";
- }
- }
- $classAndProperty[] = "\t\treturn \$defaultValue;";
- $classAndProperty[] = "\t}";
- }
- $classAndProperty[] = <<<DOC
- \t/**
- \t * 获取表名
- \t */
- \tpublic function getTable(){
- \t\treturn '{$table}';
- \t}
- DOC;
- //生成 table rules
- $classAndProperty[] = $this->generateRules($tableInfo);
- $classAndProperty[] = '}';
- return join("\n", $classAndProperty);
- }
- public function generateRules($tableInfo){
- $constantJoin[] = <<<DOC
- /**
- * 字段验证数据规则
- */
- public function rules() {
- DOC;
- $constantJoin[] = "\t\t". '$rules = [];';
- $next = array_reduce(array_reverse(['required', 'int', 'minlength', 'maxlength', 'decimal', 'timestamp', 'datetime']), function($carry, $item){
- return function() use ($carry, $item){
- $tableInfo = func_get_args()[0];
- $constantJoin = func_get_args()[1];
- $currentRules = $tableInfo['rules'][$item];
- $comments = $tableInfo['comment'];
- $join = [];
- switch ($item) {
- case 'required':
- $join = $this->generateRequired($currentRules, $comments);
- break;
- case 'int':
- $join = $this->generateInt($currentRules, $comments);
- break;
- case 'decimal':
- $join = $this->generateDecimal($currentRules, $comments);
- break;
- case 'minlength':
- $join = $this->generateMinLength($currentRules, $comments);
- break;
- case 'maxlength':
- $join = $this->generateMaxLength($currentRules, $comments);
- break;
- case 'timestamp':
- case 'datetime':
- $join = $this->generateDatetime($currentRules, $comments);
- }
- if(!empty($join)) {
- $constantJoin = array_merge($constantJoin, $join);
- }
- return $carry($tableInfo, $constantJoin);
- };
- }, function($tableInfo, $constantJoin){
- return $constantJoin;
- })($tableInfo, $constantJoin);
- $next[] = "\t\treturn ". '$rules;';
- $next[] = "\t". '}';
- //主键自动添加
- $primaryKey = array();
- if(isset($tableInfo['rules']['pri'])) {
- $primaryKey = $tableInfo['rules']['pri'];
- }
- //保存验证的时候使用 required 并去掉pri和default里边的内容
- $defaults = array();
- if(isset($tableInfo['rules']['default'])) {
- $defaults = array_keys($tableInfo['rules']['default']);
- }
- $validForSave = array();
- if(isset($tableInfo['rules']) && isset($tableInfo['rules']['required'])) {
- foreach ($tableInfo['rules']['required'] as $field) {
- if(!in_array($field, $primaryKey) && !in_array($field, $defaults)) {
- $validForSave[] = $this->convertToProperty($field);
- }
- }
- }
- $uniKey = array();
- if(isset($tableInfo['rules']) && isset($tableInfo['rules']['uniq'])) {
- foreach ($tableInfo['rules']['uniq'] as $uniq) {
- $uniKey[] = $this->convertToProperties($uniq);
- }
- }
- $next[] = <<<DOC
- /**
- * unique (unique 如果是 array 则表示 联合唯一,如果是string则是任意唯一,多个单独唯一使用字符串以逗号隔开, 主键除外)
- * array(array1, array2) , array1 和array 2单独唯一
- * @return mixed
- * @throws \Exception
- */
- public function uniqueKey(){
- DOC;
- if(count($uniKey) > 0) {
- $uniq = array();
- foreach ($uniKey as $val) {
- $uniq[] = "array('". join("','", $val). "')";
- }
- $next[] = "\t\treturn array(". join(", ", $uniq). ");";
- }else{
- $next[] = <<<DOC
- return array();
- DOC;
- }
- $next[] = <<<DOC
- }
- /**
- * 主键
- *
- * @return mixed
- * @throws \Exception
- */
- public function primaryKey(){
- DOC;
- $exclude = "\t\treturn array();";
- if($primaryKey) {
- $next[] = "\t\treturn array('". join("','", $this->convertToProperties($primaryKey)). "');";
- $exclude = "\t\treturn array('". join("','", $this->convertToProperties($primaryKey)). "');";
- }else{
- $next[] = <<<DOC
- throw new \Exception('请设置主键');
- DOC;
- }
- $next[] = <<<DOC
- }
- /**
- * 更新数据的时候,验证唯一需要排除的值,此处仅支持,单个或联合排除,不支持单个排除
- *
- * @return array
- */
- public function exclude(){
- DOC;
- $next[] = $exclude;
- $next[] = <<<DOC
- }
- /**
- * 添加时验证的字段,自行添加
- */
- public function validFieldsForAdd(){
- DOC;
- if(count($validForSave) > 0) {
- $next[] = "\t\$fields = array('". join("', '", $validForSave)."');";
- }else{
- $next[] = "\t\$fields = array();";
- }
- $next[] = <<<DOC
- return \$this->valid(\$fields);
- }
-
- /**
- * 更新时验证的字段,自行添加
- */
- public function validFieldsForUpdate() {
- \$fields = array();
- return \$this->valid(\$fields);
- }
- DOC;
- return join("\n", $next);
- }
- /**
- * required
- * @param array $rules 规则
- * @param array $comments field comment
- * @return array
- */
- public function generateRequired($rules, $comments = array()) {
- $constantJoin = [];
- if(!$rules || !is_array($rules)) {
- return $constantJoin;
- }
- $constantJoin[] = "\t\t". '$rules["required"] = [';
- $join = [];
- foreach($rules as $key => $value) {
- $comment = '';
- if(isset($comments[$value]) && $comments[$value] != "") {
- $comment = $comments[$value];
- }
- $message = ($comment != '' ? $comment : $value) . "不能为空";
- $join[] = <<<DOC
- \t\t["{$this->convertToProperty($value)}", "{$message}"]
- DOC;
- }
- $constantJoin[] = join(",\n", $join);
- $constantJoin[] = "\t\t];";
- return $constantJoin;
- }
- public function generateMaxLength($rules, $comments = array()) {
- $constantJoin = [];
- if(!$rules || !is_array($rules)) {
- return $constantJoin;
- }
- $constantJoin[] = "\t\t". '$rules["maxLength"] = [';
- $join = [];
- foreach($rules as $key => $value) {
- $comment = '';
- if(isset($comments[$value]) && $comments[$value] != "") {
- $comment = $comments[$value];
- }
- $message = ($comment != '' ? $comment : $key) . "不能超过 ". $value ."个字符";
- $join[] = <<<DOC
- \t\t["{$this->convertToProperty($key)}", "{$message}", {$value}]
- DOC;
- }
- $constantJoin[] = join(",\n", $join);
- $constantJoin[] = "\t\t];";
- return $constantJoin;
- }
- public function generateMinLength($rules, $comments = array()) {
- $constantJoin = [];
- if(!$rules || !is_array($rules)) {
- return $constantJoin;
- }
- $constantJoin[] = "\t\t". '$rules["minLength"] = [';
- $join = [];
- foreach($rules as $key => $value) {
- $comment = '';
- if(isset($comments[$value]) && $comments[$value] != "") {
- $comment = $comments[$value];
- }
- $message = ($comment != '' ? $comment : $key) . "不能少于 ". $value ."个字符";
- $join[] = <<<DOC
- \t\t["{$this->convertToProperty($key)}", "{$message}", {$value}]
- DOC;
- }
- $constantJoin[] = join(",\n", $join);
- $constantJoin[] = "\t\t];";
- return $constantJoin;
- }
- /**
- * datetime 类型
- * @param array $rules
- * @param $comments
- * @return array
- */
- public function generateDatetime($rules, $comments = array()) {
- $constantJoin = [];
- if(!$rules || !is_array($rules)) {
- return $constantJoin;
- }
- $constantJoin[] = "\t\t". '$rules["date"] = [';
- $join = [];
- foreach($rules as $key => $value) {
- $comment = '';
- if(isset($comments[$value]) && $comments[$value] != "") {
- $comment = $comments[$value];
- }
- $message = $comment . "格式不正确";
- $join[] = <<<DOC
- \t\t["{$this->convertToProperty($value)}", "{$message}"]
- DOC;
- }
- $constantJoin[] = join(",\n", $join);
- $constantJoin[] = "\t\t];";
- return $constantJoin;
- }
- /**
- * int 类型数据
- * @param $rules
- * @param $comments
- * @return array
- */
- public function generateInt($rules, $comments = array()) {
- $constantJoin = [];
- if(!$rules || !is_array($rules)) {
- return $constantJoin;
- }
- $intProperty['min'][] = "\t\t". '$rules["minNumber"] = [';
- $intProperty['max'][] = "\t\t". '$rules["maxNumber"] = [';
- $intProperty['number'][] = "\t\t". '$rules["number"] = [';
- $joinMin = [];
- $joinMax = [];
- $joinNumber = [];
- foreach ($rules as $key => $val) {
- $message = isset($comments[$key]) && $comments[$key] != "" ? $comments[$key] : $key;
- $min = $message . '不能小于'. $val[0];
- $max = $message . '不能大于'. $val[1];
- $number = $message . '必须是数字';
- $joinMin[] = <<<DOC
- \t\t["{$this->convertToProperty($key)}", "{$min}", {$val[0]}]
- DOC;
- $joinMax[] = <<<DOC
- \t\t["{$this->convertToProperty($key)}", "{$max}", {$val[1]}]
- DOC;
- $joinNumber[] = <<<DOC
- \t\t["{$this->convertToProperty($key)}", "{$number}"]
- DOC;
- }
- $intProperty['min'][] = join(",\n", $joinMin);
- $intProperty['min'][] = "\t\t];";
- $intProperty['max'][] = join(",\n", $joinMax);
- $intProperty['max'][] = "\t\t];";
- $intProperty['number'][] = join(",\n", $joinNumber);
- $intProperty['number'][] = "\t\t];";
- return array_merge($constantJoin, $intProperty['min'], $intProperty['max'], $intProperty['number']);
- }
- public function generateDecimal($rules, $comments = array()) {
- $constantJoin = [];
- if(!$rules || !is_array($rules)) {
- return $constantJoin;
- }
- $constantJoin = [];
- $constantJoin[] = "\t\t". '$rules["decimal"] = [';
- $joinProperty = [];
- foreach ($rules as $key => $val) {
- $comment = '';
- if(isset($comments[$key]) && $comments[$key] != "") {
- $comment = $comments[$key];
- }
- $message = ($comment != '' ? $comment : $key) . "格式示例: ". str_repeat(6, min(1, (int)$val[0] - (int)$val[1])) . ".". str_repeat(6, (int)$val[1]);
- $joinProperty[] = <<<DOC
- \t\t["{$this->convertToProperty($key)}", "{$message}", "{$val[0]},{$val[1]}"]
- DOC;
- }
- $constantJoin[] = join(",\n", $joinProperty);
- $constantJoin[] = "\t\t];";
- return $constantJoin;
- }
- /**
- * 转换为属性,属性会将下划线+小写/大写 转换成大写
- *
- * @param $field
- * @return array|string|string[]|null
- */
- public function convertToProperty($field) {
- $field = $this->ucFirst ? ucfirst($field) : $field;
- return preg_replace_callback("/\_([a-z]|[A-Z]|[0-9])/", function($match){
- return ucfirst($match[1]);
- }, $field);
- }
- /**
- * 批量转 property 名称
- *
- * @param $fields
- * @return array|string|string[]|null
- */
- public function convertToProperties($fields) {
- if(!is_array($fields)) {
- return $this->convertToProperty($fields);
- }
- $map = [];
- foreach ($fields as $val) {
- $map[] = $this->convertToProperty($val);
- }
- return $map;
- }
- /**
- * 将属性转换成字段,属性中的大写会转换成成下划线+小写
- *
- * @param $field
- * @return array|string|string[]|null
- */
- public function convertToField($field) {
- $field = $this->ucFirst ? lcfirst($field) : $field;
- return preg_replace_callback("/[A-Z]/", function($match){
- return "_". lcfirst($match[0]);
- }, $field);
- }
- /**
- * 批量转 field
- * @param array|string $fields
- * @return array|string|string[]|null
- */
- public function convertToFields($fields) {
- if(!is_array($fields)) {
- return $this->convertToField($fields);
- }
- $map = [];
- foreach ($fields as $val) {
- $map[] = $this->convertToField($val);
- }
- return $map;
- }
- }
|