Skip to content

Commit 46ca80a

Browse files
authored
Merge pull request florianv#146 from piotrantosik/ft/fixer-api-layer
Add Fixer ApiLayer
2 parents b1a149a + adfb277 commit 46ca80a

File tree

6 files changed

+228
-0
lines changed

6 files changed

+228
-0
lines changed

doc/readme.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,9 +414,11 @@ use Exchanger\Service\Cryptonator;
414414
use Exchanger\Service\CoinLayer;
415415
use Exchanger\Service\XchangeApi;
416416
use Exchanger\Service\AbstractApi;
417+
use Exchanger\Service\FixerApiLayer;
417418

418419
$service = new Chain([
419420
new Fixer($client, null, ['access_key' => 'YOUR_KEY']),
421+
new FixerApiLayer($client, null, ['api_key' => 'YOUR_KEY']),
420422
new CurrencyLayer($client, null, ['access_key' => 'access_key', 'enterprise' => false]),
421423
new ExchangeRatesApi($client, null, ['access_key' => 'access_key', 'enterprise' => false]),
422424
new AbstractApi($client, null, ['api_key' => 'api_key']),

src/Service/FixerApiLayer.php

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Exchanger\Service;
6+
7+
use Exchanger\Contract\CurrencyPair;
8+
use Exchanger\Contract\ExchangeRate;
9+
use Exchanger\Contract\ExchangeRateQuery;
10+
use Exchanger\Contract\HistoricalExchangeRateQuery;
11+
use Exchanger\Exception\UnsupportedCurrencyPairException;
12+
use Exchanger\StringUtil;
13+
use Exchanger\Exception\Exception;
14+
15+
final class FixerApiLayer extends HttpService
16+
{
17+
use SupportsHistoricalQueries;
18+
19+
private const API_KEY_OPTION = 'api_key';
20+
21+
private const LATEST_URL = 'https://api.apilayer.com/fixer/latest?base=%s';
22+
23+
private const HISTORICAL_URL = 'https://api.apilayer.com/fixer/%s?base=%s';
24+
25+
/**
26+
* {@inheritdoc}
27+
*/
28+
public function processOptions(array &$options): void
29+
{
30+
if (!isset($options[self::API_KEY_OPTION])) {
31+
throw new \InvalidArgumentException('The "api_key" option must be provided to use fixer.io');
32+
}
33+
}
34+
35+
/**
36+
* {@inheritdoc}
37+
*/
38+
protected function getLatestExchangeRate(ExchangeRateQuery $exchangeQuery): ExchangeRate
39+
{
40+
$currencyPair = $exchangeQuery->getCurrencyPair();
41+
42+
$url = \sprintf(
43+
self::LATEST_URL,
44+
$currencyPair->getBaseCurrency()
45+
);
46+
47+
return $this->doCreateRate($url, $currencyPair);
48+
}
49+
50+
/**
51+
* {@inheritdoc}
52+
*/
53+
protected function getHistoricalExchangeRate(HistoricalExchangeRateQuery $exchangeQuery): ExchangeRate
54+
{
55+
$currencyPair = $exchangeQuery->getCurrencyPair();
56+
57+
$url = \sprintf(
58+
self::HISTORICAL_URL,
59+
$exchangeQuery->getDate()->format('Y-m-d'),
60+
$currencyPair->getBaseCurrency()
61+
);
62+
63+
return $this->doCreateRate($url, $currencyPair);
64+
}
65+
66+
/**
67+
* {@inheritdoc}
68+
*/
69+
public function supportQuery(ExchangeRateQuery $exchangeQuery): bool
70+
{
71+
return true;
72+
}
73+
74+
/**
75+
* Creates a rate.
76+
*
77+
* @param string $url
78+
* @param CurrencyPair $currencyPair
79+
*
80+
* @return ExchangeRate
81+
*
82+
* @throws Exception
83+
*/
84+
private function doCreateRate(string $url, CurrencyPair $currencyPair): ExchangeRate
85+
{
86+
$content = $this->request($url, [
87+
'apikey' => $this->options[self::API_KEY_OPTION]
88+
]);
89+
$data = StringUtil::jsonToArray($content);
90+
91+
if (isset($data['error'])) {
92+
throw new Exception($this->getErrorMessage($data['error']['code']));
93+
}
94+
95+
if (isset($data['rates'][$currencyPair->getQuoteCurrency()])) {
96+
$date = new \DateTime($data['date']);
97+
$rate = $data['rates'][$currencyPair->getQuoteCurrency()];
98+
99+
return $this->createRate($currencyPair, (float) $rate, $date);
100+
}
101+
102+
throw new UnsupportedCurrencyPairException($currencyPair, $this);
103+
}
104+
105+
/**
106+
* Gets the error message corresponding to the error code.
107+
*
108+
* @param int $code The error code
109+
*
110+
* @return string
111+
*/
112+
private function getErrorMessage(int $code): string
113+
{
114+
$errors = [
115+
404 => 'The requested resource does not exist.',
116+
101 => 'No API Key was specified or an invalid API Key was specified.',
117+
103 => 'The requested API endpoint does not exist.',
118+
104 => 'The maximum allowed API amount of monthly API requests has been reached.',
119+
105 => 'The current subscription plan does not support this API endpoint.',
120+
106 => 'The current request did not return any results.',
121+
102 => 'The account this API request is coming from is inactive.',
122+
201 => 'An invalid base currency has been entered.',
123+
202 => 'One or more invalid symbols have been specified.',
124+
301 => 'No date has been specified.',
125+
302 => 'An invalid date has been specified.',
126+
403 => 'No or an invalid amount has been specified.',
127+
501 => 'No or an invalid timeframe has been specified.',
128+
502 => 'No or an invalid "start_date" has been specified.',
129+
503 => 'No or an invalid "end_date" has been specified.',
130+
504 => 'An invalid timeframe has been specified.',
131+
505 => 'The specified timeframe is too long, exceeding 365 days.',
132+
];
133+
134+
return $errors[$code] ?? '';
135+
}
136+
137+
/**
138+
* {@inheritdoc}
139+
*/
140+
public function getName(): string
141+
{
142+
return 'fixer_apilayer';
143+
}
144+
}

src/Service/Registry.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public static function getServices(): array
3636
'european_central_bank' => EuropeanCentralBank::class,
3737
'exchange_rates_api' => ExchangeRatesApi::class,
3838
'fixer' => Fixer::class,
39+
'fixer_apilayer' => FixerApiLayer::class,
3940
'forge' => Forge::class,
4041
'national_bank_of_romania' => NationalBankOfRomania::class,
4142
'open_exchange_rates' => OpenExchangeRates::class,
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"success": false,
3+
"error": {
4+
"code": 105,
5+
"type": "base_currency_access_restricted"
6+
}
7+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"success": true,
3+
"timestamp": 1653484743,
4+
"base": "USD",
5+
"date": "2000-01-03",
6+
"rates": {
7+
"AUD": 1.5209,
8+
"CAD": 1.4447,
9+
"CHF": 1.59,
10+
"CYP": 0.57156,
11+
"CZK": 35.741,
12+
"DKK": 7.374,
13+
"EEK": 15.507,
14+
"GBP": 0.61903,
15+
"HKD": 7.7923,
16+
"HUF": 252.26,
17+
"ISK": 72.379,
18+
"JPY": 101.83,
19+
"KRW": 1129.9,
20+
"LTL": 4.0093,
21+
"LVL": 0.58632,
22+
"MTL": 0.4114,
23+
"NOK": 7.9901,
24+
"NZD": 1.9159,
25+
"PLN": 4.1462,
26+
"ROL": 18110.0,
27+
"SEK": 8.4757,
28+
"SGD": 1.6619,
29+
"SIT": 197.12,
30+
"SKK": 41.94,
31+
"TRL": 541260.0,
32+
"ZAR": 6.146,
33+
"EUR": 0.99108
34+
}
35+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"success": true,
3+
"timestamp": 1653484743,
4+
"base": "EUR",
5+
"date": "2016-08-26",
6+
"rates": {
7+
"AUD": 1.4771,
8+
"BGN": 1.9558,
9+
"BRL": 3.6441,
10+
"CAD": 1.4546,
11+
"CHF": 1.0933,
12+
"CNY": 7.5318,
13+
"CZK": 27.024,
14+
"DKK": 7.4462,
15+
"GBP": 0.8545,
16+
"HKD": 8.7555,
17+
"HRK": 7.4893,
18+
"HUF": 308.5,
19+
"IDR": 14906.0,
20+
"ILS": 4.2444,
21+
"INR": 75.647,
22+
"JPY": 113.33,
23+
"KRW": 1258.02,
24+
"MXN": 20.7197,
25+
"MYR": 4.5349,
26+
"NOK": 9.2501,
27+
"NZD": 1.5418,
28+
"PHP": 52.29,
29+
"PLN": 4.3244,
30+
"RON": 4.4578,
31+
"RUB": 73.1392,
32+
"SEK": 9.4903,
33+
"SGD": 1.5269,
34+
"THB": 39.004,
35+
"TRY": 3.316,
36+
"USD": 1.129,
37+
"ZAR": 15.8622
38+
}
39+
}

0 commit comments

Comments
 (0)