diff --git a/Database/Relation.php b/Database/Relation.php index 27e1c75b..64fc2c12 100644 --- a/Database/Relation.php +++ b/Database/Relation.php @@ -8,7 +8,7 @@ use Snowflake\Abstracts\Component; /** * Class Relation - * @package BeReborn\db + * @package Snowflake\db */ class Relation extends Component { diff --git a/System/Gii/Gii.php b/System/Gii/Gii.php new file mode 100644 index 00000000..f61d923f --- /dev/null +++ b/System/Gii/Gii.php @@ -0,0 +1,289 @@ +db = $db; + if (!$gii->db) { + $db = Input()->get('databases', 'db'); + $gii->db = Snowflake::app()->db->get($db); + } + $redis = Snowflake::app()->getRedis(); + if (!empty(Input()->get('t'))) { + $gii->tableName = Input()->get('t'); + $redis->del('column:' . $gii->tableName); + } + if (Input()->get('m', NULL)) { + $model = 1; + } + if (Input()->get('c', NULL)) { + $c = 1; + } + if (Input()->get('isUpdate') == 1) { + $gii->isUpdate = TRUE; + } + return $gii->getTable($c, $model); + } + + /** + * @param $m + * @param $c + * @return array + * + * @throws Exception + */ + private function getTable(&$c, &$m) + { + $tables = $this->getFields($this->getTables()); + if (empty($tables)) { + return []; + } + + $fileList = []; + foreach ($tables as $key => $val) { + $data = $this->createModelFile($key, $val); + if ($m == 1) { + $fileList[] = $this->generateModel($data); + } + if ($c == 1) { + $fileList[] = $this->generateController($data); + } + } + return $fileList; + } + + /** + * @param array $data + * @return string + * @throws Exception + */ + private function generateModel(array $data) + { + $controller = new GiiModel($data['classFileName'], $data['tableName'], $data['visible'], $data['res'], $data['fields']); + $controller->setConnection($this->db); + $controller->setModelPath($this->modelPath); + $controller->setModelNamespace($this->modelNamespace); + $controller->setModule(Input()->get('module', null)); + $controller->setControllerPath($this->controllerPath); + $controller->setControllerNamespace($this->controllerNamespace); + return $controller->generate(); + } + + /** + * @param array $data + * @return string + * @throws Exception + */ + private function generateController(array $data) + { + $controller = new GiiController($data['classFileName'], $data['fields']); + $controller->setConnection($this->db); + $controller->setModelPath($this->modelPath); + $controller->setModelNamespace($this->modelNamespace); + $controller->setControllerPath($this->controllerPath); + $controller->setModule(Input()->get('module', null)); + $controller->setControllerNamespace($this->controllerNamespace); + return $controller->generate(); + } + + /** + * @return array|null + * @throws Exception + */ + private function getTables() + { + if (empty($this->tableName)) { + return $this->showAll(); + } + $res = $this->tableName; + if (is_string($res)) { + $res = explode(',', $this->tableName); + } + if (empty($res)) { + return []; + } + return $res; + } + + /** + * @return array + * @throws Exception + */ + private function showAll() + { + $res = []; + $_tables = Db::findAllBySql('show tables', [], $this->db); + if (empty($_tables)) { + return $res; + } + foreach ($_tables as $key => $val) { + $res[] = array_shift($val); + } + return $res; + } + + /** + * @param $table + * @return bool|int + * @throws Exception + */ + private function getIndex($table) + { + $data = Db::findAllBySql('SHOW INDEX FROM ' . $table, [], $this->db); + + return empty($data) ? NULL : $data[0]; + } + + /** + * @param $tables + * + * @return array + * @throws + */ + private function getFields($tables) + { + $res = []; + if (!is_array($tables)) { + $tables = [$tables]; + } + foreach ($tables as $key => $val) { + if (empty($val)) continue; + $_tmp = Db::findAllBySql('SHOW FULL FIELDS FROM ' . $val, [], $this->db); + if (empty($_tmp)) { + continue; + } + $res[$val] = $_tmp; + } + return $res; + } + + /** + * @param $tableName + * @param $tables + * + * @return array + * @throws Exception + */ + public function createModelFile($tableName, $tables) + { + $res = $visible = $fields = $keys = []; + foreach ($tables as $_key => $_val) { + $keys = $tableName; + if ($_val['Extra'] == 'auto_increment' || $_val['Key'] == 'PRI') { + $keys = $tableName; + } + if (!isset($keys) && !($index = $this->getIndex($tableName))) { + $keys = $index['Column_name']; + } + if (in_array(strtoupper($_val['Field']), $this->keyword)) { + throw new Exception('You can not use keyword "' . $_val['Field'] . '" as field at table "' . $tableName . '"'); + } + array_push($visible, $this->createVisible($_val['Field'])); + array_push($fields, $_val); + $res[] = $this->createSetFunc($_val['Field'], $_val['Comment']); + } + + $classFileName = $this->getClassName($tableName); + + return [ + 'classFileName' => $classFileName, + 'tableName' => $keys, + 'visible' => $visible, + 'fields' => $fields, + 'res' => $res, + ]; + } + + /** + * @param $field + * @return string + * 创建变量注释 + */ + private function createVisible($field) + { + return ' + * @property $' . $field; + } + + /** + * @param $field + * @param $comment + * @return string + * 暂时不知道干嘛用的 + */ + private function createSetFunc($field, $comment) + { + return ' + ' . str_pad('\'' . $field . '\'', 20, ' ', STR_PAD_RIGHT) . '=> \'' . (empty($comment) ? ucfirst($field) : $comment) . '\','; + } + + /** + * @param $tableName + * @return string + * 构建类名称 + */ + private function getClassName($tableName) + { + $res = []; + foreach (explode('_', $tableName) as $n => $val) { + $res[] = ucfirst($val); + } + + $name = ucfirst(rtrim($this->db->tablePrefix, '_')); + + return implode('', $res); + + return str_replace($name, '', implode('', $res)) . 'Comply'; + } + +} diff --git a/System/Gii/GiiBase.php b/System/Gii/GiiBase.php new file mode 100644 index 00000000..741573da --- /dev/null +++ b/System/Gii/GiiBase.php @@ -0,0 +1,218 @@ + ['tinyint', 'smallint', 'mediumint', 'int', 'bigint'], + 'string' => ['char', 'varchar', 'tinytext', 'text', 'mediumtext', 'longtext', 'enum'], + 'date' => ['date'], + 'time' => ['time'], + 'year' => ['year'], + 'datetime' => ['datetime'], + 'timestamp' => ['timestamp'], + 'float' => ['float', 'double', 'decimal',], + ]; + public $tableName = NULL; + + /** @var Connection */ + public $db; + + /** + * @param string $modelPath + */ + public function setModelPath(string $modelPath): void + { + $this->modelPath = $modelPath; + } + + /** + * @param string $modelNamespace + */ + public function setModelNamespace(string $modelNamespace): void + { + $this->modelNamespace = $modelNamespace; + } + + /** + * @param string $controllerPath + */ + public function setControllerPath(string $controllerPath): void + { + $this->controllerPath = $controllerPath; + } + + /** + * @param $module + */ + public function setModule($module) + { + $this->module = $module; + } + + /** + * @param string $controllerNamespace + */ + public function setControllerNamespace(string $controllerNamespace): void + { + $this->controllerNamespace = $controllerNamespace; + } + + + /** + * @param \ReflectionClass $object + * @param $className + * + * @return string + */ + public function getUseContent($object, $className) + { + if (empty($object)) { + return ''; + } + $file = $this->getFilePath($className); + if (!file_exists($file)) { + return ''; + } + $content = file_get_contents($file); + $explode = explode(PHP_EOL, $content); + $exists = array_slice($explode, 0, $object->getStartLine()); + $_tmp = []; + foreach ($exists as $key => $val) { + if (trim($val) == '/**') { + break; + } + $_tmp[] = $val; + } + return trim(implode(PHP_EOL, $_tmp)); + } + + + /** + * @param $fields + * @return mixed|null + * 返回表主键 + */ + public function getPrimaryKey($fields) + { + $condition = ['PRI', 'UNI']; + foreach ($fields as $field) { + if ($field['Extra'] == 'auto_increment') { + return $field['Field']; + } + if (in_array($field['Key'], $condition)) { + return $field['Field']; + } + } + return null; + } + + /** + * @param $className + * @return string + */ + private function getFilePath($className) + { + if (strpos($className, '\\')) { + $className = str_replace('\\', '/', $className); + } + if (strpos($className, '\\')) { + $className = str_replace('\\', '/', $className); + } + + return APP_PATH . $className; + } + + /** + * @param \ReflectionClass $object + * @param $className + * @param $method + * @return string + * @throws \Exception + */ + public function getFuncLineContent($object, $className, $method) + { + $fun = $object->getMethod($method); + + $content = file_get_contents($this->getFilePath($className)); + $explode = explode(PHP_EOL, $content); + $exists = array_slice($explode, $fun->getStartLine() - 1, $fun->getEndLine() - $fun->getStartLine() + 1); + return implode(PHP_EOL, $exists); + } + + + /** + * @return array + */ + protected function getModelPath() + { + $dbName = $this->db->id; + if (empty($dbName) || $dbName == 'db') { + $dbName = ''; + } + + $modelPath = [ + 'namespace' => $this->modelNamespace, + 'path' => $this->modelPath, + ]; + if (!is_dir($modelPath['path'])) { + mkdir($modelPath['path']); + } + if (!empty($dbName)) { + $modelPath['namespace'] = $this->modelNamespace . ucfirst($dbName); + $modelPath['path'] = $this->modelPath . ucfirst($dbName); + } + + if (!is_dir($modelPath['path'])) { + mkdir($modelPath['path']); + } + return $modelPath; + } + + /** + * @param $db + */ + public function setConnection($db) + { + $this->db = $db; + } + + /** + * @param $val + * @return string + */ + protected function checkIsRequired($val) + { + return strtolower($val['Null']) == 'no' && $val['Default'] === NULL ? 'true' : 'false'; + } + + /** + * @return array + */ + public function getFileLists() + { + return $this->fileList; + } + +} diff --git a/System/Gii/GiiController.php b/System/Gii/GiiController.php new file mode 100644 index 00000000..3749b9fe --- /dev/null +++ b/System/Gii/GiiController.php @@ -0,0 +1,486 @@ +className = $className; + $this->fields = $fields; + } + + + /** + * @return string + * @throws \Exception + */ + public function generate() + { + $path = $this->getControllerPath(); + $modelPath = $this->getModelPath(); + + $managerName = $this->className; + + $namespace = rtrim($path['namespace'], '\\'); + $model_namespace = rtrim($modelPath['namespace'], '\\'); + + $prefix = str_replace('_', '', $this->db->tablePrefix); + $managerName = str_replace(ucfirst($prefix), '', $managerName); + + $class = ''; + $controller = $namespace . '\\' . $managerName . 'Controller'; + if (file_exists($path['path'] . '/' . $managerName . 'Controller.php')) { + $class = new \ReflectionClass($controller); + } + + $controllerName = $managerName; + + $html = $this->getUseContent($class, $controller); + + + if (empty($html)) { + + + $html .= "getMethods(\ReflectionMethod::IS_PUBLIC); + $funcNames = array_column($methods, 'name'); + + $classFileName = str_replace(APP_PATH, '', $class->getFileName()); + + if (!empty($methods)) foreach ($methods as $key => $val) { + if ($val->class != $class->getName()) continue; + $html .= " + " . $val->getDocComment() . "\n"; + $html .= $this->getFuncLineContent($class, $classFileName, $val->name) . "\n"; + } + } + if (!Input()->get('--controller-empty', false)) { + $default = ['actionLoadParam', 'actionAdd', 'actionUpdate', 'actionDetail', 'actionDelete', 'actionBatchDelete', 'actionList']; + + foreach ($default as $key => $val) { + if (in_array($val, $funcNames)) continue; + $html .= $this->{'controllerMethod' . str_replace('action', '', $val)}($this->fields, $managerName, $managerName) . "\n"; + } + } + + $html .= ' +}'; + + $file = $path['path'] . '/' . $controllerName . 'Controller.php'; + if (file_exists($file)) { + unlink($file); + } + + Snowflake::writeFile($file, $html); + return $controllerName . 'Controller.php'; + } + + + /** + * @return array + */ + private function getControllerPath() + { + $dbName = $this->db->id; + if (empty($dbName) || $dbName == 'db') { + $dbName = ''; + } + + $module = empty($this->module) ? '' : $this->module; + $modelPath['namespace'] = $this->controllerNamespace . $module; + $modelPath['path'] = $this->controllerPath . $module; + if (!is_dir($modelPath['path'])) { + mkdir($modelPath['path']); + } + if (!empty($dbName)) { + $modelPath['namespace'] = $this->controllerNamespace . ucfirst($dbName); + $modelPath['path'] = $this->controllerPath . ucfirst($dbName); + } + + $modelPath['namespace'] = rtrim($modelPath['namespace'], '\\'); + $modelPath['path'] = rtrim($modelPath['path'], '\\'); + + if (!is_dir($modelPath['path'])) { + mkdir($modelPath['path']); + } + return $modelPath; + } + + /** + * @param $fields + * @param $className + * @param null $object + * @return string + * 新增 + */ + public function controllerMethodAdd($fields, $className, $object = NULL) + { + return ' + /** + * @return array + * @throws exception + */ + public function actionAdd() + { + $model = new ' . $className . '(); + $model->attributes = $this->loadParam(); + if (!$model->save()) { + return JSON::to(500, $model->getLastError()); + } + return JSON::to(Code::SUCCESS, $model->toArray()); + }'; + } + + /** + * @param $fields + * @param $className + * @param null $object + * @return string + * 通用 + */ + public function controllerMethodLoadParam($fields, $className, $object = NULL) + { + return ' + /** + * @return array + * @throws Exception + */ + private function loadParam() + { + return [' . $this->getData($fields) . ' + ]; + }'; + } + + /** + * @param $fields + * @param $className + * @param null $object + * @return string + * 构建更新 + */ + public function controllerMethodUpdate($fields, $className, $object = NULL) + { + return ' + /** + * @return array + * @throws exception + */ + public function actionUpdate() + { + $model = ' . $className . '::findOne(Input()->post(\'id\', 0)); + if (empty($model)) { + return JSON::to(500, \'指定数据不存在\'); + } + $model->attributes = $this->loadParam(); + + if (!$model->save()) { + return JSON::to(500, $model->getLastError()); + } + return JSON::to(Code::SUCCESS, $model->toArray()); + }'; + } + + /** + * @param $fields + * @param $className + * @param null $object + * @return string + * 构建更新 + */ + public function controllerMethodBatchDelete($fields, $className, $object = NULL) + { + return ' + /** + * @return array + * @throws exception + */ + public function actionBatchDelete() + { + $_key = Input()->array(\'ids\'); + $pass = Input()->string(\'password\', true, 32); + if (empty($_key)) { + return JSON::to(500, \'IDS集合不能为空\'); + } + + $user = $this->request->identity; + if (strcmp(Str::encrypt($pass), $user->password)) { + return JSON::to(500, \'密码错误\'); + } + + $model = ' . $className . '::find()->in(\'id\', $_key); + if(!$model->delete()){ + return JSON::to(500, \'系统繁忙, 请稍后再试!\'); + } + return JSON::to(Code::SUCCESS, $model->toArray()); + }'; + } + + /** + * @param $fields + * @param $className + * @param $managerName + * @return string + * 构建详情 + */ + public function controllerMethodDetail($fields, $className, $managerName) + { + return ' + /** + * @return array + * @throws exception + */ + public function actionDetail() + { + $model = ' . $managerName . '::findOne(Input()->get(\'id\')); + if(empty($model)){ + return JSON::to(404, \'Data Not Exists\'); + } + return JSON::to(Code::SUCCESS, $model->toArray()); + }'; + } + + /** + * @param $fields + * @param $className + * @param $managerName + * @return string + * 构建删除操作 + */ + public function controllerMethodDelete($fields, $className, $managerName) + { + return ' + /** + * @return array + * @throws exception + */ + public function actionDelete() + { + $_key = Input()->int(\'id\', true); + $pass = Input()->string(\'password\', true, 32); + + $user = $this->request->identity; + if (strcmp(Str::encrypt($pass), $user->password)) { + return JSON::to(500, \'密码错误\'); + } + + $model = ' . $managerName . '::findOne($_key); + if (empty($model)) { + return JSON::to(500, \'指定数据不存在\'); + } + if(!$model->delete()){ + return JSON::to(500, $model->getLastError()); + } + return JSON::to(Code::SUCCESS, $model); + }'; + } + + /** + * @param $fields + * @param $className + * @param $managerName + * @param null $object + * @return string + * 构建查询列表 + */ + public function controllerMethodList($fields, $className, $managerName, $object = NULL) + { + return ' + /** + * @return array + * @throws exception + */ + public function actionList() + { + $pWhere = array();' . $this->getWhere($fields) . ' + + //分页处理 + $count = Input()->get(\'count\', -1); + $order = Input()->get(\'order\', \'id\'); + if(!empty($order)) { + $order .= !Input()->get(\'isDesc\', 0) ? \' asc\' : \' desc\'; + }else{ + $order = \'id desc\'; + } + + //列表输出 + $model = ' . $managerName . '::find()->where($pWhere)->orderBy($order); + + if((int) $count === 1){ + $count = $model->count(); + } + if($count != -100){ + $model->limit(Input()->offset() ,Input()->size()); + } + + $data = $model->all()->toArray(); + + return JSON::to(Code::SUCCESS, $data, $count); + } + '; + } + + private function getData($fields) + { + $html = ''; + + $length = $this->getMaxLength($fields); + + + foreach ($fields as $key => $val) { + preg_match('/\((\d+)(,(\d+))*\)/', $val['Type'], $number); + $type = strtolower(preg_replace('/\(\d+(,\d+)*\)/', '', $val['Type'])); + + $first = preg_replace('/\s+\w+/', '', $type); + if ($val['Field'] == 'id') continue; + if ($type == 'timestamp') continue; + $_field = []; + $_field['required'] = $this->checkIsRequired($val); + foreach ($this->type as $_key => $value) { + if (!in_array(strtolower($first), $value)) continue; + $comment = '//' . $val['Comment']; + $_field['type'] = $_key; + + if ($type == 'date' || $type == 'datetime' || $type == 'time') { + switch ($type) { + case 'date': + $_tps = 'Input()->' . $_key . '(\'' . $val['Field'] . '\', date(\'Y-m-d\'))'; + break; + case 'time': + $_tps = 'Input()->' . $_key . '(\'' . $val['Field'] . '\', date(\'H:i:s\'))'; + break; + default: + $_tps = 'Input()->' . $_key . '(\'' . $val['Field'] . '\', date(\'Y-m-d H:i:s\'))'; + } + $html .= ' + \'' . str_pad($val['Field'] . '\'', $length, ' ', STR_PAD_RIGHT) . ' => ' . str_pad($_tps . ',', 60, ' ', STR_PAD_RIGHT) . $comment; + } else { + $tmp = 'null'; + if (isset($number[0])) { + if (strpos(',', $number[0])) { + $tmp = '[' . $number[1] . ',' . $number[3] . ']'; + $_field['min'] = $number[1]; + $_field['max'] = $number[3]; + } else { + $tmp = '[0,' . $number[1] . ']'; + $_field['min'] = 0; + $_field['max'] = $number[1]; + } + } + if ($key == 'string') { + $_tps = 'Input()->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ', ' . $tmp . ')'; + } else if ($type == 'int') { + if ($number[0] == 10) { + $_tps = 'Input()->' . $_key . '(\'' . $val['Field'] . '\', time())'; + } else { + $_tps = 'Input()->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ')'; + } + } else if ($type == 'float') { + $_tps = 'Input()->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ', ' . ($number[3] ?? '2') . ')'; + } else if ($key == 'email') { + $_tps = 'Input()->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ')'; + } else if ($key == 'timestamp') { + $_tps = 'Input()->' . $_key . '(\'' . $val['Field'] . '\', time())'; + } else { + $_tps = 'Input()->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ')'; + } + $html .= ' + \'' . str_pad($val['Field'] . '\'', $length, ' ', STR_PAD_RIGHT) . ' => ' . str_pad($_tps . ',', 60, ' ', STR_PAD_RIGHT) . $comment; + } + } + $this->rules[$val['Field']] = $_field; + } + return $html; + } + + private function getMaxLength($fields) + { + $length = 0; + foreach ($fields as $key => $val) { + if (mb_strlen($val['Field'] . ' >=') > $length) $length = mb_strlen($val['Field'] . ' >='); + } + return $length; + } + + private function getWhere($fields) + { + $html = ''; + + $length = $this->getMaxLength($fields); + + foreach ($fields as $key => $val) { + preg_match('/\d+/', $val['Type'], $number); + + $type = strtolower(preg_replace('/\(\d+\)/', '', $val['Type'])); + + $first = preg_replace('/\s+\w+/', '', $type); + + if ($type == 'timestamp') continue; + if ($type == 'json') continue; + + foreach ($this->type as $_key => $value) { + if (!in_array(strtolower($first), $value)) continue; + $comment = '//' . $val['Comment']; + if ($type == 'date' || $type == 'datetime' || $type == 'time') { + $_tps = 'Input()->get(\'' . $val['Field'] . '\', null)'; + $html .= ' + $pWhere[\'' . str_pad($val['Field'] . ' <=\']', $length, ' ', STR_PAD_RIGHT) . ' = ' . str_pad($_tps . ';', 60, ' ', STR_PAD_RIGHT) . $comment; + $html .= ' + $pWhere[\'' . str_pad($val['Field'] . ' >=\']', $length, ' ', STR_PAD_RIGHT) . ' = ' . str_pad($_tps . ';', 60, ' ', STR_PAD_RIGHT) . $comment; + } else { + + $_tps = 'Input()->get(\'' . $val['Field'] . '\', null)'; + $html .= ' + $pWhere[\'' . str_pad($val['Field'] . '\']', $length, ' ', STR_PAD_RIGHT) . ' = ' . str_pad($_tps . ';', 60, ' ', STR_PAD_RIGHT) . $comment; + } + } + } + return $html; + } +} diff --git a/System/Gii/GiiModel.php b/System/Gii/GiiModel.php new file mode 100644 index 00000000..e5a27a20 --- /dev/null +++ b/System/Gii/GiiModel.php @@ -0,0 +1,456 @@ +classFileName = $classFileName; + $this->tableName = $tableName; + $this->visible = $visible; + $this->res = $res; + $this->fields = $fields; + } + + /** + * @throws \ReflectionException + * @throws \Exception + */ + public function generate() + { + $class = ''; + $modelPath = $this->getModelPath(); + $managerName = $this->classFileName; + + $namespace = rtrim($modelPath['namespace'], '\\'); + $classFileName = rtrim($modelPath['namespace'], '\\') . '\\' . $managerName; + + $prefix = str_replace('_', '', $this->db->tablePrefix); + $managerName = str_replace(ucfirst($prefix), '', $managerName); + + if (file_exists($modelPath['path'] . '/' . $managerName . '.php')) { + try { + $class = new \ReflectionClass($modelPath['namespace'] . '\\' . $managerName); + } catch (\Exception $e) { + var_dump($e->getMessage()); + } + } + + + $html = $this->getUseContent($class, $classFileName); + if (empty($html)) { + $html = 'setCreateSql($this->tableName); + + if (strpos($html, $createSql) === false) { + $html .= ' +' . $this->setCreateSql($this->tableName); + } + + $html .= ' + +/** + * Class ' . $managerName . ' + * @package Inter\mysql + *' . implode('', $this->visible) . ' + * @sql + */ +class ' . $managerName . ' extends ActiveRecord +{'; + + if (!empty($class)) { + foreach ($class->getConstants() as $key => $val) { + if (is_numeric($val)) { + $html .= ' + const ' . $key . ' = ' . $val . ';' . "\n"; + } else { + $html .= ' + const ' . $key . ' = \'' . $val . '\';' . "\n"; + } + } + + foreach ($class->getDefaultProperties() as $key => $val) { + $property = $class->getProperty($key); + if ($property->class != $class->getName()) continue; + if (is_array($val)) { + $val = '[\'' . implode('\', \'', $val) . '\']'; + } else if (!is_numeric($val)) { + $val = '\'' . $val . '\''; + } + + if ($property->isProtected()) { + $debug = 'protected'; + } else if ($property->isPrivate()) { + $debug = 'private'; + } else { + $debug = 'public'; + } + + + if ($property->isStatic()) { + $html .= ' + ' . $debug . ' static $' . $key . ' = ' . $val . ';' . "\n"; + } else { + $html .= ' + ' . $debug . ' $' . $key . ' = ' . $val . ';' . "\n"; + } + + } + } else { + $primary = $this->createPrimary($this->fields); + if (!empty($primary)) { + $html .= $primary . "\n"; + } + } + + $html .= $this->createTableName($this->tableName) . "\n"; + + $html .= $this->createRules($this->fields); + + + $html .= ' + + /** + * @return array + */ + public function attributes() : array + { + return [' . implode('', $this->res) . ' + ]; + }' . "\n"; + + $out = ['rules', 'tableName', 'attributes']; + if (is_object($class)) { + $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC); + + $classFileName = str_replace(APP_PATH, '', $class->getFileName()); + + $content = []; + if (!empty($methods)) foreach ($methods as $key => $val) { + if ($val->class != $class->getName()) continue; + if (in_array($val->name, $out)) continue; + $over = " + " . $val->getDocComment() . "\n"; + + $func = $this->getFuncLineContent($class, $classFileName, $val->name) . "\n"; + + $content[] = $over . $func; + } + if (!empty($content)) { + $html .= implode($content); + } + } else { + $html .= $this->createDatabaseSource(); + $other = $this->generate_json_function($html, $this->fields); + if (!empty($other)) { + $html .= implode($other); + } + } + + $html .= ' +}'; + + $file = rtrim($modelPath['path'], '/') . '/' . $managerName . '.php'; + if (file_exists($file)) { + unlink($file); + } + + Snowflake::writeFile($file, $html); + return $managerName . '.php'; + } + + + private function generate_json_function($html, $fields) + { + $strings = []; + foreach ($fields as $field) { + if ($field['Type'] === 'json') { + $function = ' + /** + * @param $value + * @return false|string + */ + public function set' . ucfirst($field['Field']) . 'Attribute($value) + { + if ( !is_string($value) ) { + return JSON::encode($value); + } + return $value; + } + '; + + $get_function = ' + /** + * @param $value + * @return mixed + */ + public function get' . ucfirst($field['Field']) . 'Attribute($value) + { + $value = stripcslashes($value) + if ( is_string($value) ) { + return JSON::decode($value, true); + } + return $value; + } + '; + + if (strpos($html, 'set' . ucfirst($field['Field']) . 'Attribute') === false) { + $strings[] = $function; + } + + if (strpos($html, 'get' . ucfirst($field['Field']) . 'Attribute') === false) { + $strings[] = $get_function; + } + } + } + + return $strings; + } + + + /** + * @param $field + * @return string + * 创建表名称 + */ + private function createTableName($field) + { + + $prefixed = $this->db->tablePrefix; + if (!empty($prefixed)) { + $field = str_replace($prefixed, '', $field); + $field = '{{%' . $field . '}}'; + } + + return ' + /** + * @inheritdoc + */ + public static function tableName(){ + return \'' . $field . '\'; + } + '; + } + + /** + * @param $fields + * @return string + * 创建效验规则 + */ + private function createRules($fields) + { + $data = []; + foreach ($fields as $key => $val) { + if ($val['Extra'] == 'auto_increment') continue; + $type = preg_replace('/\(.*?\)|\s+\w+/', '', $val['Type']); + foreach ($this->type as $_key => $_val) { + if (in_array($type, $_val)) { + $type = lcfirst(str_replace('get', '', $_key)); + break; + } + } + $data[$type][] = $val; + } + + $_field_one = ''; + $required = $this->getRequired($fields); + if (!empty($required)) { + $_field_one .= $required; + } + foreach ($data as $key => $val) { + $field = '[\'' . implode('\', \'', array_column($val, 'Field')) . '\']'; + if (count($val) == 1) { + $field = '\'' . current($val)['Field'] . '\''; + } + $_field_one .= ' + [' . $field . ', \'' . $key . '\'],'; + } + foreach ($data as $key => $val) { + $length = $this->getLength($val); + if (!empty($length)) { + $_field_one .= $length . ','; + } + } + $required = $this->getUnique($fields); + if (!empty($required)) { + $_field_one .= $required; + } + return ' + /** + * @return array + */ + public function rules(): array + { + return [' . $_field_one . ' + ]; + } + '; + } + + /** + * @param $val + * @return string + */ + public function getLength($val) + { + $data = []; + foreach ($val as $key => $_val) { + $preg = preg_match('/(\w+)\((.*?)\)/', $_val['Type'], $results); + if ($preg && isset($results[2])) { + $results[] = $_val['Field']; + + $data[$results[2]][] = $results; + } + } + if (empty($data)) return ''; + $string = []; + foreach ($data as $key => $_val) { + if (strpos($key, ',') !== false) { + $key = '[' . $key . ']'; + } + if (count($_val) == 1) { + [$typeRule, $type, $rule, $field] = current($_val); + $_tmp = ' + [\'' . $field . '\', \'' . ($type == 'enum' ? 'enum' : 'maxLength') . '\' => ' . $key . ']'; + } else { + $_tmp = ' + [[\'' . implode('\', \'', array_column($_val, 3)) . '\'], \'maxLength\' => ' . $key . ']'; + } + $string[] = $_tmp; + } + return implode(',', $string); + } + + /** + * @param $fields + * @return string + */ + public function getUnique($fields) + { + $data = []; + foreach ($fields as $_key => $_val) { + if ($_val['Extra'] == 'auto_increment') continue; + if (strpos($_val['Type'], 'unique') !== FALSE) { + $data[] = $_val['Field']; + } + } + if (empty($data)) { + return ''; + } + return ' + [[\'' . implode('\', \'', $data) . '\'], \'unique\'],'; + } + + /** + * @param $val + * @return string + */ + public function getRequired($val) + { + $data = []; + foreach ($val as $_key => $_val) { + if ($_val['Extra'] == 'auto_increment') continue; + if ($_val['Key'] == 'PRI' || $_val['Key'] == 'UNI' || $this->checkIsRequired($_val) === 'true') { + array_push($data, $_val['Field']); + } + } + if (empty($data)) { + return ''; + } + return ' + [[\'' . implode('\', \'', $data) . '\'], \'required\'],'; + } + + /** + * 用来生成文档的 + * 格式 + * @param $fields + * @return null|string + * array( + * 'field' ,'字段類型' ,'是否必填' ,'字段长度' , '字段解释', + * 'field' ,'字段類型' ,'是否必填' ,'字段长度' , '字段解释', + * 'field' ,'字段類型' ,'是否必填' ,'字段长度' , '字段解释', + * 'field' ,'字段類型' ,'是否必填' ,'字段长度' , '字段解释', + * 'field' ,'字段類型' ,'是否必填' ,'字段长度' , '字段解释', + * 'field' ,'字段類型' ,'是否必填' ,'字段长度' , '字段解释', + * ) + */ + private function createPrimary($fields) + { + $field = $this->getPrimaryKey($fields); + if (empty($field)) { + return null; + } + return ' + public static $primary = \'' . $field . '\';'; + } + + /** + * @return string + */ + private function createDatabaseSource() + { + return ' + /** + * @return mixed|Connection + * @throws Exception + */ + public static function getDb() + { + return static::setDatabaseConnect(\'' . $this->db->id . '\'); + } +'; + } + + /** + * @param $table + * @return string + * @throws \Exception + */ + private function setCreateSql($table) + { + $text = Db::showCreateSql($table, $this->db)['Create Table'] ?? ''; + + $_tmp = []; + foreach (explode(PHP_EOL, $text) as $val) { + $_tmp[] = '// ' . $val; + } + + return implode(PHP_EOL, $_tmp); + } + + +}