diff --git a/README.md b/README.md index 03d6e89..5e42775 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,31 @@ catch (ResponseException $e) { } ``` +## Convert Endpoint +Accessing the currency conversion endpoint may be done like so: + +```php +use Fadion\Fixerio\Currency; //optional if you want to use currency constants +use Fadion\Fixerio\Convert; + +$converter = new Convert(); +$converter->key('YOUR_ACCESS_KEY'); +$converter->from('USD'); +$converter->to('CAD'); +$converter->amount('22.50'); +$converter = new Convert('USD', 'CAD', '22.50'); +$result = $converter->get(); +print $result; + +``` + +You may also use currency constants + +```php +$converter->from(Currency::USD); +``` + + ## Laravel Usage Nothing changes for Laravel apart from the Facade. It's just a convenience for a tad shorter way of using the package: diff --git a/src/Convert.php b/src/Convert.php new file mode 100644 index 0000000..af2d60b --- /dev/null +++ b/src/Convert.php @@ -0,0 +1,302 @@ +guzzle = $guzzle; + } else { + $this->guzzle = new GuzzleClient(); + } + } + + /** + * Sets the from currency + * + * @param string $to + * @return Exchange + */ + public function from($from) + { + $this->from = $from; + + return $this; + } + + + /** + * Sets the to currency + * + * @param string $to + * @return Exchange + */ + public function to($to) + { + $this->to = $to; + + return $this; + } + + + /** + * Sets the amount + * + * @param string $to + * @return Exchange + */ + public function amount($amount) + { + $this->amount = $amount; + + return $this; + } + + /** + * Sets the protocol to https + * + * @return Exchange + */ + public function secure() + { + $this->protocol = 'https'; + + return $this; + } + + /** + * Sets the API key + * + * @param string $key + * @return Exchange + */ + public function key($key) + { + $this->key = $key; + + return $this; + } + + /** + * Returns the correctly formatted url + * + * @return string + */ + public function getUrl() + { + return $this->buildUrl($this->url); + } + + /** + * Makes the request and returns the response + * with the rates. + * + * @throws ConnectionException if the request is incorrect or times out + * @throws ResponseException if the response is malformed + * @return array + */ + public function get() + { + $url = $this->buildUrl($this->url); + + try { + $response = $this->makeRequest($url); + + return $this->prepareResponse($response); + } + // The client needs to know only one exception, no + // matter what exception is thrown by Guzzle + catch (TransferException $e) { + throw new ConnectionException($e->getMessage()); + } + } + + /** + * Makes the request and returns the response + * with the rates, as a Result object + * + * @throws ConnectionException if the request is incorrect or times out + * @throws ResponseException if the response is malformed + * @return Result + */ + public function getResult() + { + $url = $this->buildUrl($this->url); + + try { + $response = $this->makeRequest($url); + + return $this->prepareResponseResult($response); + } + // The client needs to know only one exception, no + // matter what exception is thrown by Guzzle + catch (TransferException $e) { + throw new ConnectionException($e->getMessage()); + } + } + + /** + * Alias of get() but returns an object + * response. + * + * @throws ConnectionException if the request is incorrect or times out + * @throws ResponseException if the response is malformed + * @return object + */ + public function getAsObject() + { + $this->asObject = true; + + return $this->get(); + } + + /** + * Forms the correct url from the different parts + * + * @param string $url + * @return string + */ + private function buildUrl($url) + { + $url = $this->protocol . '://' . $url . '/convert'; + + if ($this->key) { + $url .= '?access_key=' . $this->key; + } + + if ($this->from) { + $url .= '&from=' . $this->from; + } + + if ($this->to) { + $url .= '&to=' . $this->to; + } + + if ($this->amount) { + $url .= '&amount=' . $this->amount; + } + + return $url; + } + + /** + * Makes the http request + * + * @param string $url + * @return string + */ + private function makeRequest($url) + { + $response = $this->guzzle->request('GET', $url); + + return $response->getBody(); + } + + /** + * @param string $body + * @throws ResponseException if the response is malformed + * @return array + */ + private function prepareResponse($body) + { + $response = json_decode($body, true); + + if (isset($response['result'])) { + return ($this->asObject) ? (object) $response['result'] : $response['result']; + } else if (isset($response['error'])) { + throw new ResponseException($response['error']); + // var_dump($response); + // throw new ResponseException("{$response['error']['type']} {$response['error']['info']}"); + } else { + throw new ResponseException('Response body is malformed.'); + } + } + + /** + * @param string $body + * @throws ResponseException if the response is malformed + * @return Result + */ + private function prepareResponseResult($body) + { + $response = json_decode($body, true); + + if (isset($response['query']) and isset($response['result'])) { + return new Result( + $response['base'], + new DateTime($response['date']), + $response['rates'] + ); + } else if (isset($response['error'])) { + throw new ResponseException($response['error']); + } else { + throw new ResponseException('Response body is malformed.'); + } + } +} diff --git a/tests/ConvertTest.php b/tests/ConvertTest.php new file mode 100644 index 0000000..e19e9a2 --- /dev/null +++ b/tests/ConvertTest.php @@ -0,0 +1,109 @@ +from('USD'); + $converter->to('CAD'); + $converter->amount('22.50'); + $url = $converter->getUrl(); + $expected = $this->url . '/convert&from=USD&to=CAD&amount=22.50'; + + $this->assertEquals($url, $expected); + } + + public function testSecure() + { + $converter = new Convert(); + $converter->from('USD'); + $converter->to('CAD'); + $converter->amount('22.50'); + $converter->secure(); + $url = $converter->getUrl(); + $expected = str_replace('http', 'https', $this->url).'/convert&from=USD&to=CAD&amount=22.50'; + + $this->assertEquals($url, $expected); + } + + public function testResponse() + { + $response = m::mock('StdClass'); + $response->shouldReceive('getBody')->once()->andReturn(json_encode(['result' => 47.3685])); + + $client = m::mock('GuzzleHttp\Client'); + $client->shouldReceive('request')->once()->andReturn($response); + + $converter = new Convert($client); + $converter->from('USD'); + $converter->to('CAD'); + $converter->amount('22.50'); + $actual = $converter->get(); + $expected = 47.3685; + + $this->assertEquals($actual, $expected); + } + + public function testResponseAsObject() + { + $response = m::mock('StdClass'); + $response->shouldReceive('getBody')->once()->andReturn(json_encode(['result' => 47.3685])); + + $client = m::mock('GuzzleHttp\Client'); + $client->shouldReceive('request')->once()->andReturn($response); + + $converter = new Convert($client); + $converter->from('USD'); + $converter->to('CAD'); + $converter->amount('22.50'); + $actual = $converter->getAsObject(); + $expected = (object) 47.3685; + + $this->assertEquals($actual, $expected); + } + + /** + * @expectedException Fadion\Fixerio\Exceptions\ResponseException + * @expectedExceptionMessage Some error message + */ + public function testResponseException() + { + $response = m::mock('StdClass'); + $response->shouldReceive('getBody')->once()->andReturn(json_encode(['error' => 'Some error message'])); + + $client = m::mock('GuzzleHttp\Client'); + $client->shouldReceive('request')->once()->andReturn($response); + + $converter = new Convert($client); + $converter->get(); + } + + /** + * @expectedException Fadion\Fixerio\Exceptions\ResponseException + * @expectedExceptionMessage Some error message + */ + public function testResponseResultException() + { + $response = m::mock('StdClass'); + $response->shouldReceive('getBody')->once()->andReturn(json_encode(['error' => 'Some error message'])); + + $client = m::mock('GuzzleHttp\Client'); + $client->shouldReceive('request')->once()->andReturn($response); + + $converter = new Convert($client); + + $converter->getResult(); + } +}