orkhanahmadov/currencylayer

View on GitHub
src/CurrencylayerClient.php

Summary

Maintainability
A
2 hrs
Test Coverage
<?php

namespace Orkhanahmadov\Currencylayer;

use GuzzleHttp\Client as Guzzle;
use Orkhanahmadov\Currencylayer\Data\Change;
use Orkhanahmadov\Currencylayer\Data\Conversion;
use Orkhanahmadov\Currencylayer\Data\Quotes;
use Orkhanahmadov\Currencylayer\Data\Timeframe;

class CurrencylayerClient implements Client
{
    /**
     * @var Guzzle
     */
    private $client;
    /**
     * @var string
     */
    private $accessKey;
    /**
     * @var string
     */
    private $source = 'USD';
    /**
     * @var string
     */
    private $currencies;
    /**
     * @var \DateTimeInterface|null
     */
    private $date = null;

    /**
     * CurrencylayerClient constructor.
     *
     * @param string $accessKey
     * @param bool   $useHttps
     */
    public function __construct(string $accessKey, bool $useHttps = false)
    {
        $this->client = new Guzzle([
            'base_uri' => $useHttps ? 'https://apilayer.net/api/' : 'http://apilayer.net/api/',
        ]);

        $this->accessKey = $accessKey;
    }

    /**
     * @param string $source
     *
     * @return $this
     */
    public function source(string $source): Client
    {
        $this->source = $source;

        return $this;
    }

    /**
     * @param array<string>|string $currency
     *
     * @return $this
     */
    public function currency($currency): Client
    {
        if (is_array($currency)) {
            $this->currencies = implode(',', $currency);
        } else {
            $this->currencies = implode(',', func_get_args());
        }

        return $this;
    }

    /**
     * @param \DateTimeInterface|string $date
     *
     * @throws \Exception
     *
     * @return $this
     */
    public function date($date): Client
    {
        $this->date = $date instanceof \DateTimeInterface ?
            $date :
            new \DateTimeImmutable($date);

        return $this;
    }

    /**
     * @throws \Exception
     *
     * @return Quotes
     */
    public function quotes(): Quotes
    {
        $query = [
            'currencies' => $this->currencies,
            'source'     => $this->source,
        ];

        if ($this->date) {
            $query['date'] = $this->date->format('Y-m-d');

            return new Quotes($this->request('historical', $query));
        }

        return new Quotes($this->request('live', $query));
    }

    /**
     * @param int|float $amount
     *
     * @throws \Exception
     *
     * @return Conversion
     */
    public function convert($amount): Conversion
    {
        if (!$this->source || !$this->currencies) {
            throw new \InvalidArgumentException('Conversion "from" and "to" currencies were not set.');
        }

        $query = [
            'from'   => $this->source,
            'to'     => $this->currencies,
            'amount' => $amount,
        ];

        if ($this->date) {
            $query['date'] = $this->date->format('Y-m-d');
        }

        return new Conversion($this->request('convert', $query));
    }

    /**
     * @param \DateTimeInterface|string $startDate
     * @param \DateTimeInterface|string $endDate
     *
     * @throws \Exception
     *
     * @return Timeframe
     */
    public function timeframe($startDate, $endDate): Timeframe
    {
        $data = $this->request('timeframe', [
            'source'     => $this->source,
            'currencies' => $this->currencies,
            'start_date' => $startDate instanceof \DateTimeInterface ?
                $startDate->format('Y-m-d') :
                $startDate,
            'end_date'   => $endDate instanceof \DateTimeInterface ?
                $endDate->format('Y-m-d') :
                $endDate,
        ]);

        return new Timeframe($data);
    }

    /**
     * @param \DateTimeInterface|string $startDate
     * @param \DateTimeInterface|string $endDate
     *
     * @throws \Exception
     *
     * @return Change
     */
    public function change($startDate, $endDate): Change
    {
        $data = $this->request('change', [
            'source'     => $this->source,
            'currencies' => $this->currencies,
            'start_date' => $startDate instanceof \DateTimeInterface ?
                $startDate->format('Y-m-d') :
                $startDate,
            'end_date'   => $endDate instanceof \DateTimeInterface ?
                $endDate->format('Y-m-d') :
                $endDate,
        ]);

        return new Change($data);
    }

    /**
     * @return array
     */
    public function list(): array
    {
        $data = $this->request('list', []);

        return $data['currencies'];
    }

    /**
     * @param string $endpoint
     * @param array  $query
     *
     * @return array
     */
    private function request(string $endpoint, array $query): array
    {
        $response = $this->client->get($endpoint, [
            'query' => array_merge($query, ['access_key' => $this->accessKey]),
        ]);

        $data = \GuzzleHttp\json_decode($response->getBody()->getContents(), true);

        if (!$data['success']) {
            throw new \InvalidArgumentException($data['error']['info']);
        }

        return $data;
    }
}