YahooProvider   A
last analyzed

Complexity

Total Complexity 18

Size/Duplication

Total Lines 181
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 18
dl 0
loc 181
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A date() 0 5 1
C latest() 0 50 9
A historical() 0 7 1
A targetsToString() 0 8 2
A __construct() 0 3 1
A query() 0 20 4
1
<?php
2
3
namespace Ultraleet\CurrencyRates\Providers;
4
5
use Ultraleet\CurrencyRates\AbstractProvider;
6
use Ultraleet\CurrencyRates\Result;
7
use Ultraleet\CurrencyRates\Exceptions\ConnectionException;
8
use Ultraleet\CurrencyRates\Exceptions\ResponseException;
9
use GuzzleHttp\Client as GuzzleClient;
10
use DateTime;
11
use InvalidArgumentException;
12
use GuzzleHttp\Exception\TransferException;
13
14
class YahooProvider extends AbstractProvider
15
{
16
    protected $guzzle;
17
    protected $url = 'http://query.yahooapis.com/v1/public/yql';
18
    protected $urlParams = [
19
        'env' => 'store://datatables.org/alltableswithkeys',
20
        'format' => 'json',
21
    ];
22
23
    /**
24
     * @var array List of supported currencies.
25
     */
26
    protected $currencies = [
27
        'KRW', 'XAG', 'VND', 'BOB', 'MOP', 'BDT', 'MDL', 'VEF', 'GEL', 'ISK',
28
        'BYR', 'THB', 'MXV', 'TND', 'JMD', 'DKK', 'SRD', 'BWP', 'NOK', 'MUR',
29
        'AZN', 'INR', 'MGA', 'CAD', 'XAF', 'LBP', 'XDR', 'IDR', 'IEP', 'AUD',
30
        'MMK', 'LYD', 'ZAR', 'IQD', 'XPF', 'TJS', 'CUP', 'UGX', 'NGN', 'PGK',
31
        'TOP', 'TMT', 'KES', 'CRC', 'MZN', 'BYN', 'SYP', 'ANG', 'ZMW', 'BRL',
32
        'BSD', 'NIO', 'GNF', 'BMD', 'SLL', 'MKD', 'BIF', 'LAK', 'BHD', 'SHP',
33
        'BGN', 'SGD', 'CNY', 'EUR', 'TTD', 'SCR', 'BBD', 'SBD', 'MAD', 'GTQ',
34
        'MWK', 'PKR', 'ITL', 'PEN', 'AED', 'LVL', 'XPD', 'UAH', 'FRF', 'LRD',
35
        'LSL', 'SEK', 'RON', 'XOF', 'COP', 'CDF', 'USD', 'TZS', 'GHS', 'NPR',
36
        'ZWL', 'SOS', 'DZD', 'FKP', 'LKR', 'JPY', 'CHF', 'KYD', 'CLP', 'IRR',
37
        'AFN', 'DJF', 'SVC', 'PLN', 'PYG', 'ERN', 'ETB', 'ILS', 'TWD', 'KPW',
38
        'SIT', 'GIP', 'BND', 'HNL', 'CZK', 'HUF', 'BZD', 'DEM', 'JOD', 'RWF',
39
        'LTL', 'RUB', 'RSD', 'WST', 'XPT', 'NAD', 'PAB', 'DOP', 'ALL', 'HTG',
40
        'AMD', 'KMF', 'MRO', 'HRK', 'HTG', 'KHR', 'PHP', 'CYP', 'KWD', 'XCD',
41
        'XCP', 'CNH', 'SDG', 'CLF', 'KZT', 'TRY', 'FJD', 'NZD', 'BAM', 'BTN',
42
        'STD', 'VUV', 'MVR', 'AOA', 'EGP', 'QAR', 'OMR', 'CVE', 'KGS', 'MXN',
43
        'MYR', 'GYD', 'SZL', 'YER', 'SAR', 'UYU', 'GBP', 'UZS', 'GMD', 'AWG',
44
        'MNT', 'XAU', 'HKD', 'ARS', 'HUX', 'FKP', 'CHF', 'GEL', 'MOP', 'SIT',
45
        'KMF', 'ZWL', 'BAM', 'AOA', 'CNY', 'TTD', 'BRX', 'ECS'
46
    ];
47
48
49
    /**
50
     * Class constructor.
51
     *
52
     * @param \GuzzleHttp\Client $guzzle
53
     * @return void
54
     */
55
    public function __construct(GuzzleClient $guzzle)
56
    {
57
        $this->guzzle = $guzzle;
58
    }
59
60
    /**
61
     * Get latest currency exchange rates.
62
     *
63
     * @param  string  $base
64
     * @param  array   $targets
65
     * @return \Ultraleet\CurrencyRates\Contracts\Result
66
     */
67
    public function latest($base = 'EUR', $targets = [])
68
    {
69
        // Query all supported targets in case none were specified
70
        if (empty($targets)) {
71
            $targets = $this->currencies;
72
73
            // unset base currency
74
            if ($key = array_search($base, $targets)) {
75
                unset($targets[$key]);
76
            }
77
        }
78
79
        // Build query
80
        $targets = $this->targetsToString($targets, $base);
81
        $yql = sprintf('select * from yahoo.finance.xchange where pair in (%s)', $targets);
82
83
        // Query API
84
        $response = $this->query($yql);
85
86
        // Parse response
87
        if (isset($response['rate']) && is_array($response['rate'])) {
88
            $rates = [];
89
            $date = 0;
90
            if (isset($response['rate']['Rate'])) {
91
                // Wrap single result in an array
92
                $response['rate'] = [$response['rate']];
93
            }
94
            foreach ($response['rate'] as $result) {
95
                // No result, skip
96
                if ('N/A' == $result['Rate']) {
97
                    continue;
98
                }
99
100
                // Save the latest timestamp
101
                if ($date < $ts = strtotime($result['Date'] . ' ' . $result['Time'])) {
102
                    $date = $ts;
103
                }
104
105
                // Save rate
106
                $currency = substr($result['Name'], strpos($result['Name'], '/') + 1);
107
                $rates[$currency] = $result['Rate'];
108
            }
109
110
            return new Result(
111
                $base,
112
                new DateTime('@' . $date),
113
                $rates
114
            );
115
        } else {
116
            throw new ResponseException('Invalid results.');
117
        }
118
    }
119
120
    /**
121
     * Overriden method - historical rates are unsupported by Yahoo Finance API
122
     *
123
     * @param mixed $date Can be a string, a DateTime object, or null to unset.
124
     * @return self
125
     */
126
    public function date($date = null)
127
    {
128
        trigger_error('Yahoo Finance API does not provide historical rates', E_USER_WARNING);
129
130
        return $this;
131
    }
132
133
    /**
134
     * Unsupported by Yahoo Finance API.
135
     *
136
     * @param  \DateTime $date
137
     * @param  string    $base
138
     * @param  array     $targets
139
     * @return \Ultraleet\CurrencyRates\Contracts\Result
140
     */
141
    public function historical($date, $base = 'EUR', $targets = [])
142
    {
143
        // Yahoo Finance API no longer provides historical rates...
144
        // Let's just trigger a warning and return latest rates instead.
145
        $this->date($date);
146
147
        return $this->latest($base, $targets);
148
    }
149
150
    /**
151
     * Perform the API query and return results as an array.
152
     *
153
     * @param  string $yql YQL query to send.
154
     * @return array
155
     */
156
    protected function query($yql)
157
    {
158
        $params = $this->urlParams;
159
        $params['q'] = $yql;
160
        $url = $this->url . '?' . http_build_query($params);
161
162
        // query the API
163
        try {
164
            $response = $this->guzzle->request('GET', $url);
165
        } catch (TransferException $e) {
166
            throw new ConnectionException($e->getMessage());
167
        }
168
169
        // process response
170
        $response = json_decode($response->getBody(), true);
171
172
        if (isset($response['query']) && isset($response['query']['results'])) {
173
            return $response['query']['results'];
174
        } else {
175
            throw new ResponseException('Response body is malformed.');
176
        }
177
    }
178
179
    /**
180
     * Convert targets array to string for using in the YQL query.
181
     *
182
     * @param  array  $targets
183
     * @param  string $prefix  Prefix to add to each currency (e.g. base currency)
184
     * @param  string $suffix  Suffix to add to each currency
185
     * @return string
186
     */
187
    protected static function targetsToString($targets, $prefix = '', $suffix = '')
188
    {
189
        $array = [];
190
        foreach ($targets as $currency) {
191
            $array[] = '"' . $prefix . $currency . $suffix . '"';
192
        }
193
194
        return implode(', ', $array);
195
    }
196
}
197