| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- <?php
- namespace App\Module\ThirdParty\Commands;
- use Illuminate\Console\Command;
- use App\Module\ThirdParty\Models\ThirdPartyService;
- use App\Module\ThirdParty\Enums\SERVICE_TYPE;
- use App\Module\ThirdParty\Enums\AUTH_TYPE;
- /**
- * 第三方服务同步命令
- */
- class SyncServicesCommand extends Command
- {
- /**
- * 命令签名
- *
- * @var string
- */
- protected $signature = 'thirdparty:sync-services
- {--config= : 配置文件路径}
- {--dry-run : 只显示将要同步的服务,不实际执行}
- {--force : 强制覆盖现有服务}';
- /**
- * 命令描述
- *
- * @var string
- */
- protected $description = '从配置文件同步第三方服务';
- /**
- * 执行命令
- *
- * @return int
- */
- public function handle(): int
- {
- $this->info('开始同步第三方服务...');
- try {
- $services = $this->loadServicesConfig();
-
- if (empty($services)) {
- $this->warn('没有找到需要同步的服务配置');
- return Command::SUCCESS;
- }
- $this->displayServicesToSync($services);
- if ($this->option('dry-run')) {
- $this->info('这是预览模式,没有实际同步服务');
- return Command::SUCCESS;
- }
- if (!$this->option('force') && !$this->confirm('确认要同步这些服务吗?')) {
- $this->info('操作已取消');
- return Command::SUCCESS;
- }
- $results = $this->syncServices($services);
- $this->displayResults($results);
- return Command::SUCCESS;
- } catch (\Exception $e) {
- $this->error("同步失败: {$e->getMessage()}");
- return Command::FAILURE;
- }
- }
- /**
- * 加载服务配置
- *
- * @return array
- */
- protected function loadServicesConfig(): array
- {
- $configPath = $this->option('config');
-
- if ($configPath) {
- if (!file_exists($configPath)) {
- throw new \Exception("配置文件不存在: {$configPath}");
- }
-
- $config = json_decode(file_get_contents($configPath), true);
- if (json_last_error() !== JSON_ERROR_NONE) {
- throw new \Exception("配置文件格式错误: " . json_last_error_msg());
- }
-
- return $config['services'] ?? [];
- }
- // 使用默认配置
- return $this->getDefaultServicesConfig();
- }
- /**
- * 获取默认服务配置
- *
- * @return array
- */
- protected function getDefaultServicesConfig(): array
- {
- return [
- [
- 'name' => '阿里云短信服务',
- 'code' => 'aliyun_sms',
- 'type' => 'SMS',
- 'provider' => 'ALIYUN',
- 'description' => '阿里云短信发送服务',
- 'base_url' => 'https://dysmsapi.aliyuncs.com',
- 'auth_type' => 'API_KEY',
- 'status' => 'INACTIVE',
- ],
- [
- 'name' => '腾讯云短信服务',
- 'code' => 'tencent_sms',
- 'type' => 'SMS',
- 'provider' => 'TENCENT',
- 'description' => '腾讯云短信发送服务',
- 'base_url' => 'https://sms.tencentcloudapi.com',
- 'auth_type' => 'SIGNATURE',
- 'status' => 'INACTIVE',
- ],
- [
- 'name' => '支付宝支付',
- 'code' => 'alipay',
- 'type' => 'PAYMENT',
- 'provider' => 'ALIPAY',
- 'description' => '支付宝开放平台支付服务',
- 'base_url' => 'https://openapi.alipay.com/gateway.do',
- 'auth_type' => 'SIGNATURE',
- 'status' => 'INACTIVE',
- ],
- [
- 'name' => '微信支付',
- 'code' => 'wechat_pay',
- 'type' => 'PAYMENT',
- 'provider' => 'WECHAT',
- 'description' => '微信支付API服务',
- 'base_url' => 'https://api.mch.weixin.qq.com',
- 'auth_type' => 'SIGNATURE',
- 'status' => 'INACTIVE',
- ],
- ];
- }
- /**
- * 显示将要同步的服务
- *
- * @param array $services
- * @return void
- */
- protected function displayServicesToSync(array $services): void
- {
- $this->info("\n将要同步的服务:");
- $this->line(str_repeat('-', 80));
- $headers = ['名称', '代码', '类型', '提供商', '状态'];
- $rows = [];
- foreach ($services as $service) {
- $rows[] = [
- $service['name'],
- $service['code'],
- $service['type'],
- $service['provider'],
- $service['status'] ?? 'INACTIVE',
- ];
- }
- $this->table($headers, $rows);
- }
- /**
- * 同步服务
- *
- * @param array $services
- * @return array
- */
- protected function syncServices(array $services): array
- {
- $results = [
- 'created' => [],
- 'updated' => [],
- 'skipped' => [],
- 'failed' => [],
- ];
- $progressBar = $this->output->createProgressBar(count($services));
- $progressBar->start();
- foreach ($services as $serviceConfig) {
- try {
- $result = $this->syncSingleService($serviceConfig);
- $results[$result['action']][] = $result;
-
- $this->line("\n{$result['action']}: {$serviceConfig['name']}");
-
- } catch (\Exception $e) {
- $results['failed'][] = [
- 'service' => $serviceConfig,
- 'error' => $e->getMessage(),
- ];
- $this->line("\n<fg=red>失败: {$serviceConfig['name']}: {$e->getMessage()}</fg>");
- }
-
- $progressBar->advance();
- }
- $progressBar->finish();
- $this->line('');
- return $results;
- }
- /**
- * 同步单个服务
- *
- * @param array $serviceConfig
- * @return array
- */
- protected function syncSingleService(array $serviceConfig): array
- {
- // 验证配置
- $this->validateServiceConfig($serviceConfig);
- $existingService = ThirdPartyService::where('code', $serviceConfig['code'])->first();
- if ($existingService) {
- if ($this->option('force')) {
- // 更新现有服务
- $existingService->update($serviceConfig);
- return [
- 'action' => 'updated',
- 'service' => $existingService,
- ];
- } else {
- // 跳过现有服务
- return [
- 'action' => 'skipped',
- 'service' => $existingService,
- 'reason' => '服务已存在',
- ];
- }
- } else {
- // 创建新服务
- $service = ThirdPartyService::create($serviceConfig);
- return [
- 'action' => 'created',
- 'service' => $service,
- ];
- }
- }
- /**
- * 验证服务配置
- *
- * @param array $config
- * @return void
- * @throws \Exception
- */
- protected function validateServiceConfig(array $config): void
- {
- $required = ['name', 'code', 'type', 'provider', 'auth_type'];
-
- foreach ($required as $field) {
- if (empty($config[$field])) {
- throw new \Exception("服务配置缺少必填字段: {$field}");
- }
- }
- // 验证服务类型
- if (!SERVICE_TYPE::tryFrom($config['type'])) {
- throw new \Exception("无效的服务类型: {$config['type']}");
- }
- // 验证认证类型
- if (!AUTH_TYPE::tryFrom($config['auth_type'])) {
- throw new \Exception("无效的认证类型: {$config['auth_type']}");
- }
- // 验证URL格式
- if (isset($config['base_url']) && !filter_var($config['base_url'], FILTER_VALIDATE_URL)) {
- throw new \Exception("无效的基础URL: {$config['base_url']}");
- }
- }
- /**
- * 显示同步结果
- *
- * @param array $results
- * @return void
- */
- protected function displayResults(array $results): void
- {
- $this->line(str_repeat('-', 80));
- $this->info('同步结果:');
- $created = count($results['created']);
- $updated = count($results['updated']);
- $skipped = count($results['skipped']);
- $failed = count($results['failed']);
- $this->line("<fg=green>创建: {$created}</fg>");
- $this->line("<fg=blue>更新: {$updated}</fg>");
- $this->line("<fg=yellow>跳过: {$skipped}</fg>");
- $this->line("<fg=red>失败: {$failed}</fg>");
- // 显示失败的详情
- if ($failed > 0) {
- $this->line('');
- $this->error('失败的服务:');
- foreach ($results['failed'] as $failure) {
- $this->line("- {$failure['service']['name']}: {$failure['error']}");
- }
- }
- // 显示跳过的详情
- if ($skipped > 0 && !$this->option('force')) {
- $this->line('');
- $this->warn('跳过的服务 (使用 --force 强制更新):');
- foreach ($results['skipped'] as $skipped) {
- $this->line("- {$skipped['service']['name']}: {$skipped['reason']}");
- }
- }
- }
- /**
- * 生成示例配置文件
- *
- * @return void
- */
- protected function generateExampleConfig(): void
- {
- $config = [
- 'services' => $this->getDefaultServicesConfig()
- ];
- $configPath = storage_path('app/thirdparty_services_example.json');
- file_put_contents($configPath, json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
- $this->info("示例配置文件已生成: {$configPath}");
- }
- }
|