您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

CurrencyService.php 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <?php
  2. namespace App\Services;
  3. use App\Contracts\CurrencyHandler;
  4. use GuzzleHttp\Client;
  5. use GuzzleHttp\Exception\GuzzleException;
  6. use Illuminate\Support\Facades\Cache;
  7. use Illuminate\Support\Facades\Log;
  8. class CurrencyService implements CurrencyHandler
  9. {
  10. public function __construct(
  11. protected ?string $apiKey,
  12. protected ?string $baseUrl,
  13. protected Client $client
  14. ) {}
  15. /**
  16. * Determine if the Currency Exchange Rate feature is enabled.
  17. */
  18. public function isEnabled(): bool
  19. {
  20. if (app()->environment('demo')) {
  21. return false;
  22. }
  23. return filled($this->apiKey) && filled($this->baseUrl);
  24. }
  25. public function getSupportedCurrencies(): ?array
  26. {
  27. if (! $this->isEnabled()) {
  28. return null;
  29. }
  30. return Cache::remember('supported_currency_codes', now()->addMonth(), function () {
  31. $response = $this->client->get("{$this->baseUrl}/{$this->apiKey}/codes");
  32. if ($response->getStatusCode() === 200) {
  33. $responseData = json_decode($response->getBody()->getContents(), true);
  34. if ($responseData['result'] === 'success' && filled($responseData['supported_codes'])) {
  35. return array_column($responseData['supported_codes'], 0);
  36. }
  37. }
  38. Log::error('Failed to retrieve supported currencies from Currency API', [
  39. 'status_code' => $response->getStatusCode(),
  40. 'response_body' => $response->getBody()->getContents(),
  41. ]);
  42. return null;
  43. });
  44. }
  45. public function getExchangeRates(string $baseCurrency, array $targetCurrencies): ?array
  46. {
  47. $cacheKey = "currency_rates_{$baseCurrency}";
  48. $cachedRates = Cache::get($cacheKey);
  49. if (Cache::missing($cachedRates)) {
  50. $cachedRates = $this->updateCurrencyRatesCache($baseCurrency);
  51. if (empty($cachedRates)) {
  52. return null;
  53. }
  54. }
  55. $filteredRates = array_intersect_key($cachedRates, array_flip($targetCurrencies));
  56. $filteredRates = array_filter($filteredRates);
  57. $filteredCurrencies = array_keys($filteredRates);
  58. $missingCurrencies = array_diff($targetCurrencies, $filteredCurrencies);
  59. if (filled($missingCurrencies)) {
  60. return null;
  61. }
  62. return $filteredRates;
  63. }
  64. public function getCachedExchangeRates(string $baseCurrency, array $targetCurrencies): ?array
  65. {
  66. if ($this->isEnabled()) {
  67. return $this->getExchangeRates($baseCurrency, $targetCurrencies);
  68. }
  69. return null;
  70. }
  71. public function getCachedExchangeRate(string $baseCurrency, string $targetCurrency): ?float
  72. {
  73. $rates = $this->getCachedExchangeRates($baseCurrency, [$targetCurrency]);
  74. if (isset($rates[$targetCurrency])) {
  75. return (float) $rates[$targetCurrency];
  76. }
  77. return null;
  78. }
  79. public function updateCurrencyRatesCache(string $baseCurrency): ?array
  80. {
  81. try {
  82. $response = $this->client->get("{$this->baseUrl}/{$this->apiKey}/latest/{$baseCurrency}");
  83. if ($response->getStatusCode() === 200) {
  84. $responseData = json_decode($response->getBody()->getContents(), true);
  85. if ($responseData['result'] === 'success' && isset($responseData['conversion_rates'])) {
  86. Cache::put("currency_rates_{$baseCurrency}", $responseData['conversion_rates'], now()->addDay());
  87. return $responseData['conversion_rates'];
  88. }
  89. $errorType = $responseData['error-type'] ?? 'unknown';
  90. Log::error('API returned error', [
  91. 'error_type' => $errorType,
  92. 'response_body' => $responseData,
  93. ]);
  94. } else {
  95. Log::error('Failed to retrieve exchange rates from Currency API', [
  96. 'status_code' => $response->getStatusCode(),
  97. 'response_body' => $response->getBody()->getContents(),
  98. ]);
  99. }
  100. } catch (GuzzleException $e) {
  101. Log::error('Failed to retrieve exchange rates from Currency API', [
  102. 'message' => $e->getMessage(),
  103. 'code' => $e->getCode(),
  104. ]);
  105. }
  106. return null;
  107. }
  108. }