# XBoard 插件开发指南 ## 插件结构 每个插件都是一个独立目录,推荐结构如下: ``` plugins/ └── YourPlugin/ # 插件目录(PascalCase 命名) ├── Plugin.php # 插件主类(必需) ├── config.json # 插件配置(必需) ├── routes/ │ └── api.php # API 路由 ├── Controllers/ # 控制器目录 │ └── YourController.php ├── Commands/ # Artisan 命令目录 │ └── YourCommand.php └── README.md # 文档说明 ``` ## 快速开始 ### 1. 创建配置文件 `config.json` ```json { "name": "My Plugin", "code": "my_plugin", // Corresponds to plugin directory (lowercase + underscore) "version": "1.0.0", "description": "Plugin functionality description", "author": "Author Name", "require": { "xboard": ">=1.0.0" // Version not fully implemented yet }, "config": { "api_key": { "type": "string", "default": "", "label": "API Key", "description": "API Key" }, "timeout": { "type": "number", "default": 300, "label": "Timeout (seconds)", "description": "Timeout in seconds" } } } ``` ### 2. 创建插件主类 `Plugin.php` ```php filter('guest_comm_config', function ($config) { $config['my_plugin_enable'] = true; $config['my_plugin_setting'] = $this->getConfig('api_key', ''); return $config; }); } } ``` ### 3. 创建控制器 推荐做法:继承 `PluginController`。 ```php getConfig('api_key'); $timeout = $this->getConfig('timeout', 300); // Your business logic... return $this->success(['message' => 'Success']); } } ``` ### 4. 创建路由 `routes/api.php` ```php 'api/v1/your-plugin' ], function () { Route::post('/handle', [YourController::class, 'handle']); }); ``` ## 配置访问 在控制器中可直接访问插件配置: ```php // Get single configuration $value = $this->getConfig('key', 'default_value'); // Get all configurations $allConfig = $this->getConfig(); // Check if plugin is enabled $enabled = $this->isPluginEnabled(); ``` ## Hook 系统 ### 常用 Hook(建议优先关注) XBoard 在多个关键业务节点提供了内置 hook。插件可通过 `filter` 或 `listen` 扩展行为。 | Hook 名称 | 类型 | 常见参数 | 说明 | | ------------------------- | ------ | ----------------------- | ---- | | user.register.before | action | Request | 用户注册前 | | user.register.after | action | User | 用户注册后 | | user.login.after | action | User | 用户登录后 | | user.password.reset.after | action | User | 密码重置后 | | order.cancel.before | action | Order | 订单取消前 | | order.cancel.after | action | Order | 订单取消后 | | payment.notify.before | action | method, uuid, request | 支付回调校验前 | | payment.notify.verified | action | array | 支付回调校验成功 | | payment.notify.failed | action | method, uuid, request | 支付回调校验失败 | | traffic.reset.after | action | User | 流量重置后 | | ticket.create.after | action | Ticket | 工单创建后 | | ticket.reply.user.after | action | Ticket | 用户回复工单后 | | ticket.close.after | action | Ticket | 工单关闭后 | > hook 能力会持续扩展。可结合本文与 `php artisan hook:list` 获取最新支持列表。 ### Filter Hook 用于修改数据: ```php // In Plugin.php boot() method $this->filter('guest_comm_config', function ($config) { // Add configuration for frontend $config['my_setting'] = $this->getConfig('setting'); return $config; }); ``` ### Action Hook 用于执行动作: ```php $this->listen('user.created', function ($user) { // Operations after user creation $this->doSomething($user); }); ``` ## 实战示例:Telegram 登录插件 下面使用 TelegramLogin 插件展示完整实现思路。 ### 插件主类 ```php filter('guest_comm_config', function ($config) { $config['telegram_login_enable'] = true; $config['telegram_login_domain'] = $this->getConfig('domain', ''); $config['telegram_bot_username'] = $this->getConfig('bot_username', ''); return $config; }); } } ``` ### 控制器(继承 `PluginController`) ```php class TelegramLoginController extends PluginController { public function telegramLogin(Request $request) { // Check plugin status if ($error = $this->beforePluginAction()) { return $error[1]; } // Get configuration $botToken = $this->getConfig('bot_token'); $timeout = $this->getConfig('auth_timeout', 300); // Business logic... return $this->success($result); } } ``` ## 插件定时任务(Scheduler) 插件可在主类中实现 `schedule(Schedule $schedule)` 方法来注册定时任务。 ```php use Illuminate\Console\Scheduling\Schedule; class Plugin extends AbstractPlugin { public function schedule(Schedule $schedule): void { // Execute every hour $schedule->call(function () { // Your scheduled task logic \Log::info('Plugin scheduled task executed'); })->hourly(); } } ``` - 只需在 `Plugin.php` 中实现 `schedule()`。 - 主程序会自动调度所有插件任务。 - 支持 Laravel Scheduler 的全部能力。 ## 插件 Artisan 命令 插件启用后,会自动加载 `Commands/` 目录中的命令类。 ### 命令目录结构 ``` plugins/YourPlugin/ ├── Commands/ │ ├── TestCommand.php # 测试命令 │ ├── BackupCommand.php # 备份命令 │ └── CleanupCommand.php # 清理命令 ``` ### 创建命令类 示例:`TestCommand.php` ```php argument('action'); $message = $this->option('message'); try { return match ($action) { 'ping' => $this->ping($message), 'info' => $this->showInfo(), default => $this->showHelp() }; } catch (\Exception $e) { $this->error('Operation failed: ' . $e->getMessage()); return 1; } } protected function ping(string $message): int { $this->info("✅ {$message}"); return 0; } protected function showInfo(): int { $this->info('Plugin Information:'); $this->table( ['Property', 'Value'], [ ['Plugin Name', 'YourPlugin'], ['Version', '1.0.0'], ['Status', 'Enabled'], ] ); return 0; } protected function showHelp(): int { $this->info('Usage:'); $this->line(' php artisan your-plugin:test ping --message="Hello" # Test'); $this->line(' php artisan your-plugin:test info # Show info'); return 0; } } ``` ### 自动注册规则 - 插件启用时,自动注册 `Commands/` 目录下全部命令类。 - 命令命名空间自动按 `Plugin\YourPlugin\Commands` 解析。 - 支持 Laravel 命令全部能力(参数、选项、交互等)。 ### 使用示例 ```bash # Test command php artisan your-plugin:test ping --message="Hello World" # Show information php artisan your-plugin:test info # View help php artisan your-plugin:test --help ``` ### 命令开发建议 1. **命令命名**:使用 `plugin-name:action`,例如 `telegram:test`。 2. **异常处理**:主流程建议统一 `try-catch`。 3. **返回码规范**:成功返回 `0`,失败返回 `1`。 4. **可用性**:提供清晰的帮助信息和错误提示。 5. **类型声明**:建议使用 PHP 8.2 类型声明。 ## 开发工具与基础能力 ### 控制器基类选择 #### 方案一:继承 `PluginController`(推荐) - 自动配置读取:`$this->getConfig()` - 自动状态检查:`$this->beforePluginAction()` - 统一返回与错误处理 #### 方案二:使用 `HasPluginConfig` Trait ```php use App\Http\Controllers\Controller; use App\Traits\HasPluginConfig; class YourController extends Controller { use HasPluginConfig; public function handle() { $config = $this->getConfig('key'); // ... } } ``` ### 配置类型 支持以下配置类型: - `string`:字符串 - `number`:数字 - `boolean`:布尔值 - `json`:数组 - `yaml` ## 通用最佳实践 ### 1. 保持主类简洁 - `Plugin.php` 只保留启动相关逻辑。 - 主要负责注册 hooks、路由、调度等入口。 - 复杂业务放到 Controller 或 Service。 ### 2. 统一配置管理 - 所有配置都在 `config.json` 明确定义。 - 通过 `$this->getConfig()` 读取。 - 所有项建议提供默认值。 ### 3. 路由设计清晰 - 使用语义化前缀。 - API 路由放在 `routes/api.php`。 - Web 路由放在 `routes/web.php`。 ### 4. 完善错误处理 ```php public function handle(Request $request) { // Check plugin status if ($error = $this->beforePluginAction()) { return $error[1]; } try { // Business logic return $this->success($result); } catch (\Exception $e) { return $this->fail([500, $e->getMessage()]); } } ``` ## 调试技巧 ### 1. 日志记录 ```php \Log::info('Plugin operation', ['data' => $data]); \Log::error('Plugin error', ['error' => $e->getMessage()]); ``` ### 2. 配置校验 ```php // Check required configuration if (!$this->getConfig('required_key')) { return $this->fail([400, 'Missing configuration']); } ``` ### 3. 开发模式 ```php if (config('app.debug')) { // Detailed debug information for development environment } ``` ## 插件生命周期 1. **安装**:校验配置并注册到数据库。 2. **启用**:加载插件并注册 hooks、路由、命令、调度。 3. **运行**:处理请求并执行业务逻辑。 ## 阶段总结 结合 TelegramLogin 插件的实践经验: - **简洁**:主类短小、职责单一。 - **实用**:基于 `PluginController`,开发效率高。 - **可维护**:目录结构清晰,模式统一。 - **可扩展**:通过 hooks 可快速扩展业务。 ## 插件 Artisan 命令完整指南 ### 功能亮点 - **自动注册**:插件启用时自动注册 `Commands/` 下命令。 - **命名空间隔离**:各插件命令互不冲突。 - **类型安全**:支持 PHP 8.2 类型声明。 - **异常处理**:可统一错误输出与退出码。 - **配置集成**:命令中可读取插件配置。 - **交互支持**:支持输入、确认、选择等交互流程。 ### 真实案例 #### 1. Telegram 插件命令 ```bash # Test Bot connection php artisan telegram:test ping # Send message php artisan telegram:test send --message="Hello World" # Get Bot information php artisan telegram:test info ``` #### 2. TelegramExtra 插件命令 ```bash # Show all statistics php artisan telegram-extra:stats all # User statistics php artisan telegram-extra:stats users # JSON format output php artisan telegram-extra:stats users --format=json ``` #### 3. Example 插件命令 ```bash # Basic usage php artisan example:hello # With arguments and options php artisan example:hello Bear --message="Welcome!" ``` ### 命令开发规范 #### 1. 命名约定 ```php // ✅ Recommended: Use plugin name as prefix protected $signature = 'telegram:test {action}'; protected $signature = 'telegram-extra:stats {type}'; protected $signature = 'example:hello {name}'; // ❌ Avoid: Use generic names protected $signature = 'test {action}'; protected $signature = 'stats {type}'; ``` #### 2. 异常处理模式 ```php public function handle(): int { try { // Main logic return $this->executeAction(); } catch (\Exception $e) { $this->error('Operation failed: ' . $e->getMessage()); return 1; } } ``` #### 3. 交互能力 ```php // Get user input $chatId = $this->ask('Please enter chat ID'); // Confirm operation if (!$this->confirm('Are you sure you want to execute this operation?')) { $this->info('Operation cancelled'); return 0; } // Choose operation $action = $this->choice('Choose operation', ['ping', 'send', 'info']); ``` #### 4. 配置访问 ```php // Access plugin configuration in commands protected function getConfig(string $key, $default = null): mixed { // Get plugin instance through PluginManager $plugin = app(\App\Services\Plugin\PluginManager::class) ->getEnabledPlugins()['example_plugin'] ?? null; return $plugin ? $plugin->getConfig($key, $default) : $default; } ``` ### 进阶用法 #### 1. 多命令插件 ```php // One plugin can have multiple commands plugins/YourPlugin/Commands/ ├── BackupCommand.php # Backup command ├── CleanupCommand.php # Cleanup command ├── StatsCommand.php # Statistics command └── TestCommand.php # Test command ``` #### 2. 命令间通信 ```php // Share data between commands through cache or database Cache::put('plugin:backup:progress', $progress, 3600); $progress = Cache::get('plugin:backup:progress'); ``` #### 3. 与定时任务联动 ```php // Call commands in plugin's schedule method public function schedule(Schedule $schedule): void { $schedule->command('your-plugin:backup')->daily(); $schedule->command('your-plugin:cleanup')->weekly(); } ``` ### 命令调试建议 #### 1. 命令测试 ```bash # View command help php artisan your-plugin:command --help # Verbose output php artisan your-plugin:command --verbose # Debug mode php artisan your-plugin:command --debug ``` #### 2. 命令日志 ```php // Log in commands Log::info('Plugin command executed', [ 'command' => $this->signature, 'arguments' => $this->arguments(), 'options' => $this->options() ]); ``` #### 3. 性能监控 ```php // Record command execution time $startTime = microtime(true); // ... execution logic $endTime = microtime(true); $this->info("Execution time: " . round(($endTime - $startTime) * 1000, 2) . "ms"); ``` ### 常见问题 #### Q: 命令没有出现在列表里? A: 检查插件是否启用,并确认 `Commands/` 目录存在且命令类有效。 #### Q: 命令执行失败? A: 检查命名空间是否正确,且类继承了 `Illuminate\Console\Command`。 #### Q: 如何在命令中读取插件配置? A: 通过 `PluginManager` 获取插件实例,再调用 `getConfig()`。 #### Q: 命令能否调用其他命令? A: 可以,使用 `Artisan::call()`。 ```php Artisan::call('other-plugin:command', ['arg' => 'value']); ``` ### 总结 插件命令系统为 XBoard 提供了强扩展能力: - **开发效率**:快速构建运维与管理命令 - **运维便利**:支持自动化日常操作 - **监控能力**:便于查看系统运行状态 - **调试支持**:可快速定位与排查问题 合理使用插件命令,可以显著提升系统可维护性和使用体验。