errors = []; // 验证必填字段 $this->validateRequired($data, [ 'name' => '服务名称', 'type' => '服务类型', 'provider' => '服务提供商', 'auth_type' => '认证类型', ]); // 验证字段格式 $this->validateServiceData($data); // 验证代码唯一性 if (isset($data['code'])) { $this->validateCodeUnique($data['code']); } return empty($this->errors); } /** * 验证更新服务数据 * * @param array $data * @param int $serviceId * @return bool */ public function validateUpdate(array $data, int $serviceId): bool { $this->errors = []; // 验证字段格式 $this->validateServiceData($data); // 验证代码唯一性(排除当前服务) if (isset($data['code'])) { $this->validateCodeUnique($data['code'], $serviceId); } return empty($this->errors); } /** * 验证服务状态更新 * * @param string $status * @param int $serviceId * @return bool */ public function validateStatusUpdate(string $status, int $serviceId): bool { $this->errors = []; // 验证状态值 if (!SERVICE_STATUS::tryFrom($status)) { $this->addError('status', '无效的服务状态'); return false; } $service = ThirdPartyService::find($serviceId); if (!$service) { $this->addError('service', '服务不存在'); return false; } $newStatus = SERVICE_STATUS::from($status); $currentStatus = SERVICE_STATUS::from($service->status); // 验证状态转换 if (!$currentStatus->canTransitionTo($newStatus)) { $this->addError('status', "不能从状态 {$currentStatus->getLabel()} 转换到 {$newStatus->getLabel()}"); } // 如果要激活服务,检查前置条件 if ($newStatus === SERVICE_STATUS::ACTIVE) { $this->validateActivationRequirements($service); } return empty($this->errors); } /** * 验证服务删除 * * @param int $serviceId * @return bool */ public function validateDelete(int $serviceId): bool { $this->errors = []; $service = ThirdPartyService::find($serviceId); if (!$service) { $this->addError('service', '服务不存在'); return false; } // 检查服务状态 if ($service->status === SERVICE_STATUS::ACTIVE->value) { $this->addError('status', '活跃状态的服务无法删除,请先停用服务'); } // 检查是否有活跃的凭证 $activeCredentials = $service->credentials()->where('is_active', true)->count(); if ($activeCredentials > 0) { $this->addError('credentials', "服务有 {$activeCredentials} 个活跃凭证,无法删除"); } // 检查是否有最近的调用记录 $recentLogs = $service->logs()->where('created_at', '>', now()->subHours(1))->count(); if ($recentLogs > 0) { $this->addError('logs', '服务在1小时内有调用记录,无法删除'); } return empty($this->errors); } /** * 验证服务数据 * * @param array $data * @return void */ protected function validateServiceData(array $data): void { // 验证服务类型 if (isset($data['type']) && !SERVICE_TYPE::tryFrom($data['type'])) { $this->addError('type', '不支持的服务类型'); } // 验证认证类型 if (isset($data['auth_type']) && !AUTH_TYPE::tryFrom($data['auth_type'])) { $this->addError('auth_type', '不支持的认证类型'); } // 验证服务状态 if (isset($data['status']) && !SERVICE_STATUS::tryFrom($data['status'])) { $this->addError('status', '无效的服务状态'); } // 验证名称长度 if (isset($data['name'])) { if (strlen($data['name']) < 2) { $this->addError('name', '服务名称至少需要2个字符'); } if (strlen($data['name']) > 100) { $this->addError('name', '服务名称不能超过100个字符'); } } // 验证代码格式 if (isset($data['code'])) { if (!preg_match('/^[a-z0-9_]+$/', $data['code'])) { $this->addError('code', '服务代码只能包含小写字母、数字和下划线'); } if (strlen($data['code']) < 3) { $this->addError('code', '服务代码至少需要3个字符'); } if (strlen($data['code']) > 50) { $this->addError('code', '服务代码不能超过50个字符'); } } // 验证提供商 if (isset($data['provider'])) { if (strlen($data['provider']) < 2) { $this->addError('provider', '服务提供商至少需要2个字符'); } if (strlen($data['provider']) > 50) { $this->addError('provider', '服务提供商不能超过50个字符'); } } // 验证URL格式 if (isset($data['base_url']) && !empty($data['base_url'])) { if (!filter_var($data['base_url'], FILTER_VALIDATE_URL)) { $this->addError('base_url', '基础URL格式无效'); } } if (isset($data['health_check_url']) && !empty($data['health_check_url'])) { if (!filter_var($data['health_check_url'], FILTER_VALIDATE_URL)) { $this->addError('health_check_url', '健康检查URL格式无效'); } } if (isset($data['webhook_url']) && !empty($data['webhook_url'])) { if (!filter_var($data['webhook_url'], FILTER_VALIDATE_URL)) { $this->addError('webhook_url', 'Webhook URL格式无效'); } } // 验证数值范围 if (isset($data['timeout'])) { if (!is_numeric($data['timeout']) || $data['timeout'] < 1 || $data['timeout'] > 300) { $this->addError('timeout', '超时时间必须在1-300秒之间'); } } if (isset($data['retry_times'])) { if (!is_numeric($data['retry_times']) || $data['retry_times'] < 0 || $data['retry_times'] > 10) { $this->addError('retry_times', '重试次数必须在0-10次之间'); } } if (isset($data['retry_delay'])) { if (!is_numeric($data['retry_delay']) || $data['retry_delay'] < 100 || $data['retry_delay'] > 60000) { $this->addError('retry_delay', '重试延迟必须在100-60000毫秒之间'); } } if (isset($data['priority'])) { if (!is_numeric($data['priority']) || $data['priority'] < 0 || $data['priority'] > 999) { $this->addError('priority', '优先级必须在0-999之间'); } } if (isset($data['health_check_interval'])) { if (!is_numeric($data['health_check_interval']) || $data['health_check_interval'] < 60 || $data['health_check_interval'] > 86400) { $this->addError('health_check_interval', '健康检查间隔必须在60-86400秒之间'); } } // 验证JSON格式 if (isset($data['config']) && !empty($data['config'])) { if (is_string($data['config'])) { json_decode($data['config']); if (json_last_error() !== JSON_ERROR_NONE) { $this->addError('config', '配置信息必须是有效的JSON格式'); } } } if (isset($data['headers']) && !empty($data['headers'])) { if (is_string($data['headers'])) { json_decode($data['headers']); if (json_last_error() !== JSON_ERROR_NONE) { $this->addError('headers', '请求头必须是有效的JSON格式'); } } } if (isset($data['params']) && !empty($data['params'])) { if (is_string($data['params'])) { json_decode($data['params']); if (json_last_error() !== JSON_ERROR_NONE) { $this->addError('params', '默认参数必须是有效的JSON格式'); } } } } /** * 验证激活服务的前置条件 * * @param ThirdPartyService $service * @return void */ protected function validateActivationRequirements(ThirdPartyService $service): void { // 检查是否有可用的凭证 $hasActiveCredential = $service->credentials() ->where('is_active', true) ->where(function ($query) { $query->whereNull('expires_at') ->orWhere('expires_at', '>', now()); }) ->exists(); if (!$hasActiveCredential) { $this->addError('credentials', '服务没有可用的认证凭证,无法激活'); } // 检查基础配置 if (empty($service->base_url)) { $this->addError('base_url', '服务缺少基础URL配置,无法激活'); } } /** * 验证代码唯一性 * * @param string $code * @param int|null $excludeId * @return void */ protected function validateCodeUnique(string $code, ?int $excludeId = null): void { $query = ThirdPartyService::where('code', $code); if ($excludeId) { $query->where('id', '!=', $excludeId); } if ($query->exists()) { $this->addError('code', '服务代码已存在'); } } /** * 验证必填字段 * * @param array $data * @param array $required * @return void */ protected function validateRequired(array $data, array $required): void { foreach ($required as $field => $label) { if (!isset($data[$field]) || empty($data[$field])) { $this->addError($field, "{$label}不能为空"); } } } /** * 添加错误信息 * * @param string $field * @param string $message * @return void */ protected function addError(string $field, string $message): void { if (!isset($this->errors[$field])) { $this->errors[$field] = []; } $this->errors[$field][] = $message; } /** * 获取错误信息 * * @return array */ public function getErrors(): array { return $this->errors; } /** * 获取第一个错误信息 * * @return string|null */ public function getFirstError(): ?string { if (empty($this->errors)) { return null; } $firstField = array_key_first($this->errors); return $this->errors[$firstField][0] ?? null; } /** * 检查是否有错误 * * @return bool */ public function hasErrors(): bool { return !empty($this->errors); } }