sozo-design/Magento2_CurrencyConversionExtended

View on GitHub
Model/Currency/Import/FreeCurrencyConverterApi.php

Summary

Maintainability
B
4 hrs
Test Coverage
<?php
/**
 * SOZO Design Ltd
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Open Software License (OSL 3.0)
 * that is bundled with this package in the file LICENSE.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/osl-3.0.php
 *
 * @category    SOZO Design Ltd
 * @package     Sozo_CurrencyConversionExtended
 * @copyright   Copyright (c) 2019 SOZO Design Ltd (https://sozodesign.com)
 * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 */

namespace Sozo\CurrencyConversionExtended\Model\Currency\Import;

use Magento\Directory\Model\CurrencyFactory;
use Magento\Directory\Model\Currency\Import\AbstractImport;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\HTTP\ZendClientFactory;
use Magento\Store\Model\ScopeInterface;

/**
 * Currency rate import model (From https://free.currencyconverterapi.com/)
 */
class FreeCurrencyConverterApi extends AbstractImport
{
    /**
     * @var string
     */
    const CURRENCY_CONVERTER_URL = 'https://free.currconv.com/api/v7/convert?apiKey={{API_KEY}}&q={{CURRENCY_FROM}}_{{CURRENCY_TO}}&compact=ultra';

    /**
     * Http Client Factory
     *
     * @var ZendClientFactory
     */
    protected $httpClientFactory;

    /**
     * Core scope config
     *
     * @var ScopeConfigInterface
     */
    private $scopeConfig;

    /**
     * The API Key
     *
     * @var string
     */
    protected $accessKey;

    /**
     * Initialize dependencies
     *
     * @param CurrencyFactory $currencyFactory
     * @param ScopeConfigInterface $scopeConfig
     * @param ZendClientFactory $httpClientFactory
     */
    public function __construct(
        CurrencyFactory $currencyFactory,
        ScopeConfigInterface $scopeConfig,
        ZendClientFactory $httpClientFactory
    )
    {
        parent::__construct($currencyFactory);
        $this->scopeConfig = $scopeConfig;
        $this->httpClientFactory = $httpClientFactory;

        $this->accessKey = $this->scopeConfig->getValue(
            'currency/currency_converter/api_key',
            ScopeInterface::SCOPE_STORE
        );
    }

    /**
     * {@inheritdoc}
     */
    public function fetchRates()
    {
        $data = [];
        $currencies = $this->_getCurrencyCodes();
        $defaultCurrencies = $this->_getDefaultCurrencyCodes();
        foreach ($defaultCurrencies as $currencyFrom) {
            if (!isset($data[$currencyFrom])) {
                $data[$currencyFrom] = [];
            }
            $data = $this->convertBatch($data, $currencyFrom, $currencies);
            ksort($data[$currencyFrom]);
        }
        return $data;
    }

    /**
     * Return currencies convert rates in batch mode
     *
     * @param array $data
     * @param string $currencyFrom
     * @param array $currenciesTo
     * @return array
     */
    private function convertBatch($data, $currencyFrom, $currenciesTo)
    {
        if (empty($this->accessKey)) {
            $this->_messages[] = __('No API key was specified or an invalid API key was specified');
            $data[$currencyFrom] = $this->makeEmptyResponse($currenciesTo);
            return $data;
        }

        foreach ($currenciesTo as $to) {
            set_time_limit(0);
            try {
                $url = $this->prepareUrl($currencyFrom, $to);
                $response = $this->getServiceResponse($url);
                $this->processResponse($data, $currencyFrom, $to, $url, $response);
            } finally {
                ini_restore('max_execution_time');
            }
        }
        return $data;
    }

    /**
     * Prepare the URL
     *
     * @param float $currencyFrom
     * @param float $currencyTo
     * @return string $url
     */
    public function prepareUrl($currencyFrom, $currencyTo)
    {
        $url = str_replace('{{API_KEY}}', $this->accessKey, self::CURRENCY_CONVERTER_URL);
        $url = str_replace('{{CURRENCY_FROM}}', $currencyFrom, $url);
        $url = str_replace('{{CURRENCY_TO}}', $currencyTo, $url);

        return $url;
    }

    /**
     * Get CurrencyConverterApi service response
     *
     * @param string $url
     * @param int $retry
     * @return array
     */
    private function getServiceResponse($url, $retry = 0)
    {
        /** @var \Magento\Framework\HTTP\ZendClient $httpClient */
        $httpClient = $this->httpClientFactory->create();
        $response = [];
        try {
            $jsonResponse = $httpClient->setUri(
                $url
            )->setConfig(
                [
                    'timeout' => $this->scopeConfig->getValue(
                        'currency/currency_converter/timeout',
                        \Magento\Store\Model\ScopeInterface::SCOPE_STORE
                    ),
                ]
            )->request(
                'GET'
            )->getBody();
            $response = json_decode($jsonResponse, true);
        } catch (\Exception $e) {
            if ($retry == 0) {
                $response = $this->getServiceResponse($url, 1);
            }
        }
        return $response;
    }

    /**
     * Process the result
     *
     * @param array $data
     * @param string $currencyFrom
     * @param string $currencyTo
     * @param string $url
     * @param array $response
     * @return mixed
     */
    protected function processResponse(&$data, $currencyFrom, $currencyTo, $url, $response)
    {
        if ($currencyFrom == $currencyTo) {
            $data[$currencyFrom][$currencyTo] = $this->_numberFormat(1);
        } else {
            if (empty($response)) {
                $this->_messages[] = __('We can\'t retrieve a rate from %1 for %2.', $url, $currencyTo);
                $data[$currencyFrom][$currencyTo] = null;
            } elseif (isset($response['status']) && $response['status'] == 400) {
                $this->_messages[] = __($response['error']);
                $data[$currencyFrom][$currencyTo] = null;
            } else {
                $data[$currencyFrom][$currencyTo] = $this->_numberFormat(
                    (double)$response[$currencyFrom . '_' . $currencyTo]
                );
            }
        }
    }

    /**
     * {@inheritdoc}
     */
    protected function _convert($currencyFrom, $currencyTo)
    {
        return 1;
    }
}