1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the ONGR package. |
5
|
|
|
* |
6
|
|
|
* (c) NFQ Technologies UAB <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
namespace ONGR\CurrencyExchangeBundle\Service; |
13
|
|
|
|
14
|
|
|
use Elasticsearch\Common\Exceptions\Missing404Exception; |
15
|
|
|
use ONGR\CurrencyExchangeBundle\Document\CurrencyDocument; |
16
|
|
|
use ONGR\CurrencyExchangeBundle\Document\RatesObject; |
17
|
|
|
use ONGR\CurrencyExchangeBundle\Driver\CurrencyDriverInterface; |
18
|
|
|
use ONGR\CurrencyExchangeBundle\Exception\RatesNotLoadedException; |
19
|
|
|
use ONGR\ElasticsearchBundle\Result\Result; |
20
|
|
|
use ONGR\ElasticsearchDSL\Query\MatchAllQuery; |
21
|
|
|
use ONGR\ElasticsearchDSL\Query\MatchQuery; |
22
|
|
|
use ONGR\ElasticsearchDSL\Query\RangeQuery; |
23
|
|
|
use ONGR\ElasticsearchDSL\Sort\FieldSort; |
24
|
|
|
use ONGR\ElasticsearchBundle\Service\Manager; |
25
|
|
|
use Psr\Log\LoggerAwareTrait; |
26
|
|
|
use Stash\Interfaces\ItemInterface; |
27
|
|
|
use Stash\Interfaces\PoolInterface; |
28
|
|
|
use Symfony\Component\Validator\Constraints\DateTime; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* This class provides currency rates. |
32
|
|
|
*/ |
33
|
|
|
class CurrencyRatesService |
34
|
|
|
{ |
35
|
|
|
use LoggerAwareTrait; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @var null|array |
39
|
|
|
*/ |
40
|
|
|
public $rates = null; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @var CurrencyDriverInterface |
44
|
|
|
*/ |
45
|
|
|
private $driver; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var PoolInterface |
49
|
|
|
*/ |
50
|
|
|
private $pool; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @var Manager |
54
|
|
|
*/ |
55
|
|
|
private $manager; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* @param CurrencyDriverInterface $driver Currency exchange driver. |
59
|
|
|
* @param Manager $manager ES Manager. |
60
|
5 |
|
* @param PoolInterface $pool Cache pool. |
61
|
|
|
*/ |
62
|
|
|
public function __construct( |
63
|
|
|
CurrencyDriverInterface $driver, |
64
|
|
|
Manager $manager, |
65
|
5 |
|
PoolInterface $pool |
66
|
5 |
|
) { |
67
|
5 |
|
$this->driver = $driver; |
68
|
5 |
|
$this->manager = $manager; |
69
|
|
|
$this->pool = $pool; |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* This method returns exchange rates. |
74
|
|
|
* |
75
|
|
|
* @param string|null $date |
76
|
4 |
|
* |
77
|
|
|
* @throws RatesNotLoadedException |
78
|
4 |
|
* @return array |
79
|
3 |
|
*/ |
80
|
|
|
public function getRates($date = null) |
81
|
|
|
{ |
82
|
4 |
|
$date = $date ? $date : $this->getCurrentDate(); |
83
|
4 |
|
|
84
|
4 |
|
if (isset($this->rates[$date])) { |
85
|
1 |
|
return $this->rates[$date]; |
86
|
|
|
} |
87
|
|
|
|
88
|
3 |
|
$item = $this->getCachedRates(); |
89
|
3 |
|
$this->rates = $item->get(); |
90
|
|
|
if (isset($this->rates[$date])) { |
91
|
|
|
return $this->rates[$date]; |
92
|
|
|
} |
93
|
3 |
|
|
94
|
3 |
|
$this->rates = $this->getRatesFromBackup($date); |
95
|
2 |
|
if (isset($this->rates[$date])) { |
96
|
|
|
return $this->rates[$date]; |
97
|
1 |
|
} elseif ($date != $this->getCurrentDate()) { |
98
|
|
|
throw new RatesNotLoadedException( |
99
|
|
|
'Currency rates for '.$date.' are not loaded and could not be loaded on demand' |
100
|
|
|
); |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
$this->reloadRates(); |
104
|
|
|
if (isset($this->rates[$date])) { |
105
|
3 |
|
return $this->rates[$date]; |
106
|
|
|
} |
107
|
3 |
|
throw new RatesNotLoadedException( |
108
|
3 |
|
'Currency rates for '.$date.' are not loaded and could not be loaded on demand' |
109
|
3 |
|
); |
110
|
3 |
|
} |
111
|
3 |
|
|
112
|
3 |
|
/** |
113
|
3 |
|
* Returns currency rates from ES. |
114
|
|
|
* |
115
|
3 |
|
* @param string|null $date |
116
|
3 |
|
* |
117
|
1 |
|
* @return array |
118
|
|
|
*/ |
119
|
1 |
|
private function getRatesFromBackup($date = null) |
120
|
|
|
{ |
121
|
|
|
$date = $date ? $date : $this->getCurrentDate(); |
122
|
2 |
|
$rates = []; |
123
|
|
|
$currency = $this->getCurrencyFromEs($date); |
124
|
|
|
|
125
|
|
|
if (!empty($currency)) { |
126
|
|
|
foreach ($currency['rates'] as $data) { |
127
|
|
|
$rates[$data['name']] = $data['value']; |
128
|
|
|
} |
129
|
|
|
$this->logger && $this->logger->notice('Rates returned from ES. Cache updated.'); |
130
|
|
|
$this->updateRatesCache($rates, new \DateTime($currency['created_at'])); |
131
|
|
|
|
132
|
2 |
|
return [$date => $rates]; |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
return null; |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
/** |
139
|
|
|
* Update rates in cache. |
140
|
2 |
|
* |
141
|
|
|
* @param array $rates |
142
|
2 |
|
* @param \DateTime $createdAt |
143
|
2 |
|
*/ |
144
|
|
|
private function updateRatesCache($rates, \DateTime $createdAt = null) |
145
|
|
|
{ |
146
|
|
|
$createdAt = $createdAt ? $createdAt : new \DateTime(); |
147
|
|
|
$cache = [ |
148
|
4 |
|
$createdAt->format('Y-m-d') => $rates |
149
|
|
|
]; |
150
|
4 |
|
$this->getCachedRates()->set($cache); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* @return ItemInterface |
155
|
|
|
*/ |
156
|
|
|
private function getCachedRates() |
157
|
|
|
{ |
158
|
3 |
|
return $this->pool->getItem('ongr_currency'); |
|
|
|
|
159
|
|
|
} |
160
|
3 |
|
|
161
|
3 |
|
/** |
162
|
|
|
* Reloads rates using given driver. |
163
|
|
|
* |
164
|
3 |
|
* @return array |
165
|
3 |
|
*/ |
166
|
|
|
public function reloadRates() |
167
|
3 |
|
{ |
168
|
2 |
|
$date = $this->getCurrentDate(); |
169
|
2 |
|
|
170
|
2 |
|
$esCurrency = $this->getCurrencyFromEs($date); |
171
|
2 |
|
if (!empty($esCurrency)) { |
172
|
2 |
|
$this->rates = [ |
173
|
2 |
|
$date => $esCurrency['rates'] |
174
|
2 |
|
]; |
175
|
2 |
|
return $this->rates; |
176
|
2 |
|
} |
177
|
2 |
|
|
178
|
|
|
$rates = $this->driver->getRates(); |
179
|
2 |
|
|
180
|
|
|
if ($rates) { |
|
|
|
|
181
|
1 |
|
$this->rates = [ |
182
|
|
|
$date => $rates |
183
|
1 |
|
]; |
184
|
|
|
} |
185
|
|
|
|
186
|
|
|
/** @var CurrencyDocument $document */ |
187
|
|
|
$document = new CurrencyDocument(); |
188
|
|
|
|
189
|
|
|
if ($this->rates[$date]) { |
190
|
|
|
foreach ($this->rates[$date] as $name => $value) { |
191
|
2 |
|
$ratesObject = new RatesObject(); |
192
|
|
|
$ratesObject->setName($name); |
193
|
2 |
|
$ratesObject->setValue($value); |
194
|
|
|
$document->addRate($ratesObject); |
195
|
|
|
} |
196
|
|
|
$this->manager->persist($document); |
197
|
|
|
$this->manager->commit(); |
198
|
|
|
$this->updateRatesCache($this->rates, $document->getCreatedAt()); |
199
|
|
|
|
200
|
|
|
return $this->rates; |
201
|
|
|
} |
202
|
|
|
$this->logger && $this->logger->notice('Failed to retrieve currency rates from provider.'); |
203
|
|
|
|
204
|
|
|
return null; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* Returns actual base currency name. |
209
|
|
|
* |
210
|
|
|
* @return string |
211
|
|
|
*/ |
212
|
|
|
public function getBaseCurrency() |
213
|
|
|
{ |
214
|
|
|
return $this->driver->getBaseCurrency(); |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* Returns formatted current date |
219
|
|
|
* |
220
|
|
|
* @returns string |
221
|
|
|
*/ |
222
|
|
|
private function getCurrentDate() |
223
|
|
|
{ |
224
|
|
|
$now = new \DateTime(); |
225
|
|
|
return $now->format('Y-m-d'); |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
/** |
229
|
|
|
* Returns an array representing a currency for a specific date from ES |
230
|
|
|
* |
231
|
|
|
* @param string $date |
232
|
|
|
* |
233
|
|
|
* @returns array |
234
|
|
|
*/ |
235
|
|
|
private function getCurrencyFromEs($date) |
236
|
|
|
{ |
237
|
|
|
$repository = $this->manager->getRepository('ONGRCurrencyExchangeBundle:CurrencyDocument'); |
238
|
|
|
$search = $repository->createSearch(); |
239
|
|
|
$search->addQuery( |
240
|
|
|
new MatchQuery('date', $date) |
241
|
|
|
); |
242
|
|
|
$search->setSize(1); |
243
|
|
|
try { |
244
|
|
|
$results = $repository->execute($search, Result::RESULTS_ARRAY); |
245
|
|
|
} catch (Missing404Exception $e) { |
246
|
|
|
$this->logger && $this->logger->notice('Failed to execute query. Please check ES configuration'); |
247
|
|
|
|
248
|
|
|
return null; |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
return count($results) > 0 ? $results[0] : []; |
252
|
|
|
} |
253
|
|
|
} |
254
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.