diff --git a/src/Service/AbstractApi.php b/src/Service/AbstractApi.php index 64f715d..d0df143 100644 --- a/src/Service/AbstractApi.php +++ b/src/Service/AbstractApi.php @@ -13,9 +13,12 @@ namespace Exchanger\Service; +use Exchanger\Contract\CurrencyPair; use Exchanger\Contract\ExchangeRateQuery; use Exchanger\Contract\HistoricalExchangeRateQuery; +use Exchanger\Exception\Exception; use Exchanger\Exception\UnsupportedCurrencyPairException; +use Exchanger\ExchangeRate; use Exchanger\StringUtil; use Exchanger\Contract\ExchangeRate as ExchangeRateContract; @@ -26,9 +29,13 @@ */ final class AbstractApi extends HttpService { + use SupportsHistoricalQueries; + const API_KEY_OPTION = 'api_key'; - const LATEST_URL = 'https://currency.abstractapi.com/v1/latest?api_key=%s&base=%s'; + const LATEST_URL = 'https://exchange-rates.abstractapi.com/v1/live?api_key=%s&base=%s'; + + const HISTORICAL_URL = 'https://exchange-rates.abstractapi.com/v1/historical?api_key=%s&base=%s&date=%s'; /** * {@inheritdoc} @@ -43,9 +50,9 @@ public function processOptions(array &$options): void /** * {@inheritdoc} */ - public function getExchangeRate(ExchangeRateQuery $exchangeRateQuery): ExchangeRateContract + protected function getLatestExchangeRate(ExchangeRateQuery $exchangeQuery): ExchangeRateContract { - $currencyPair = $exchangeRateQuery->getCurrencyPair(); + $currencyPair = $exchangeQuery->getCurrencyPair(); $url = sprintf( self::LATEST_URL, @@ -53,16 +60,48 @@ public function getExchangeRate(ExchangeRateQuery $exchangeRateQuery): ExchangeR $currencyPair->getBaseCurrency() ); + return $this->doCreateRate($url, $currencyPair); + } + + /** + * {@inheritdoc} + */ + protected function getHistoricalExchangeRate(HistoricalExchangeRateQuery $exchangeQuery): ExchangeRateContract + { + $currencyPair = $exchangeQuery->getCurrencyPair(); + + $url = sprintf( + self::HISTORICAL_URL, + $this->options[self::API_KEY_OPTION], + $currencyPair->getBaseCurrency(), + $exchangeQuery->getDate()->format('Y-m-d') + ); + + return $this->doCreateRate($url, $currencyPair); + } + + /** + * Creates a rate. + * + * @param string $url + * @param CurrencyPair $currencyPair + * + * @return ExchangeRate + * + * @throws Exception + */ + private function doCreateRate($url, CurrencyPair $currencyPair): ExchangeRate + { $content = $this->request($url); + $data = StringUtil::jsonToArray($content); - if (isset($data['exchange_rate'][$currencyPair->getQuoteCurrency()])) { - $date = new \DateTime( - $data['last_updated_utc'], - new \DateTimeZone('UTC') - ); + if (isset($data['exchange_rates'][$currencyPair->getQuoteCurrency()])) { + $date = new \DateTime(); + $date->setTimestamp($data['last_updated']); + $date->setTimezone(new \DateTimeZone('UTC')); - $rate = $data['exchange_rate'][$currencyPair->getQuoteCurrency()]; + $rate = $data['exchange_rates'][$currencyPair->getQuoteCurrency()]; return $this->createRate($currencyPair, (float) $rate, $date); } @@ -75,7 +114,7 @@ public function getExchangeRate(ExchangeRateQuery $exchangeRateQuery): ExchangeR */ public function supportQuery(ExchangeRateQuery $exchangeQuery): bool { - return !$exchangeQuery instanceof HistoricalExchangeRateQuery; + return true; } /** diff --git a/tests/Fixtures/Service/AbstractApi/success.json b/tests/Fixtures/Service/AbstractApi/success.json index f7f7605..b34da6c 100644 --- a/tests/Fixtures/Service/AbstractApi/success.json +++ b/tests/Fixtures/Service/AbstractApi/success.json @@ -1,13 +1,38 @@ { "base": "USD", - "last_updated_unix": "1593614038", - "last_updated_utc": "Wed, 01 Jul 2020 14:33:58 +0000", - "exchange_rate": { - "EUR": 0.889758, - "CAD": 1.35676, - "AUD": 1.44753, - "GBP": 0.807175, - "CHF": 0.946451, - "CNY": 7.06409 + "last_updated": 1620998100, + "exchange_rates": { + "EUR": 0.824878, + "JPY": 109.28813, + "BGN": 1.613297, + "CZK": 21.027798, + "DKK": 6.13396, + "GBP": 0.71008, + "HUF": 293.260744, + "PLN": 3.729935, + "RON": 4.063268, + "SEK": 8.35313, + "CHF": 0.903407, + "ISK": 124.47414, + "NOK": 8.254887, + "HRK": 6.20226, + "RUB": 73.926916, + "TRY": 8.428112, + "AUD": 1.289615, + "BRL": 5.274437, + "CAD": 1.212571, + "CNY": 6.436031, + "HKD": 7.766312, + "IDR": 14296.749979, + "ILS": 3.279469, + "INR": 73.25497, + "KRW": 1128.491298, + "MXN": 19.816217, + "MYR": 4.125464, + "NZD": 1.383403, + "PHP": 47.733234, + "SGD": 1.333086, + "THB": 31.355275, + "ZAR": 14.082488 } } diff --git a/tests/Tests/Service/AbstractApiTest.php b/tests/Tests/Service/AbstractApiTest.php index 25394f4..c86c85e 100644 --- a/tests/Tests/Service/AbstractApiTest.php +++ b/tests/Tests/Service/AbstractApiTest.php @@ -24,12 +24,12 @@ class AbstractApiTest extends ServiceTestCase /** * @test */ - public function it_does_not_support_all_queries() + public function it_supports_all_queries() { $service = new AbstractApi($this->createMock('Http\Client\HttpClient'), null, ['api_key' => 'secret']); $this->assertTrue($service->supportQuery(new ExchangeRateQuery(CurrencyPair::createFromString('EUR/USD')))); - $this->assertFalse($service->supportQuery(new HistoricalExchangeRateQuery(CurrencyPair::createFromString('EUR/USD'), new \DateTime()))); + $this->assertTrue($service->supportQuery(new HistoricalExchangeRateQuery(CurrencyPair::createFromString('EUR/USD'), new \DateTime()))); } /** @@ -38,7 +38,7 @@ public function it_does_not_support_all_queries() public function it_throws_an_exception_when_rate_not_supported() { $this->expectException(Exception::class); - $url = 'https://currency.abstractapi.com/v1/latest?api_key=secret&base=USD'; + $url = 'https://exchange-rates.abstractapi.com/v1/live?api_key=secret&base=USD'; $content = file_get_contents(__DIR__.'/../../Fixtures/Service/AbstractApi/success.json'); $service = new AbstractApi($this->getHttpAdapterMock($url, $content), null, ['api_key' => 'secret']); @@ -51,14 +51,33 @@ public function it_throws_an_exception_when_rate_not_supported() public function it_fetches_a_rate() { $pair = CurrencyPair::createFromString('USD/GBP'); - $url = 'https://currency.abstractapi.com/v1/latest?api_key=secret&base=USD'; + $url = 'https://exchange-rates.abstractapi.com/v1/live?api_key=secret&base=USD'; $content = file_get_contents(__DIR__.'/../../Fixtures/Service/AbstractApi/success.json'); $service = new AbstractApi($this->getHttpAdapterMock($url, $content), null, ['api_key' => 'secret']); $rate = $service->getExchangeRate(new ExchangeRateQuery($pair)); - $this->assertSame(0.807175, $rate->getValue()); - $this->assertEquals('2020-07-01', $rate->getDate()->format('Y-m-d')); + $this->assertSame(0.71008, $rate->getValue()); + $this->assertEquals('2021-05-14', $rate->getDate()->format('Y-m-d')); + $this->assertEquals('abstract_api', $rate->getProviderName()); + $this->assertSame($pair, $rate->getCurrencyPair()); + } + + /** + * @test + */ + public function it_fetches_a_historical_rate() + { + $pair = CurrencyPair::createFromString('USD/GBP'); + $url = 'https://exchange-rates.abstractapi.com/v1/historical?api_key=secret&base=USD&date=2000-01-03'; + $content = file_get_contents(__DIR__.'/../../Fixtures/Service/AbstractApi/success.json'); + $date = new \DateTime('2000-01-03'); + + $service = new AbstractApi($this->getHttpAdapterMock($url, $content), null, ['api_key' => 'secret']); + $rate = $service->getExchangeRate(new HistoricalExchangeRateQuery($pair, $date)); + + $this->assertSame(0.71008, $rate->getValue()); + $this->assertEquals('2021-05-14', $rate->getDate()->format('Y-m-d')); $this->assertEquals('abstract_api', $rate->getProviderName()); $this->assertSame($pair, $rate->getCurrencyPair()); }