1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace RunOpenCode\ExchangeRate\Source; |
4
|
|
|
|
5
|
|
|
use Goutte\Client as GoutteClient; |
6
|
|
|
use GuzzleHttp\Client as GuzzleClient; |
7
|
|
|
use GuzzleHttp\Cookie\CookieJar; |
8
|
|
|
use Psr\Log\LoggerAwareTrait; |
9
|
|
|
use RunOpenCode\ExchangeRate\Contract\RateInterface; |
10
|
|
|
use RunOpenCode\ExchangeRate\Contract\SourceInterface; |
11
|
|
|
use RunOpenCode\ExchangeRate\Exception\SourceNotAvailableException; |
12
|
|
|
use RunOpenCode\ExchangeRate\Exception\UnknownCurrencyCodeException; |
13
|
|
|
use RunOpenCode\ExchangeRate\Exception\UnknownRateTypeException; |
14
|
|
|
use Symfony\Component\DomCrawler\Crawler; |
15
|
|
|
|
16
|
|
|
class NationalBankOfSerbiaDomCrawlerSource implements SourceInterface |
17
|
|
|
{ |
18
|
|
|
const SOURCE = 'http://www.nbs.rs/kursnaListaModul/naZeljeniDan.faces'; |
19
|
|
|
|
20
|
|
|
use LoggerAwareTrait; |
21
|
|
|
|
22
|
|
|
private $cache; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* {@inheritdoc} |
26
|
|
|
*/ |
27
|
|
|
public function getName() |
28
|
|
|
{ |
29
|
|
|
return 'national_bank_of_serbia'; |
30
|
|
|
} |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* {@inheritdoc} |
34
|
|
|
*/ |
35
|
|
|
public function fetch($currencyCode, $rateType = 'default', $date = null) |
36
|
|
|
{ |
37
|
|
|
$this |
38
|
|
|
->validateRateType($rateType) |
39
|
|
|
->validateCurrencyCode($currencyCode, $rateType); |
40
|
|
|
|
41
|
|
|
if (is_null($date)) { |
42
|
|
|
$date = new \DateTime('now'); |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
if ($this->cache === null) { |
46
|
|
|
$this->cache = $this->load($date); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
if (array_key_exists($key = sprintf('%s_%s', $currencyCode, $rateType), $this->cache)) { |
50
|
|
|
return $this->cache[$key]; |
51
|
|
|
} else { |
|
|
|
|
52
|
|
|
// Baciti exception. |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
} |
56
|
|
|
|
57
|
|
View Code Duplication |
protected function validateRateType($rateType) |
|
|
|
|
58
|
|
|
{ |
59
|
|
|
$knownTypes = array( |
60
|
|
|
'default', // It is actually a middle exchange rate |
61
|
|
|
'foreign_cache_buying', |
62
|
|
|
'foreign_cache_selling', |
63
|
|
|
'foreign_exchange_buying', |
64
|
|
|
'foreign_exchange_selling' |
65
|
|
|
); |
66
|
|
|
|
67
|
|
|
if (!in_array($rateType, $knownTypes)) { |
68
|
|
|
throw new UnknownRateTypeException(sprintf('Unknown rate type "%s" for source "%s", known types are: %s.', $rateType, $this->getName(), implode(', ', $knownTypes))); |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
return $this; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
View Code Duplication |
protected function validateCurrencyCode($currencyCode, $rateType) |
|
|
|
|
75
|
|
|
{ |
76
|
|
|
$supports = array( |
77
|
|
|
'default' => array( |
78
|
|
|
'EUR' |
79
|
|
|
), |
80
|
|
|
'foreign_cache_buying', |
81
|
|
|
'foreign_cache_selling', |
82
|
|
|
'foreign_exchange_buying', |
83
|
|
|
'foreign_exchange_selling' |
84
|
|
|
); |
85
|
|
|
|
86
|
|
|
if (!in_array($currencyCode, $supports[$rateType])) { |
87
|
|
|
throw new UnknownCurrencyCodeException(sprintf('Unknown currency code "%s".', $currencyCode)); |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
return $this; |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* @param \DateTime $date |
95
|
|
|
* @return RateInterface[] |
96
|
|
|
* @throws SourceNotAvailableException |
97
|
|
|
*/ |
98
|
|
|
protected function load(\DateTime $date) |
99
|
|
|
{ |
100
|
|
|
$guzzleClient = new GuzzleClient(array('cookies' => true)); |
101
|
|
|
$jar = new CookieJar; |
|
|
|
|
102
|
|
|
$client = new GoutteClient(); |
103
|
|
|
$client->setClient($guzzleClient); |
104
|
|
|
|
105
|
|
|
$crawler = $this->getCrawler($date); |
|
|
|
|
106
|
|
|
|
107
|
|
|
// parsiranje |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* @param \DateTime $date |
112
|
|
|
* @return Crawler |
113
|
|
|
* @throws SourceNotAvailableException |
114
|
|
|
*/ |
115
|
|
|
protected function getCrawler(\DateTime $date) |
116
|
|
|
{ |
117
|
|
|
$url = sprintf('http', $date->format('Y-m-d')); |
118
|
|
|
$goutte = new Client(); |
119
|
|
|
try { |
120
|
|
|
return $goutte->request('GET', $url); |
121
|
|
|
} catch (\Exception $e) { |
122
|
|
|
throw new SourceNotAvailableException(sprintf('Source not available on "%s".', $url), 0, $e); |
123
|
|
|
} |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
protected function getPostParams(\DateTime $date, $rateType) |
127
|
|
|
{ |
128
|
|
|
return array( |
129
|
|
|
'index:brKursneListe:' => '', |
130
|
|
|
'index:year' => $date->format('Y'), |
131
|
|
|
'index:inputCalendar1' => $date->format('d/m/Y'), |
132
|
|
|
'index:vrsta' => call_user_func(function($rateType) { |
133
|
|
|
switch ($rateType) { |
134
|
|
|
case 'foreign_cache_buying': // FALL TROUGH |
135
|
|
|
case 'foreign_cache_selling': |
136
|
|
|
return 1; |
137
|
|
|
break; |
|
|
|
|
138
|
|
|
case 'foreign_exchange_buying': // FALL TROUGH |
139
|
|
|
case 'foreign_exchange_selling': |
140
|
|
|
return 2; |
141
|
|
|
break; |
|
|
|
|
142
|
|
|
default: |
143
|
|
|
return 3; |
144
|
|
|
break; |
|
|
|
|
145
|
|
|
} |
146
|
|
|
}, $rateType), |
147
|
|
|
'index:prikaz' => 0, |
148
|
|
|
'index:buttonShow' => 'Show', |
149
|
|
|
'index' => 'index', |
150
|
|
|
'com.sun.faces.VIEW' => null |
151
|
|
|
); |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
protected function extractCsrfToken(GuzzleClient $guzzleClient, CookieJar $jar) |
155
|
|
|
{ |
156
|
|
|
$response = $guzzleClient->request('GET', self::SOURCE, array('cookies' => $jar)); |
157
|
|
|
$crawler = new Crawler($response->getBody()->getContents()); |
158
|
|
|
|
159
|
|
|
$hiddens = $crawler->filter('input[type="hidden"]'); |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* @var \DOMElement $hidden |
163
|
|
|
*/ |
164
|
|
|
foreach ($hiddens as $hidden) { |
165
|
|
|
|
166
|
|
|
if ($hidden->getAttribute('id') === 'com.sun.faces.VIEW') { |
167
|
|
|
return $hidden->getAttribute('value'); |
168
|
|
|
} |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
$exception = new \RuntimeException('FATAL ERROR: National Bank of Serbia changed it\'s API, unable to extract token.'); |
172
|
|
|
|
173
|
|
|
if ($this->logger) { |
174
|
|
|
$this->logger->emergency($exception->getMessage()); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
throw $exception; |
178
|
|
|
} |
179
|
|
|
} |
180
|
|
|
|
This check looks for the
else
branches ofif
statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.These
else
branches can be removed.could be turned into
This is much more concise to read.