1
|
|
|
<?php |
2
|
|
|
/* |
3
|
|
|
* This file is part of the Exchange Rate package, an RunOpenCode project. |
4
|
|
|
* |
5
|
|
|
* (c) 2017 RunOpenCode |
6
|
|
|
* |
7
|
|
|
* For the full copyright and license information, please view the LICENSE |
8
|
|
|
* file that was distributed with this source code. |
9
|
|
|
*/ |
10
|
|
|
namespace RunOpenCode\ExchangeRate\Repository; |
11
|
|
|
|
12
|
|
|
use RunOpenCode\ExchangeRate\Contract\RateInterface; |
13
|
|
|
use RunOpenCode\ExchangeRate\Contract\RepositoryInterface; |
14
|
|
|
use RunOpenCode\ExchangeRate\Enum\RateType; |
15
|
|
|
use RunOpenCode\ExchangeRate\Exception\ExchangeRateException; |
16
|
|
|
use RunOpenCode\ExchangeRate\Utils\RateFilterUtil; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Class MemoryRepository |
20
|
|
|
* |
21
|
|
|
* Memory repository is useful for unit testing only. |
22
|
|
|
* |
23
|
|
|
* @package RunOpenCode\ExchangeRate\Repository |
24
|
|
|
*/ |
25
|
|
|
class MemoryRepository implements RepositoryInterface |
26
|
|
|
{ |
27
|
|
|
/** |
28
|
|
|
* @var RateInterface[] |
29
|
|
|
*/ |
30
|
|
|
private $rates; |
31
|
|
|
|
32
|
21 |
|
public function __construct() |
33
|
|
|
{ |
34
|
21 |
|
$this->rates = []; |
35
|
21 |
|
} |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* {@inheritdoc} |
39
|
|
|
*/ |
40
|
15 |
|
public function save(array $rates) |
41
|
|
|
{ |
42
|
|
|
/** |
43
|
|
|
* @var RateInterface $rate |
44
|
|
|
*/ |
45
|
15 |
|
foreach ($rates as $rate) { |
46
|
15 |
|
$this->rates[$this->getRateKey($rate->getCurrencyCode(), $rate->getDate(), $rate->getRateType(), $rate->getSourceName())] = $rate; |
47
|
|
|
} |
48
|
|
|
|
49
|
15 |
|
uasort($this->rates, function (RateInterface $rate1, RateInterface $rate2) { |
50
|
5 |
|
return ($rate1->getDate() > $rate2->getDate()) ? -1 : 1; |
51
|
15 |
|
}); |
52
|
15 |
|
} |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* {@inheritdoc} |
56
|
|
|
*/ |
57
|
1 |
View Code Duplication |
public function delete(array $rates) |
|
|
|
|
58
|
|
|
{ |
59
|
|
|
/** |
60
|
|
|
* @var RateInterface $rate |
61
|
|
|
*/ |
62
|
1 |
|
foreach ($rates as $rate) { |
63
|
1 |
|
unset($this->rates[$this->getRateKey($rate->getCurrencyCode(), $rate->getDate(), $rate->getRateType(), $rate->getSourceName())]); |
64
|
|
|
} |
65
|
1 |
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* {@inheritdoc} |
69
|
|
|
*/ |
70
|
13 |
View Code Duplication |
public function has($sourceName, $currencyCode, \DateTime $date = null, $rateType = RateType::MEDIAN) |
|
|
|
|
71
|
|
|
{ |
72
|
13 |
|
if ($date === null) { |
73
|
2 |
|
$date = new \DateTime('now'); |
74
|
|
|
} |
75
|
|
|
|
76
|
13 |
|
return array_key_exists($this->getRateKey($currencyCode, $date, $rateType, $sourceName), $this->rates); |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* {@inheritdoc} |
81
|
|
|
*/ |
82
|
10 |
View Code Duplication |
public function get($sourceName, $currencyCode, \DateTime $date = null, $rateType = RateType::MEDIAN) |
|
|
|
|
83
|
|
|
{ |
84
|
10 |
|
if ($date === null) { |
85
|
3 |
|
$date = new \DateTime('now'); |
86
|
|
|
} |
87
|
|
|
|
88
|
10 |
|
if ($this->has($sourceName, $currencyCode, $date, $rateType)) { |
89
|
8 |
|
return $this->rates[$this->getRateKey($currencyCode, $date, $rateType, $sourceName)]; |
90
|
|
|
} |
91
|
|
|
|
92
|
2 |
|
throw new ExchangeRateException(sprintf('Could not fetch rate for rate currency code "%s" and rate type "%s" on date "%s".', $currencyCode, $rateType, $date->format('Y-m-d'))); |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
/** |
96
|
|
|
* {@inheritdoc} |
97
|
|
|
*/ |
98
|
4 |
View Code Duplication |
public function latest($sourceName, $currencyCode, $rateType = RateType::MEDIAN, \DateTimeInterface $date = null) |
|
|
|
|
99
|
|
|
{ |
100
|
|
|
/** |
101
|
|
|
* @var RateInterface $rate |
102
|
|
|
*/ |
103
|
4 |
|
foreach ($this->rates as $rate) { |
104
|
|
|
|
105
|
|
|
if (null !== $date && $date < $rate->getDate()) { |
106
|
2 |
|
continue; |
107
|
|
|
} |
108
|
2 |
|
|
109
|
|
|
if ( |
110
|
2 |
|
$rate->getSourceName() === $sourceName |
111
|
|
|
&& |
112
|
2 |
|
$rate->getCurrencyCode() === $currencyCode |
113
|
|
|
&& |
114
|
|
|
$rate->getRateType() === $rateType |
115
|
|
|
) { |
116
|
2 |
|
return $rate; |
117
|
|
|
} |
118
|
|
|
} |
119
|
|
|
|
120
|
|
|
throw new ExchangeRateException(sprintf('Could not fetch latest rate for rate currency code "%s" and rate type "%s" from source "%s".', $currencyCode, $rateType, $sourceName)); |
121
|
|
|
} |
122
|
3 |
|
|
123
|
|
|
/** |
124
|
3 |
|
* {@inheritdoc} |
125
|
1 |
|
*/ |
126
|
|
View Code Duplication |
public function all(array $criteria = array()) |
|
|
|
|
127
|
|
|
{ |
128
|
2 |
|
if (count($criteria) == 0) { |
129
|
|
|
return $this->rates; |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
$result = array(); |
133
|
2 |
|
|
134
|
|
|
/** |
135
|
2 |
|
* @var RateInterface $rate |
136
|
2 |
|
*/ |
137
|
|
|
foreach ($this->rates as $rate) { |
138
|
|
|
|
139
|
|
|
if (RateFilterUtil::matches($rate, $criteria)) { |
140
|
2 |
|
$result[] = $rate; |
141
|
|
|
} |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
return $this->paginate($result, $criteria); |
145
|
|
|
} |
146
|
1 |
|
|
147
|
|
|
/** |
148
|
1 |
|
* {@inheritdoc} |
149
|
|
|
*/ |
150
|
|
|
public function count() |
151
|
|
|
{ |
152
|
|
|
return count($this->rates); |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* Builds rate key to speed up search. |
157
|
|
|
* |
158
|
|
|
* @param string $currencyCode |
159
|
|
|
* @param \DateTime $date |
160
|
18 |
|
* @param string $rateType |
161
|
|
|
* @param string $sourceName |
162
|
18 |
|
* @return string |
163
|
18 |
|
*/ |
164
|
18 |
View Code Duplication |
protected function getRateKey($currencyCode, $date, $rateType, $sourceName) |
|
|
|
|
165
|
18 |
|
{ |
166
|
|
|
return str_replace( |
167
|
|
|
array('%currency_code%', '%date%', '%rate_type%', '%source_name%'), |
168
|
|
|
array($currencyCode, $date->format('Y-m-d'), $rateType, $sourceName), |
169
|
|
|
'%currency_code%_%date%_%rate_type%_%source_name%' |
170
|
|
|
); |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* Extract requested page from filter criteria. |
175
|
|
|
* |
176
|
2 |
|
* @param array $rates Rates to filter for pagination. |
177
|
|
|
* @param array $criteria Filter criteria. |
178
|
2 |
|
* @return RateInterface[] Paginated rates. |
179
|
1 |
|
*/ |
180
|
|
View Code Duplication |
protected function paginate(array $rates, $criteria) |
|
|
|
|
181
|
|
|
{ |
182
|
1 |
|
if (!array_key_exists('offset', $criteria) && !array_key_exists('limit', $criteria)) { |
183
|
1 |
|
return $rates; |
184
|
1 |
|
} |
185
|
|
|
|
186
|
1 |
|
$range = array(); |
187
|
1 |
|
$offset = array_key_exists('offset', $criteria) ? $criteria['offset'] : 0; |
188
|
|
|
$limit = min((array_key_exists('limit', $criteria) ? $criteria['limit'] : count($rates)) + $offset, count($rates)); |
189
|
|
|
|
190
|
1 |
|
for ($i = $offset; $i < $limit; $i++) { |
191
|
|
|
$range[] = $rates[$i]; |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
return $range; |
195
|
|
|
} |
196
|
|
|
} |
197
|
|
|
|
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.