From a689474053a6d356469a68b4b42cc4b7f2df28c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=90=91=E6=9E=97?= Date: Thu, 17 Mar 2022 10:35:14 +0800 Subject: [PATCH] modify plugin name --- Gii.php | 340 +++++++++++++++++++++++++++++ GiiBase.php | 412 +++++++++++++++++++++++++++++++++++ GiiCommand.php | 76 +++++++ GiiController.php | 537 ++++++++++++++++++++++++++++++++++++++++++++++ GiiJsonRpc.php | 113 ++++++++++ GiiMiddleware.php | 73 +++++++ GiiModel.php | 426 ++++++++++++++++++++++++++++++++++++ GiiProviders.php | 34 +++ GiiRpcClient.php | 100 +++++++++ GiiRpcService.php | 79 +++++++ GiiTask.php | 91 ++++++++ composer.json | 22 ++ 12 files changed, 2303 insertions(+) create mode 100644 Gii.php create mode 100644 GiiBase.php create mode 100644 GiiCommand.php create mode 100644 GiiController.php create mode 100644 GiiJsonRpc.php create mode 100644 GiiMiddleware.php create mode 100644 GiiModel.php create mode 100644 GiiProviders.php create mode 100644 GiiRpcClient.php create mode 100644 GiiRpcService.php create mode 100644 GiiTask.php create mode 100644 composer.json diff --git a/Gii.php b/Gii.php new file mode 100644 index 0000000..409f1de --- /dev/null +++ b/Gii.php @@ -0,0 +1,340 @@ +gen($input, $db); + } + + + /** + * @param InputInterface $input + * @param $db + * @return array + * @throws Exception + */ + public function gen(InputInterface $input, $db): array + { + $this->input = $input; + $this->db = $db; + + $make = $this->input->getOption('make'); + if (empty($make)) { + throw new Exception('构建类型不能为空~'); + } + switch (strtolower($make)) { + case 'task': + $task = new GiiTask(); + $task->setInput($this->input); + return $task->generate(); + case 'middleware': + $task = new GiiMiddleware(); + $task->setInput($this->input); + return $task->generate(); + case 'rpc-client': + $task = new GiiRpcClient(); + $task->setInput($this->input); + return $task->generate(); + case 'rpc-service': + $task = new GiiRpcService(); + $task->setInput($this->input); + return $task->generate(); + case 'json-rpc': + $task = new GiiJsonRpc(); + $task->setInput($this->input); + return $task->create(); + default: + return $this->getModel($make, $input); + } + } + + + /** + * @param $make + * @param $input + * @return array + * @throws Exception + */ + private function getModel($make, $input): array + { + return $this->makeByDatabases($make, $input); + } + + + /** + * @param $make + * @param InputInterface $input + * @return array + * @throws Exception + */ + private function makeByDatabases($make, InputInterface $input): array + { + if ($input->hasOption('name')) { + $this->tableName = $input->getOption('name'); + } + return match ($make) { + 'controller' => $this->getTable(1, 0), + 'model' => $this->getTable(0, 1), + default => [], + }; + } + + + /** + * @param $controller + * @param $model + * @return array + * + * @throws Exception + */ + private function getTable($controller, $model): array + { + $tables = $this->getFields($this->getTables()); + if (empty($tables)) { + return []; + } + + $fileList = []; + foreach ($tables as $key => $val) { + $data = $this->createModelFile($key, $val); + if ($controller == 1) { + $fileList[] = $this->generateController($data); + } + if ($model == 1) { + $fileList[] = $this->generateModel($data); + } + } + return $fileList; + } + + /** + * @param array $data + * @return string + * @throws Exception + */ + private function generateModel(array $data): string + { + $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->setInput($this->input); +// $controller->setModule($this->input->getArgument('module')); + $controller->setControllerPath($this->controllerPath); + $controller->setControllerNamespace($this->controllerNamespace); + return $controller->generate(); + } + + /** + * @param array $data + * @return string + * @throws Exception + */ + private function generateController(array $data): string + { + $controller = new GiiController($data['classFileName'], $data['fields']); + $controller->setConnection($this->db); + $controller->setModelPath($this->modelPath); + $controller->setInput($this->input); + $controller->setModelNamespace($this->modelNamespace); + $controller->setControllerPath($this->controllerPath); +// $controller->setModule($this->input->getArgument('module')); + $controller->setControllerNamespace($this->controllerNamespace); + return $controller->generate(); + } + + /** + * @return array|string|null + * @throws Exception + */ + private function getTables(): array|string|null + { + 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(): array + { + $res = []; + $_tables = Db::findAllBySql('show tables from `' . $this->db->database . '`', [], $this->db); + if (empty($_tables)) { + return $res; + } + foreach ($_tables as $key => $val) { + $res[] = array_shift($val); + } + return $res; + } + + /** + * @param $table + * @return bool|int|null + * @throws Exception + */ + private function getIndex($table): bool|int|null + { + $data = Db::findAllBySql('SHOW INDEX FROM ' . $table, [], $this->db); + + return empty($data) ? NULL : $data[0]; + } + + /** + * @param $tables + * + * @return array + * @throws + */ + private function getFields($tables): array + { + $res = []; + if (!is_array($tables)) { + $tables = [$tables]; + } + foreach ($tables as $key => $val) { + if (empty($val)) continue; + $_tmp = Db::findAllBySql('SHOW FULL FIELDS FROM `' . $this->db->database . '`.' . $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): array + { + $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): string + { + return ' + * @property $' . $field; + } + + /** + * @param $field + * @param $comment + * @return string + * 暂时不知道干嘛用的 + */ + private function createSetFunc($field, $comment): string + { + return ' + ' . str_pad('\'' . $field . '\'', 20, ' ', STR_PAD_RIGHT) . '=> \'' . (empty($comment) ? ucfirst($field) : $comment) . '\','; + } + + /** + * @param $tableName + * @return string + * 构建类名称 + */ + private function getClassName($tableName): string + { + $res = []; + $tableName = str_replace($this->db->tablePrefix,'', $tableName); + foreach (explode('_', $tableName) as $n => $val) { + $res[] = ucfirst($val); + } + return implode('', $res); + } + +} diff --git a/GiiBase.php b/GiiBase.php new file mode 100644 index 0000000..a7d970f --- /dev/null +++ b/GiiBase.php @@ -0,0 +1,412 @@ + ['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 ?string $tableName = NULL; + + public ?Connection $db = null; + + /** + * @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 InputInterface $input + */ + public function setInput(InputInterface $input) + { + $this->input = $input; + } + + + /** + * @param ReflectionClass $object + * @param $className + * + * @return string + */ + public function getUseContent(ReflectionClass $object, $className): string + { + 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 string $fileName + * @param ReflectionClass $class + * @return string + */ + protected function getImports(string $fileName, ReflectionClass $class): string + { + $startLine = 1; + $array = []; + $fileOpen = fopen($fileName, 'r'); + while (($content = fgets($fileOpen)) !== false) { + if (str_starts_with($content, 'use ')) { + $array[] = $content; + } + if ($startLine == $class->getStartLine()) { + break; + } + ++$startLine; + } + return implode($array); + } + + + /** + * @param ReflectionClass $class + * @return string + * @throws ReflectionException + */ + protected function getClassProperty(ReflectionClass $class): string + { + $html = ''; + + $rc = $class->getParentClass()->getConstants(); + + foreach ($class->getConstants() as $key => $val) { + if (isset($rc[$key])) { + continue; + } + 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 ($key == 'primary' || $key == 'table' || $key == 'connection' || $key == 'rules') { + continue; + } + 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->hasType()) { + $type = ' ' . $property->getType() . ' $' . $key . ' = ' . $val . ';' . "\n"; + } else { + $type = ' $' . $key . ' = ' . $val . ';' . "\n"; + } + if ($property->isStatic()) { + $html .= ' + ' . $debug . ' static' . $type; + } else { + $html .= ' + ' . $debug . $type; + } + + } + return $html; + } + + + /** + * @param ReflectionClass $class + * @param array $filters + * @return string + * @throws Exception + */ + protected function getClassMethods(ReflectionClass $class, array $filters = []): string + { + $methods = $class->getMethods(); + + $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, $filters)) continue; + $over = " + " . $val->getDocComment() . "\n"; + + $attributes = $val->getAttributes(); + if (!empty($attributes)) { + foreach ($attributes as $attribute) { + $explode = explode('\\', $attribute->getName()); + + $_array = []; + foreach ($attribute->getArguments() as $_key => $argument) { + $argument = $this->resolveArray($argument); + if (is_numeric($_key)) { + $_array[] = $argument; + } else { + $_array[] = $_key . ': ' . $argument . ''; + } + } + + if (empty($_array)) { + $end = " #[" . end($explode) . "] +"; + } else { + $end = " #[" . end($explode) . "(" . implode(',', $_array) . ")] +"; + } + if (str_contains($over, $end)) { + $over = str_replace($end, '', $over); + } + $over .= $end; + } + } + + $func = $this->getFuncLineContent($class, $classFileName, $val->name) . "\n"; + + $content[] = $over . $func; + } + return implode(PHP_EOL, $content); + } + + + /** + * @param $argument + * @return string + */ + private function resolveArray($argument): string + { + if (is_array($argument)) { + $__array = []; + foreach ($argument as $key => $value) { + if (is_string($value)) { + if (str_contains($value, '\\') && class_exists($value)) { + $explode_class = explode('\\', $value); + + $__array[] = end($explode_class) . '::class'; + } else { + $__array[] = '\'' . $value . '\''; + } + } else { + $value = str_replace('{', '[', Json::encode($value)); + $value = str_replace('}', ']', Json::encode($value)); + $value = str_replace(':', '=>', Json::encode($value)); + + $value = preg_replace('/"\d+"\=\>/', '', $value); + + $__array[] = $value; + } + } + + $argument = '[' . implode(', ', $__array) . ']'; + } else { + $argument = '\'' . $argument . '\''; + } + return $argument; + } + + + /** + * @param $fields + * @return mixed 返回表主键 + * 返回表主键 + */ + public function getPrimaryKey($fields): mixed + { + $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): string + { + 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(ReflectionClass $object, $className, $method): string + { + $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(): array + { + $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): string + { + return strtolower($val['Null']) == 'no' && $val['Default'] === NULL ? 'true' : 'false'; + } + + /** + * @return array + */ + public function getFileLists(): array + { + return $this->fileList; + } + +} diff --git a/GiiCommand.php b/GiiCommand.php new file mode 100644 index 0000000..81ae8c9 --- /dev/null +++ b/GiiCommand.php @@ -0,0 +1,76 @@ +setName('sw:gii') + ->addOption('make','m', InputArgument::OPTIONAL) + ->addOption('name','t', InputArgument::OPTIONAL) + ->addOption('databases','d', InputArgument::OPTIONAL) + ->setDescription('./snowflake sw:gii make=model|controller|task|interceptor|limits|middleware name=xxxx'); + } + + + /** + * @param InputInterface $input + * @param OutputInterface $output + * @return int + * @throws ConfigException + * @throws Exception + */ + public function execute(InputInterface $input, OutputInterface $output): int + { + /** @var Gii $gii */ + $gii = Kiri::app()->get('gii'); + + $connections = Kiri::app()->get('db'); + if (($db = $input->getOption('databases')) != null) { + $gii->run($connections->get($db), $input); + return 1; + } + + $action = $input->getOption('make'); + if (!in_array($action, ['model', 'controller'])) { + $gii->run(null, $input); + return 1; + } + + $array = []; + foreach (Config::get('databases.connections') as $key => $connection) { + $array[$key] = $gii->run($connections->get($key), $input); + } + + $output->writeln(json_encode($array, JSON_UNESCAPED_UNICODE)); + + return 1; + } + +} diff --git a/GiiController.php b/GiiController.php new file mode 100644 index 0000000..8016617 --- /dev/null +++ b/GiiController.php @@ -0,0 +1,537 @@ +className = $className; + $this->fields = $fields; + } + + + /** + * @return string|bool + * @throws ReflectionException + * @throws Exception + */ + public function generate(): string|bool + { + $path = $this->getControllerPath(); + $modelPath = $this->getModelPath(); + + $managerName = $this->className; + + $namespace = rtrim($path['namespace'], '\\'); + $model_namespace = rtrim($modelPath['namespace'], '\\'); + + $class = ''; + $controller = str_replace('\\\\', '\\', "$namespace\\{$managerName}Controller"); + + $html = "getImports($path['path'] . '/' . $managerName . 'Controller.php', $class); + } catch (\Throwable $Exception) { + logger()->addError($Exception, 'throwable'); + exit(); + } + } else { + $import = "use Kiri; +use Exception; +use Kiri\Annotation\Target; +use Kiri\Annotation\Route\Middleware; +use Kiri\Annotation\Route\Route; +use Kiri\Annotation\Route\RequestMethod; +use Kiri\Core\Str; +use Kiri\Core\Json; +use Kiri\Message\Controller; +use JetBrains\PhpStorm\ArrayShape; +use {$model_namespace}\\{$managerName}; +"; + } + if (!empty($import)) { + $html .= $import; + } + + $controllerName = $managerName; + + $historyModel = "use {$model_namespace}\\{$managerName};"; + if (!str_contains($html, $historyModel)) { + $html .= $historyModel; + } + + $html .= " + +/** + * Class {$controllerName}Controller + * + * @package controller + */ +#[Target] class {$controllerName}Controller extends Controller +{ + +"; + + + $funcNames = []; + if (is_object($class)) { + $html .= $this->getClassProperty($class); + $html .= $this->getClassMethods($class); + } + + $default = ['loadParam', 'actionAdd', 'actionUpdate', 'actionDetail', 'actionDelete', 'actionBatchDelete', 'actionList']; + + foreach ($default as $key => $val) { + if (str_contains($html, ' function ' . $val . '(')) { + continue; + } + $html .= $this->{'controllerMethod' . str_replace('action', '', $val)}($this->fields, $managerName, $managerName, $path) . "\n"; + } + + $html .= ' +}'; + + $file = $path['path'] . '/' . $controllerName . 'Controller.php'; + if (file_exists($file)) { + unlink($file); + } + + Kiri::writeFile($file, $html); + return $controllerName . 'Controller.php'; + } + + + /** + * @return array + */ + private function getControllerPath(): array + { + $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 + * @param $path + * @return string + * 新增 + */ + public function controllerMethodAdd($fields, $className, $object, $path): string + { + $_path = str_replace(CONTROLLER_PATH, '', $path['path']); + $_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className); + + $_path = ltrim($_path,'/'); + + return ' + /** + * @return string + * @throws Exception + */ + #[Route(uri: "' . $_path . '/add", method: RequestMethod::REQUEST_POST)] + #[Middleware(middleware: [])] + public function actionAdd(): string + { + $model = new ' . $className . '(); + $model->attributes = $this->loadParam(); + if (!$model->save()) { + return JSON::to(500, $model->getLastError()); + } + return JSON::to(0, $model->toArray()); + }'; + } + + /** + * @param $fields + * @param $className + * @param null $object + * @return string + * 通用 + */ + public function controllerMethodLoadParam($fields, $className, $object = NULL): string + { + return ' + /** + * @return array + * @throws Exception + */ + #[ArrayShape([])] + private function loadParam(): array + { + return [' . $this->getData($fields) . ' + ]; + }'; + } + + /** + * @param $fields + * @param $className + * @param null $object + * @param array $path + * @return string + * 构建更新 + */ + public function controllerMethodUpdate($fields, $className, $object = NULL, $path = []): string + { + $_path = str_replace(CONTROLLER_PATH, '', $path['path']); + $_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className); + + $_path = ltrim($_path,'/'); + + return ' + /** + * @return string + * @throws Exception + */ + #[Route(uri: "' . $_path . '/update", method: RequestMethod::REQUEST_POST)] + #[Middleware(middleware: [])] + public function actionUpdate(): string + { + $model = ' . $className . '::findOne($this->request->post(\'id\', 0)); + if (empty($model)) { + return JSON::to(500, SELECT_IS_NULL); + } + $model->attributes = $this->loadParam(); + + if (!$model->save()) { + return JSON::to(500, $model->getLastError()); + } + return JSON::to(0, $model->toArray()); + }'; + } + + /** + * @param $fields + * @param $className + * @param null $object + * @param array $path + * @return string + * 构建更新 + */ + public function controllerMethodBatchDelete($fields, $className, $object = NULL, $path = []): string + { + $_path = str_replace(CONTROLLER_PATH, '', $path['path']); + $_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className); + + $_path = ltrim($_path,'/'); + + return ' + /** + * @return string + * @throws Exception + */ + #[Route(uri: "' . $_path . '/batch-delete", method: RequestMethod::REQUEST_POST)] + #[Middleware(middleware: [])] + public function actionBatchDelete(): string + { + $_key = $this->request->array(\'ids\'); + if (empty($_key)) { + return JSON::to(500, PARAMS_IS_NULL); + } + + $model = ' . $className . '::find()->whereIn(\'id\', $_key); + if (!$model->delete()) { + return JSON::to(500, DB_ERROR_BUSY); + } + return JSON::to(0, $_key); + }'; + } + + /** + * @param $fields + * @param $className + * @param $managerName + * @param array $path + * @return string + * 构建详情 + */ + public function controllerMethodDetail($fields, $className, $managerName, $path = []): string + { + $_path = str_replace(CONTROLLER_PATH, '', $path['path']); + $_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className); + + $_path = ltrim($_path,'/'); + + return ' + /** + * @return string + * @throws Exception + */ + #[Route(uri: "' . $_path . '/detail", method: RequestMethod::REQUEST_POST)] + #[Middleware(middleware: [])] + public function actionDetail(): string + { + $model = ' . $managerName . '::findOne($this->request->query(\'id\')); + if (empty($model)) { + return JSON::to(404, SELECT_IS_NULL); + } + return JSON::to(0, $model->toArray()); + }'; + } + + /** + * @param $fields + * @param $className + * @param $managerName + * @param $path + * @return string + * 构建删除操作 + */ + public function controllerMethodDelete($fields, $className, $managerName, $path): string + { + $_path = str_replace(CONTROLLER_PATH, '', $path['path']); + $_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className); + + $_path = ltrim($_path,'/'); + + return ' + /** + * @return string + * @throws Exception + */ + #[Route(uri: "' . $_path . '/delete", method: RequestMethod::REQUEST_POST)] + #[Middleware(middleware: [])] + public function actionDelete(): string + { + $_key = $this->request->int(\'id\', true); + + $model = ' . $managerName . '::findOne($_key); + if (empty($model)) { + return JSON::to(500, SELECT_IS_NULL); + } + if (!$model->delete()) { + return JSON::to(500, $model->getLastError()); + } + return JSON::to(0, $model); + }'; + } + + /** + * @param $fields + * @param $className + * @param $managerName + * @param array $path + * @return string + * 构建查询列表 + */ + public function controllerMethodList($fields, $className, $managerName, $path = []): string + { + $_path = str_replace(CONTROLLER_PATH, '', $path['path']); + $_path = lcfirst(rtrim($_path, '/')) . '/' . lcfirst($className); + + + $_path = ltrim($_path,'/'); + + return ' + /** + * @return string + * @throws Exception + */ + #[Route(uri: "' . $_path . '/list", method: RequestMethod::REQUEST_GET)] + #[Middleware(middleware: [])] + public function actionList(): string + { + //分页处理 + $count = $this->request->query(\'count\', -1); + $order = $this->request->query(\'order\', \'id\'); + if (!empty($order)) { + $order .= !$this->request->query(\'isDesc\', 0) ? \' asc\' : \' desc\'; + } else { + $order = \'id desc\'; + } + + //列表输出 + $model = ' . $managerName . '::find()->where($this->request->gets())->orderBy($order); + + $keyword = $this->request->query(\'keyword\', null); + if (!empty($keyword)) { + $model->like(\'keyword\', $keyword); + } + + if ((int) $count === 1) { + $count = $model->count(); + } + if ($count != -100) { + $model->limit($this->request->offset() ,$this->request->size()); + } + + $data = $model->all()->toArray(); + + return JSON::to(0, $data, $count); + } + '; + } + + private function getData($fields): string + { + $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') { + $_tps = match ($type) { + 'date' => '$this->request->' . $_key . '(\'' . $val['Field'] . '\', date(\'Y-m-d\'))', + 'time' => '$this->request->' . $_key . '(\'' . $val['Field'] . '\', date(\'H:i:s\'))', + default => '$this->request->' . $_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 = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ', ' . $tmp . ')'; + } else if ($type == 'int') { + if ($number[0] == 10) { + $_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', time())'; + } else { + $_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ')'; + } + } else if ($type == 'float') { + $_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ', ' . ($number[3] ?? '2') . ')'; + } else if ($key == 'email') { + $_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', ' . $_field['required'] . ')'; + } else if ($key == 'timestamp') { + $_tps = '$this->request->' . $_key . '(\'' . $val['Field'] . '\', time())'; + } else { + $_tps = '$this->request->' . $_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; + } + + + /** + * @param $fields + * @return int + */ + private function getMaxLength($fields): int + { + $length = 0; + foreach ($fields as $key => $val) { + if (mb_strlen($val['Field'] . ' >=') > $length) $length = mb_strlen($val['Field'] . ' >='); + } + return $length; + } + + /** + * @param $fields + * @return string + */ + private function getWhere($fields): string + { + $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 = '$this->request->query(\'' . $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 = '$this->request->query(\'' . $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/GiiJsonRpc.php b/GiiJsonRpc.php new file mode 100644 index 0000000..fc4ceee --- /dev/null +++ b/GiiJsonRpc.php @@ -0,0 +1,113 @@ +createInterface($this->input->getArgument('name')), + $this->createProducers($this->input->getArgument('name')), + $this->createConsumer($this->input->getArgument('name')), + ]; + } + + + private function createInterface($name): string + { + $html = 'input->getArgument('name'); + if (empty($managerName)) { + throw new Exception('文件名称不能为空~'); + } + $html = 'classFileName = $classFileName; + $this->tableName = $tableName; + $this->visible = $visible; + $this->res = $res; + $this->fields = $fields; + } + + /** + * @throws ReflectionException + * @throws Exception + */ + public function generate(): string + { + $class = ''; + $modelPath = $this->getModelPath(); + $managerName = $this->classFileName; + + $namespace = rtrim($modelPath['namespace'], '\\'); + + if (file_exists($modelPath['path'] . '/' . $managerName . '.php')) { + try { + $className = str_replace('\\\\', '\\', "{$modelPath['namespace']}\\{$managerName}"); + + $class = Kiri::getDi()->getReflect($className); + + $html = 'getImports($modelPath['path'] . '/' . $managerName . '.php', $class); + if (!empty($imports)) { + $html .= $imports . PHP_EOL; + } + + if (!str_contains($imports, 'Database\Annotation\Set')) { + $html .= 'use Database\Annotation\Set;' . PHP_EOL; + } + if (!str_contains($imports, 'Database\Annotation\Get')) { + $html .= 'use Database\Annotation\Get;' . PHP_EOL; + } + } catch (\Throwable $e) { + logger()->addError($e, 'throwable'); + } + } + + + if (empty($html)) { + $html = 'setCreateSql($this->tableName); + + if (!str_contains($html, $createSql)) { + $html .= ' +' . $this->setCreateSql($this->tableName); + } + + $html .= ' + +/** + * Class ' . $managerName . ' + * @package Inter\mysql + *' . implode('', $this->visible) . ' + */ +#[Target] class ' . $managerName . ' extends Model +{ + +'; + + if (!empty($class)) { + $html .= $this->getClassProperty($class); + } + + $primary = $this->createPrimary($this->fields); + if (!empty($primary)) { + $html .= $primary . "\n"; + } + + $html .= $this->createTableName($this->tableName) . "\n"; + + $html .= $this->createDatabaseSource(); + + $html .= $this->createRules($this->fields); + + if (is_object($class)) { + $html .= $this->getClassMethods($class, ['rules', 'tableName', 'attributes', 'getDb']); + } else { + $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); + } + + Kiri::writeFile($file, $html); + return $managerName . '.php'; + } + + + /** + * @param $html + * @param $fields + * @return array + */ + private function generate_json_function($html, $fields): array + { + $strings = []; + foreach ($fields as $field) { + if ($field['Type'] === 'json') { + $function = ' + /** + * @param $value + * @return int|bool|string + * @throws Exception + */ + #[Set(\'' . $field['Field'] . '\')] + public function set' . ucfirst($field['Field']) . 'Attribute($value): int|bool|string + { + if ( !is_string($value) ) { + return JSON::encode($value); + } + return $value; + } + '; + + $get_function = ' + /** + * @param $value + * @return array|null|bool + */ + #[Get(\'' . $field['Field'] . '\')] + public function get' . ucfirst($field['Field']) . 'Attribute($value): array|null|bool + { + $value = stripcslashes($value); + if ( is_string($value) ) { + return JSON::decode($value, true); + } + return $value; + } + '; + + if (!str_contains($html, 'set' . ucfirst($field['Field']) . 'Attribute')) { + $strings[] = $function; + } + + if (!str_contains($html, 'get' . ucfirst($field['Field']) . 'Attribute')) { + $strings[] = $get_function; + } + } + } + + return $strings; + } + + + /** + * @param $field + * @return string + * 创建表名称 + */ + private function createTableName($field): string + { + + $prefixed = $this->db->tablePrefix; + if (!empty($prefixed)) { + if (str_starts_with($field, $prefixed)) { + $field = str_replace($prefixed, '', $field); + } + } + + return ' + /** + * @inheritdoc + */ + protected string $table = \'' . $field . '\'; +'; + } + + /** + * @param $fields + * @return string + * 创建效验规则 + */ + private function createRules($fields): string + { + $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): string + { + $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 (in_array($_val[0][1], $this->type['float'])) { + $e_x = explode(',', $key); + $key = '\'round\' => ' . $e_x[1] . ', \'maxLength\' => ' . ((int)$e_x[0] + 1); + } else if (is_string($key) && str_contains($key, ',')) { + } else { + $key = '\'maxLength\' => ' . $key; + } + if (count($_val) == 1) { + $_tmp = ' + [\'' . $_val[0][3] . '\', ' . ($_val[0][1] == 'enum' ? '\'enum\' => [' . $key .']' : $key) . ']'; + } else { + $_tmp = ' + [[\'' . implode('\', \'', array_column($_val, 3)) . '\'], ' . $key . ']'; + } + $string[] = $_tmp; + } + return implode(',', $string); + } + + /** + * @param $fields + * @return string + */ + public function getUnique($fields): string + { + $data = []; + foreach ($fields as $_val) { + if ($_val['Extra'] == 'auto_increment') continue; + if (str_contains($_val['Type'], 'unique')) { + $data[] = $_val['Field']; + } + } + if (empty($data)) { + return ''; + } + return ' + [[\'' . implode('\', \'', $data) . '\'], \'unique\'],'; + } + + /** + * @param $val + * @return string + */ + public function getRequired($val): string + { + $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): ?string + { + $field = $this->getPrimaryKey($fields); + if (empty($field)) { + return null; + } + return ' + /** + * @var string|null + */ + protected ?string $primary = \'' . $field . '\';'; + } + + /** + * @return string + */ + private function createDatabaseSource(): string + { + return ' + /** + * @var string + */ + protected string $connection = \'' . $this->db->id . '\'; +'; + } + + /** + * @param $table + * @return string + * @throws Exception + */ + private function setCreateSql($table): string + { + if (isset(Gii::$createSqls[$table])) { + return Gii::$createSqls[$table]; + } + + $text = Db::showCreateSql($table, $this->db)['Create Table'] ?? ''; + + $_tmp = []; + foreach (explode(PHP_EOL, $text) as $val) { + $_tmp[] = '// ' . $val; + } + + return Gii::$createSqls[$table] = implode(PHP_EOL, $_tmp); + } + + +} diff --git a/GiiProviders.php b/GiiProviders.php new file mode 100644 index 0000000..9330a94 --- /dev/null +++ b/GiiProviders.php @@ -0,0 +1,34 @@ +set('gii', ['class' => Gii::class]); + + $container = Kiri::getDi(); + + $console = $container->get(\Symfony\Component\Console\Application::class); + $console->add($container->get(GiiCommand::class)); + } +} diff --git a/GiiRpcClient.php b/GiiRpcClient.php new file mode 100644 index 0000000..dc4892f --- /dev/null +++ b/GiiRpcClient.php @@ -0,0 +1,100 @@ +input->getArgument('name', null); + if (empty($managerName)) { + throw new Exception('文件名称不能为空~'); + } + + $service = $this->input->getArgument('service', strtolower($managerName)); + + $port = $this->input->getArgument('port', 443); + $mode = $this->input->getArgument('mode', 'SWOOLE_SOCK_TCP'); + + $html = ' \'127.0.0.1\', \'port\' => 5377]; + + + /** + * @return Client + * @throws Exception + */ + public function initClient(): Client + { + // TODO: Implement initClient() method. + return $this->client = $this->rpc->getClient(\'' . $service . '\'); + } + + + + /** + * @param string $event + * @param array $params + * @throws Exception + */ + #[Consumer(\'default\')] + public function push(string $event, array $params) + { + + } +}'; + + if (!is_dir(APP_PATH . 'app/Client/Rpc/')) { + mkdir(APP_PATH . 'app/Client/Rpc/', 0777, true); + } + + $file = APP_PATH . 'app/Client/Rpc/' . $managerName . 'Middleware.php'; + if (file_exists($file)) { + throw new Exception('File exists.'); + } + + Kiri::writeFile($file, $html); + return [$managerName . 'Middleware.php']; + } +} diff --git a/GiiRpcService.php b/GiiRpcService.php new file mode 100644 index 0000000..7ce27fb --- /dev/null +++ b/GiiRpcService.php @@ -0,0 +1,79 @@ +input->getArgument('name', null); + if (empty($managerName)) { + throw new Exception('文件名称不能为空~'); + } + + $port = $this->input->getArgument('port', 443); + + $html = 'input->getArgument('name', null); + if (empty($managerName)) { + throw new Exception('文件名称不能为空~'); + } + $html = 'params = $params; + return $this; + } + + + /** + * @return array + */ + public function getParams() + { + return $this->params; + } + + +}'; + + $file = APP_PATH . 'app/Async/' . $managerName . '.php'; + if (file_exists($file)) { + throw new Exception('File exists.'); + } + + Kiri::writeFile($file, $html); + return [$managerName . '.php']; + } + +} diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..c91cd3d --- /dev/null +++ b/composer.json @@ -0,0 +1,22 @@ +{ + "name": "game-worker/kiri-gii", + "description": "gii", + "authors": [ + { + "name": "XiangLin", + "email": "as2252258@163.com" + } + ], + "license": "MIT", + "require": { + "php": ">=8.0", + "composer-runtime-api": "^2.0" + }, + "autoload": { + "psr-4": { + "Gii\\": "./" + } + }, + "require-dev": { + } +}