info('开始扫描 Protobuf 请求定义...'); // 获取所有模块 $modules = $this->scanModules(); // 生成配置数组 $config = $this->generateConfig($modules); // 生成配置文件 $this->generateConfigFile($config); $this->info('Protobuf 路由配置生成完成!'); // 输出提示信息 $this->showHandlerGuide($modules); return Command::SUCCESS; } protected function scanModules(): array { $modules = []; $baseDir = base_path($this->protoDir); // 扫描 Request 目录 $requestDir = $baseDir . '/Request'; if (File::isDirectory($requestDir)) { // 扫描所有 Request 开头的 PHP 文件 $files = File::glob($requestDir . '/Request*.php'); foreach ($files as $file) { $className = basename($file, '.php'); if (strpos($className, 'Request') === 0 && $className !== 'Request') { // 解析模块和方法 $this->parseRequestClass($className, $modules); } } } // 扫描根目录下的 Request 文件 $rootFiles = File::glob($baseDir . '/Request*.php'); foreach ($rootFiles as $file) { $className = basename($file, '.php'); if (strpos($className, 'Request') === 0 && $className !== 'Request') { // 解析模块和方法 $this->parseRequestClass($className, $modules); } } return $modules; } /** * 解析请求类名,提取模块和方法 * * @param string $className 请求类名,如 RequestPublicLogin * @param array &$modules 模块数组,按引用传递 * @return void */ protected function parseRequestClass(string $className, array &$modules): void { // 如果是 RequestPublicLogin 格式,则直接处理 if ($className === 'RequestPublicLogin') { if (!isset($modules['public'])) { $modules['public'] = []; } if (!in_array('login', $modules['public'])) { $modules['public'][] = 'login'; } return; } // 如果是 Request_RequestPublicLogin 格式,则跳过 if (strpos($className, 'Request_Request') === 0) { return; } // 移除 Request 前缀 $name = substr($className, strlen('Request')); // 检查是否包含下划线,表示有方法部分 if (strpos($name, '_') !== false) { // 格式如 Public_Login list($module, $method) = explode('_', $name, 2); } else { // 如果是 RequestPublicLogin 这样的格式,需要特殊处理 if (preg_match('/^([A-Z][a-z]+)([A-Z].*)$/', $name, $matches)) { $module = $matches[1]; // Public $method = $matches[2]; // Login } else { // 其他格式,如果没有明显的分隔,则整个作为模块 $module = $name; $method = ''; } } // 模块名首字母小写 $moduleKey = lcfirst($module); // 方法名转为小写下划线格式 $methodKey = Str::snake(lcfirst($method)); // 如果方法为空,则不添加 if (!empty($methodKey)) { if (!isset($modules[$moduleKey])) { $modules[$moduleKey] = []; } if (!in_array($methodKey, $modules[$moduleKey])) { $modules[$moduleKey][] = $methodKey; } } } protected function extractMethodsFromContent(string $content): array { // 不再从文件内容中提取方法,而是从类名中解析 return []; } protected function scanMethodFields(string $moduleDir): array { return []; // 不再需要扫描子目录 } protected function generateConfig(array $modules): array { $routes = []; foreach ($modules as $field => $methods) { if (!empty($methods) && !empty($field)) { $routes[$field] = array_values($methods); } } return [ 'routes' => $routes, 'generated_at' => date('P Y-m-d H:i:s'), 'conventions' => [ 'handler_namespace' => 'App\\Module\\AppGame\\Handler', 'request_namespace' => 'Uraus\\Kku\\Request', 'response_namespace' => 'Uraus\\Kku\\Response' ] ]; } protected function generateConfigFile(array $config): void { $configContent = "option('force')) { if (!$this->confirm('配置文件已存在,是否覆盖?')) { $this->warn('操作已取消'); return; } } File::put($configPath, $configContent); $this->info("配置文件已生成:{$configPath}"); } protected function showHandlerGuide(array $modules): void { $this->info("\n按照以下约定创建处理器类:\n"); foreach ($modules as $field => $methods) { if (empty($methods)) { continue; } $moduleName = ucfirst($field); $this->line("\n模块: {$moduleName} (字段: {$field})"); foreach ($methods as $method) { $methodName = Str::studly($method); $handlerClass = "App\\Module\\AppGame\\Handler\\{$moduleName}\\{$methodName}Handler"; $requestClass = "Uraus\\Kku\\Request\\Request{$moduleName}" . ($method ? "_" . Str::studly($method) : ""); $responseClass = "Uraus\\Kku\\Response\\Response{$moduleName}" . ($method ? "_" . Str::studly($method) : ""); $this->line("\n 方法: {$method}"); $this->line(" - Handler: {$handlerClass}"); $this->line(" - Request: {$requestClass}"); $this->line(" - Response: {$responseClass}"); } } $this->info("\n提示:处理器类会根据约定自动加载,无需手动配置。"); } }