CurrencyLayerProvider::getExchangeRate()   B
last analyzed

Complexity

Conditions 7
Paths 20

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 34
rs 8.4426
c 0
b 0
f 0
cc 7
nc 20
nop 3
1
<?php
2
3
namespace BenTools\Currency\Provider;
4
5
use BenTools\Currency\Model\CurrencyInterface;
6
use BenTools\Currency\Model\ExchangeRateFactoryInterface;
7
use BenTools\Currency\Model\ExchangeRateInterface;
8
use BenTools\Currency\Model\ExchangeRateNotFoundException;
9
use BenTools\Currency\Model\NativeExchangeRateFactory;
10
use DateTime;
11
use DateTimeImmutable;
12
use DateTimeInterface;
13
use DateTimeZone;
14
use Http\Client\HttpClient;
15
use Http\Discovery\HttpClientDiscovery;
16
use Http\Discovery\MessageFactoryDiscovery;
17
use Http\Message\RequestFactory;
18
use Psr\SimpleCache\CacheInterface;
19
20
final class CurrencyLayerProvider implements ExchangeRateProviderInterface
21
{
22
    /**
23
     * @var string
24
     */
25
    private $accessKey;
26
27
    /**
28
     * @var HttpClient|null
29
     */
30
    private $client;
31
32
    /**
33
     * @var RequestFactory|null
34
     */
35
    private $requestFactory;
36
37
    /**
38
     * @var ExchangeRateFactoryInterface|null
39
     */
40
    private $exchangeRateFactory;
41
42
    /**
43
     * OpenExchangeRatesProvider constructor.
44
     * @param string                            $accessKey
45
     * @param HttpClient|null                   $client
46
     * @param RequestFactory|null               $requestFactory
47
     * @param ExchangeRateFactoryInterface|null $exchangeRateFactory
48
     * @throws \Http\Discovery\Exception\NotFoundException
49
     */
50
    public function __construct(
51
        string $accessKey,
52
        HttpClient $client = null,
53
        RequestFactory $requestFactory = null,
54
        ExchangeRateFactoryInterface $exchangeRateFactory = null
55
    ) {
56
        $this->accessKey = $accessKey;
57
        $this->client = $client ?? HttpClientDiscovery::find();
58
        $this->requestFactory = $requestFactory ?? MessageFactoryDiscovery::find();
59
        $this->exchangeRateFactory = $exchangeRateFactory ?? new NativeExchangeRateFactory();
60
    }
61
62
    /**
63
     * @inheritDoc
64
     */
65
    public function getExchangeRate(CurrencyInterface $sourceCurrency, CurrencyInterface $targetCurrency, DateTimeInterface $date = null): ExchangeRateInterface
66
    {
67
        if (null === $date) {
68
            $date = new DateTimeImmutable('now', new DateTimeZone('GMT'));
69
        }
70
71
        if ($date instanceof DateTime) {
72
            $date = DateTimeImmutable::createFromMutable($date)->setTimezone(new DateTimeZone('GMT'));
73
        }
74
75
        if (!in_array('USD', [$sourceCurrency->getCode(), $targetCurrency->getCode()])) {
76
            throw new ExchangeRateNotFoundException($sourceCurrency, $targetCurrency, "CurrencyLayer Free plan only provide USD-based currency conversions.");
77
        }
78
79
        // Same currencies
80
        if ($sourceCurrency->getCode() === $targetCurrency->getCode()) {
81
            return $this->exchangeRateFactory->create($sourceCurrency, $targetCurrency, 1);
82
        }
83
84
        // Invert currencies
85
        if ('USD' === $targetCurrency->getCode()) { // CurrencyLayer free plan only provide USD -> *
86
            $revertExchangeRate = $this->getExchangeRate($targetCurrency, $sourceCurrency, $date);
87
            return $this->exchangeRateFactory->create($sourceCurrency, $targetCurrency, 1 / $revertExchangeRate->getRatio());
88
        }
89
90
        $url = sprintf('http://apilayer.net/api/historical?access_key=%s&date=%s', $this->accessKey, $date->format('Y-m-d'));
91
        $response = $this->client->sendRequest($this->requestFactory->createRequest('GET', $url));
92
        $json = json_decode((string) $response->getBody(), true);
93
        if (isset($json['quotes'][$sourceCurrency->getCode() . $targetCurrency->getCode()])) {
94
            return $this->exchangeRateFactory->create($sourceCurrency, $targetCurrency, $json['quotes'][$sourceCurrency->getCode() . $targetCurrency->getCode()]);
95
        }
96
97
        throw new ExchangeRateNotFoundException($sourceCurrency, $targetCurrency);
98
    }
99
}
100