1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace CurrencyConverter\Controller\Component; |
4
|
|
|
|
5
|
|
|
use Cake\Controller\Component; |
6
|
|
|
use Cake\Datasource\ConnectionManager; |
7
|
|
|
use Cake\ORM\TableRegistry; |
8
|
|
|
use Cake\I18n\Time; |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* CurrencyConverter Component to convert currency. |
12
|
|
|
* |
13
|
|
|
* Convert an amount number from one currency to an other currency |
14
|
|
|
* Return currency rate from one currency to an other |
15
|
|
|
* output type from HTML to JSON format. |
16
|
|
|
*/ |
17
|
|
View Code Duplication |
class CurrencyConverterComponent extends Component |
|
|
|
|
18
|
|
|
{ |
19
|
|
|
/** |
20
|
|
|
* CurrencyratesTable Object |
21
|
|
|
* @var \Cake\ORM\Table |
22
|
|
|
*/ |
23
|
|
|
private $_currencyratesTable; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Default CurrencyConverterComponent settings. |
27
|
|
|
* |
28
|
|
|
* When calling CurrencyConverterComponent() these settings will be merged with the configuration |
29
|
|
|
* you provide. |
30
|
|
|
* |
31
|
|
|
* - `database` - Mention if Component have to store currency rate in database |
32
|
|
|
* - `refresh` - Time interval for Component to refresh currency rate in database |
33
|
|
|
* - `decimal` - Number of decimal to use when formatting amount float number |
34
|
|
|
* |
35
|
|
|
* @var array |
36
|
|
|
*/ |
37
|
|
|
protected $_defaultConfig = [ |
38
|
|
|
'database' => true, // Mention if Component have to store currency rate in database |
39
|
8 |
|
'refresh' => 24, // Time interval for Component to refresh currency rate in database |
40
|
|
|
'decimal' => 2, // Number of decimal to use when formatting amount float number |
41
|
|
|
]; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* @param array $config |
45
|
|
|
* @return void |
46
|
|
|
*/ |
47
|
8 |
|
public function initialize(array $config = []) { |
48
|
8 |
|
|
49
|
8 |
|
$config = $this->getConfig(); |
50
|
8 |
|
|
51
|
8 |
|
$this->database = $config['database']; |
|
|
|
|
52
|
8 |
|
$this->refresh = $config['refresh']; |
|
|
|
|
53
|
8 |
|
$this->decimal = $config['decimal']; |
|
|
|
|
54
|
|
|
|
55
|
8 |
|
$this->_currencyratesTable = TableRegistry::get('CurrencyConverter.Currencyrates'); |
|
|
|
|
56
|
7 |
|
} |
57
|
|
|
|
58
|
7 |
|
/** |
59
|
5 |
|
* Convert method take an amount as first parameter and convert it using $from currency and $to currency. |
60
|
5 |
|
* |
61
|
|
|
* @param float|string $amount the amount to convert. |
62
|
5 |
|
* @param string $from currency to convert from |
63
|
|
|
* @param string $to currency to convert to |
64
|
5 |
|
* @return float $amount converted |
65
|
5 |
|
*/ |
66
|
|
|
public function convert($amount, $from, $to) |
67
|
5 |
|
{ |
68
|
|
|
$amount = floatval($amount); |
69
|
|
|
$rate = $this->getRateToUse($from, $to); |
70
|
2 |
|
|
71
|
|
|
return $convert = $this->_formatConvert($rate * $amount); |
|
|
|
|
72
|
2 |
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
1 |
|
* Rate method return the rate of two currencies |
76
|
|
|
* |
77
|
|
|
* @param string $from currency to get the rate from |
78
|
7 |
|
* @param string $to currency to get the rate to |
79
|
|
|
* @return float|null $rate |
80
|
7 |
|
*/ |
81
|
1 |
|
public function rate($from, $to) |
82
|
1 |
|
{ |
83
|
|
|
return $this->getRateToUse($from, $to); |
84
|
7 |
|
} |
85
|
1 |
|
|
86
|
1 |
|
/** |
87
|
7 |
|
* getRateToUse return rate to use |
88
|
|
|
* Using $from and $to parameters representing currency to deal with and the configuration settings |
89
|
5 |
|
* This method save or update currencyrates Table if necesseray too. |
90
|
|
|
* |
91
|
5 |
|
* @param string $from currency to get the rate from |
92
|
5 |
|
* @param string $to currency to get the rate to |
93
|
|
|
* @return float|null $rate |
94
|
5 |
|
*/ |
95
|
5 |
|
public function getRateToUse($from, $to) |
96
|
|
|
{ |
97
|
5 |
|
if ($from == $to) return 1; |
98
|
2 |
|
if ($this->database) { |
99
|
|
|
// Get a currency rate from table |
100
|
2 |
|
$result = $this->_currencyratesTable->find('all')->where(['from_currency' => $from, 'to_currency' => $to])->first(); |
101
|
2 |
|
// If currency rate is in table and it doesn't have to be updated |
102
|
2 |
|
if ($result && $result->modified->wasWithinLast($this->refresh . ' hours')) return $rate = $result->rate; |
|
|
|
|
103
|
|
|
// If currency rate is in table and it have to be updated |
104
|
2 |
|
if ($result && !$result->modified->wasWithinLast($this->refresh . ' hours')) { |
105
|
|
|
if ($rate = $this->_getRateFromAPI($from, $to)) { |
106
|
|
|
$result->rate = $rate; |
107
|
2 |
|
$this->_currencyratesTable->save($result); |
|
|
|
|
108
|
|
|
} |
109
|
5 |
|
return $rate; |
110
|
|
|
} |
111
|
5 |
|
// If currency rate isn't in table |
112
|
3 |
|
if (!$result) { |
113
|
3 |
|
if ($rate = $this->_getRateFromAPI($from, $to)) { |
114
|
5 |
|
$entity = $this->_currencyratesTable->newEntity([ |
115
|
|
|
'from_currency' => $from, |
116
|
|
|
'to_currency' => $to, |
117
|
|
|
'rate' => $rate |
118
|
|
|
]); |
119
|
|
|
$this->_currencyratesTable->save($entity); |
120
|
|
|
} |
121
|
|
|
return $rate; |
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
return $this->_getRateFromAPI($from, $to); |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Format float number using configuration |
130
|
|
|
* |
131
|
|
|
* @return floatval |
132
|
3 |
|
*/ |
133
|
|
|
private function _formatConvert($number) |
134
|
3 |
|
{ |
135
|
|
|
return number_format($number, $this->decimal); |
136
|
|
|
} |
137
|
3 |
|
|
138
|
3 |
|
/** |
139
|
3 |
|
* Call free.currencyconverterapi.com API to get a rate for one currency to an other one currency |
140
|
3 |
|
* |
141
|
3 |
|
* @param string $from the currency |
142
|
3 |
|
* @param string $to the currency |
143
|
|
|
* @return int|null $rate |
144
|
3 |
|
*/ |
145
|
3 |
|
private function _getRateFromAPI($from, $to) |
146
|
3 |
|
{ |
147
|
|
|
$rate = null; |
148
|
2 |
|
|
149
|
|
|
$url = 'https://free.currencyconverterapi.com/api/v5/convert?q=' . $from . '_' . $to . '&compact=ultra'; |
150
|
|
|
$request = @fopen($url, 'r'); |
151
|
2 |
|
|
152
|
2 |
|
if ($request) { |
153
|
2 |
|
$response = fgets($request, 4096); |
154
|
2 |
|
fclose($request); |
155
|
2 |
|
$response = json_decode($response, true); |
156
|
2 |
|
if (isset($response[$from . '_' . $to])) { |
157
|
|
|
$rate = $response[$from . '_' . $to]; |
158
|
|
|
} |
159
|
5 |
|
} |
160
|
|
|
|
161
|
5 |
|
return $rate; |
162
|
|
|
} |
163
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.