AgentDomainService.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. <?php
  2. namespace App\Services\Agent;
  3. use App\Models\Agent\Agent;
  4. use App\Models\Agent\AgentDomain;
  5. use Illuminate\Support\Facades\DB;
  6. class AgentDomainService
  7. {
  8. public function save(Agent $agent, array $domains): array
  9. {
  10. return DB::transaction(function () use ($agent, $domains) {
  11. foreach (['pc', 'h5'] as $type) {
  12. if (!array_key_exists($type, $domains)) {
  13. continue;
  14. }
  15. $url = $this->normalize((string) $domains[$type]);
  16. if ($url === '') {
  17. AgentDomain::query()->where('agent_id', $agent->id)->where('type', $type)->delete();
  18. continue;
  19. }
  20. $host = $this->host($url);
  21. $owner = AgentDomain::query()->where('host', $host)->lockForUpdate()->first();
  22. if ($owner && (int) $owner->agent_id !== (int) $agent->id) {
  23. throw new \RuntimeException('该域名已绑定其他代理');
  24. }
  25. AgentDomain::query()->updateOrCreate(
  26. ['agent_id' => $agent->id, 'type' => $type],
  27. ['domain' => $url, 'host' => $host, 'status' => 1]
  28. );
  29. }
  30. return $this->format($agent->fresh());
  31. });
  32. }
  33. public function format(Agent $agent): array
  34. {
  35. $domains = $agent->domains()->where('status', 1)->pluck('domain', 'type');
  36. $pc = (string) ($domains['pc'] ?? '');
  37. $h5 = (string) ($domains['h5'] ?? '');
  38. return [
  39. 'pc_domain' => $pc,
  40. 'h5_domain' => $h5,
  41. 'pc_register_url' => $pc === '' ? '' : $this->registerUrl($pc, (string) config('agent.pc_register_path'), $agent->invitation_code),
  42. 'h5_register_url' => $h5 === '' ? '' : $this->registerUrl($h5, (string) config('agent.h5_register_path'), $agent->invitation_code),
  43. ];
  44. }
  45. public function resolve(?string $invitationCode, ?string $domain): ?Agent
  46. {
  47. if ($invitationCode) {
  48. return Agent::query()->where('invitation_code', strtoupper(trim($invitationCode)))
  49. ->where('status', Agent::STATUS_ENABLED)->first();
  50. }
  51. $normalized = $domain ? $this->normalize($domain) : '';
  52. if ($normalized === '') {
  53. return null;
  54. }
  55. $domainRow = AgentDomain::query()->where('host', $this->host($normalized))->where('status', 1)->first();
  56. return $domainRow ? Agent::query()->whereKey($domainRow->agent_id)->where('status', Agent::STATUS_ENABLED)->first() : null;
  57. }
  58. private function normalize(string $value): string
  59. {
  60. $value = trim($value);
  61. if ($value === '') {
  62. return '';
  63. }
  64. $candidate = preg_match('#^https?://#i', $value) ? $value : 'https://' . $value;
  65. $scheme = strtolower((string) parse_url($candidate, PHP_URL_SCHEME));
  66. $host = strtolower((string) parse_url($candidate, PHP_URL_HOST));
  67. $port = parse_url($candidate, PHP_URL_PORT);
  68. if (!in_array($scheme, ['http', 'https'], true) || $host === '') {
  69. throw new \InvalidArgumentException('域名格式错误');
  70. }
  71. return $scheme . '://' . $host . ($port ? ':' . $port : '');
  72. }
  73. private function registerUrl(string $domain, string $path, string $code): string
  74. {
  75. $separator = str_contains($path, '?') ? '&' : '?';
  76. return rtrim($domain, '/') . '/' . ltrim($path, '/') . $separator . 'agent_code=' . urlencode($code);
  77. }
  78. private function host(string $url): string
  79. {
  80. return strtolower((string) parse_url($url, PHP_URL_HOST));
  81. }
  82. }