CakePHP Currency Conversion Component
Published: on 23/6/08 | Comments (6)
Ever needed a reliable currency converter, that you can just drop into your application and never worry about manually updating the rates for.
Well I do for a current application I have been developing and I decided that it would make an ideal example for demonstrating how easy it is to create usefull CakePHP components.
So after a little Googling, I found that the Central European Bank, rather conveniently publishes an XML feed of rates against the Euro that is updated nightly, by using the HttpSocket class, the XML class and a little bit of code, I created the following component which you are welcome to copy and use in any way you please.
Using the component
To use the component, simply copy the code into a file called currency.php and place that in your app/controllers/components folder, add 'Currency' to the $components array of the controller you need the functionality within (or app_controller if you want it avaliable site wide) then use:
$result = $this->Currency->convert($amount,$fromCurrency,$toCurrency,$decimalPlaces);
Where $amount is the amount of money you want to convert, $fromCurrency is a 3 Character currency code from the table shown at the bottom of this article that you are converting from, $toCurrency is the 3 Character currency code that you want to convert to, and decimalPlaces is the number of decimal places you want the result returned to, so for example:
$result = $this->Currency->convert(2.5, 'EUR', 'USD');
will give the US Dollar value for €2.50.
I have added a second function called table which returns an array of rates where each rate is expressed against a given base rate, for example:
$result = $this->currency->table('USD',4);
Will return an array of currencies compared to US Dollars and to 4 decimal places.
O.K. so explaination over, here is the code and a table of currency codes, there are 35 different currencies all told so should be enough to cover most needs.
<?php
class CurrencyComponent extends object{
/**
* $components
*
* Array of components required
*
* @var $components array
* @access public
*/
var $components = array('Session');
/**
* convert
*
* Converts the $amount from $fromCurrency to $toCurrency, formatted to
* $decimals decimal places
*
* @return float [Converted Currency Amount]
* @param $amount float
* @param $fromCurrency string
* @param $toCurrency string
* @param $decimals integer[optional]default=2
*/
function convert($amount,$fromCurrency,$toCurrency,$decimals = 2){
//Get the rate table
$rates = $this->__retrieveCurrencies();
//Return result of conversion
return number_format($amount/$rates[$fromCurrency]*$rates[$toCurrency],$decimals);
}
/**
* table
*
* Returns an array of rates in comparison the the $base currency given to $decimals
* number of decimal places
*
* @return array
* @param $base string[optional]default='EUR'
* @param $decimals integer[optional]default=2
*/
function table($base='EUR',$decimals=2){
//Create array to holds rates
$rateTable = array();
//Get rate table array
$rates = $this->__retrieveCurrencies();
//Iterate throught each rate converting it against $base
foreach($rates as $key=>$value){
$rateTable[$key]=number_format(1/$rates[$base]*$rates[$key],$decimals);
}
//Return result array
return $rateTable;
}
function __retrieveCurrencies(){
//Check whther we have already cached the currencies this session...
if(!$this->Session->check('Currencies')){
//...we haven't, so load utility classes needed
App::import('HttpSocket');
App::import('Xml');
//Create an http socket
$http =& new HttpSocket();
//And retrieve rates as an XML object
$currencies =& new XML($http->get('http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml'));
//Convert XML to array
$currencies = Set::reverse($currencies);
//Filter down to just the rates
$currencies = $currencies['Envelope']['Cube']['Cube']['Cube'];
//Create an array to hold the rates
$currencyList = array();
//European Central bank gives us everything against Euro so add this manually
$currencyList['EUR']=1;
//Now iterate through and add the rates provided
foreach($currencies as $currency){
$currencyList[$currency['currency']]=$currency['rate'];
}
//Save to session
$this->Session->write('Currencies',$currencyList);
}
//Return rates array from session
return $this->Session->read('Currencies');
}
}
?>
| Currency | Code |
|---|---|
| Euro | EUR | US Dollar | USD |
| Japanese Yen | JPY |
| Bulgarian Lev | BGN |
| Czech Koruna | CZK |
| Danish Krone | DKK |
| Estonian Kroon | EEK |
| Pound Sterling | GBP |
| Hungarian Forint | HUF |
| Lithuanian Litas | LTL |
| Latvian Lats | LVL |
| Polish Zloty | PLN |
| New Romanian Leu | RON |
| Swedish Krona | SEK |
| Slovak Koruna | SKK |
| Swiss Franc | CHF |
| Icelandic Krona | ISK |
| Norwegian Krone | NOK |
| Croatian Kuna | HRK |
| Russian Rouble | RUB |
| New Turkish Lira | TRY |
| Australian Dollar | AUD |
| Brasilian Real | BRL |
| Canadian Dollar | CAD |
| Chinese Yuan Renminbi | CNY |
| Hong Kong Dollar | HKD |
| Indonesian Rupiah | IDR |
| South Korean Won | KRW |
| Mexican Peso | MXN |
| Malaysian Ringgit | MYR |
| New Zealand Dollar | NZD |
| Philippine Peso | PHP |
| Singapore Dollar | SGD |
| Thai Baht | THB |
| South African Rand | ZAR |
Hope you find this component usefull, let me know if you come up with any additional functionality you'd like it to include and 'till next time
Happy Baking!
Comments
-
1:
butters says
on 24/6/08
hey, nice idea, but i would prefer to cache the currency-xml-file not in a session but on the filesystem or database. your component have to ask the ecb once a day, not every new session-user ;)
bye, butters
-
2:
Peter Butler says
on 25/6/08
@butters: Valid point and if anyone would like me to alter the component to do this then let me know through these comments and I will make the changes to illustrate how this is done simply with cakephp.
Also if anyone has any requests or suggestions for other components or code snippets either drop me a line(see my contact page for email address) or leave a comment here.
Best Regards
Peter
-
3:
Mike says
on 30/6/08
@Peter: Implementing a cache makes more sense for app speed, bandwidth, and to not getting everyone's access to the ECB rates blocked. Anything you could add about how to cache a non-view would be helpful. Off the top of my head I think it just requires adding the Cache helper and "var cacheAction = '+1 hour';" in your component and then calling "$this->cacheAction = $currencyList;" instead of "$this->Session->write('Currencies',$currencyList);". Will that work from within a component & not a controller?
@butters: Good idea about adding caching. I think caching to the filesystem makes more sense than to the DB, unless you want to write an extra model to handle that data. Any reason the DB would be better?
-
4:
Jeff says
on 12/7/08
I
m a beginner at php I wan to apply this component to my website...ive supplied you with a demo link belowcan this component do the job like the site below
and can it be done without using cakephp and only using php
http://www.go2africa.com/south-africa/cape-town/accommodation
-
5:
Fahad says
on 30/7/08
nice one. Set::reverse() is just magic! thanks
-
6:
Alex says
on 16/8/08
Your blog is interesting!
Keep up the good work!
