1
|
|
|
<?php |
2
|
|
|
/* |
3
|
|
|
* This file is part of the Exchange Rate package, an RunOpenCode project. |
4
|
|
|
* |
5
|
|
|
* Implementation of exchange rate crawler for Banca Intesa Serbia, http://www.bancaintesa.rs. |
6
|
|
|
* |
7
|
|
|
* (c) 2016 RunOpenCode |
8
|
|
|
* |
9
|
|
|
* For the full copyright and license information, please view the LICENSE |
10
|
|
|
* file that was distributed with this source code. |
11
|
|
|
*/ |
12
|
|
|
namespace RunOpenCode\ExchangeRate\BancaIntesaSerbia\Parser; |
13
|
|
|
|
14
|
|
|
use RunOpenCode\ExchangeRate\Contract\RateInterface; |
15
|
|
|
use RunOpenCode\ExchangeRate\Model\Rate; |
16
|
|
|
use RunOpenCode\ExchangeRate\BancaIntesaSerbia\Api; |
17
|
|
|
use Symfony\Component\DomCrawler\Crawler; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* Class HtmlParser |
21
|
|
|
* |
22
|
|
|
* Parse HTML document with daily rates from Banca Intesa Serbia. |
23
|
|
|
* |
24
|
|
|
* @package RunOpenCode\ExchangeRate\BancaIntesaSerbia\Parser |
25
|
|
|
*/ |
26
|
|
|
class HtmlParser |
27
|
|
|
{ |
28
|
|
|
/** |
29
|
|
|
* @var RateInterface[] |
30
|
|
|
*/ |
31
|
|
|
private $rates; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* @var \DateTime |
35
|
|
|
*/ |
36
|
|
|
private $date; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* @var string |
40
|
|
|
*/ |
41
|
|
|
private $html; |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* HtmlParser constructor. |
45
|
|
|
* @param $node string |
46
|
|
|
* @param $date \DateTime |
47
|
|
|
*/ |
48
|
10 |
|
public function __construct($node, \DateTime $date) |
49
|
|
|
{ |
50
|
10 |
|
$this->html = $node; |
51
|
10 |
|
$this->date = $date; |
52
|
10 |
|
} |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* @return array|\RunOpenCode\ExchangeRate\Contract\RateInterface[] |
56
|
|
|
*/ |
57
|
10 |
|
public function getRates() |
58
|
|
|
{ |
59
|
10 |
|
if (!$this->rates) { |
|
|
|
|
60
|
10 |
|
$this->rates = $this->parseHtml($this->html, $this->date); |
61
|
10 |
|
} |
62
|
|
|
|
63
|
10 |
|
return $this->rates; |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* @param $html string |
68
|
|
|
* @param \DateTime $date |
69
|
|
|
* @return array |
70
|
|
|
*/ |
71
|
10 |
|
private function parseHtml($html, \DateTime $date) |
72
|
|
|
{ |
73
|
10 |
|
$crawler = new Crawler($html); |
74
|
10 |
|
$crawler = $crawler->filter('table'); |
75
|
|
|
|
76
|
10 |
|
return $this->extractRates($crawler, $date); |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* @param Crawler $crawler |
81
|
|
|
* @param \DateTime $date |
82
|
|
|
* @return array |
83
|
|
|
*/ |
84
|
10 |
|
private function extractRates(Crawler $crawler, \DateTime $date) |
85
|
|
|
{ |
86
|
10 |
|
$rates = array(); |
87
|
|
|
|
88
|
|
|
$crawler->filter('tr')->each(function (Crawler $node) use ($date, &$rates) { |
89
|
|
|
|
90
|
10 |
|
$row = $this->parseRow($node); |
91
|
|
|
|
92
|
10 |
|
if (null !== $row) { |
93
|
|
|
|
94
|
10 |
|
$rates[] = $this->buildRate( |
95
|
10 |
|
$row['default'] / $row['unit'], |
96
|
10 |
|
$row['currencyCode'], |
97
|
10 |
|
'default', |
98
|
|
|
$date |
99
|
10 |
|
); |
100
|
|
|
|
101
|
10 |
|
$rates[] = $this->buildRate( |
102
|
10 |
|
$row['foreign_exchange_buying'] / $row['unit'], |
103
|
10 |
|
$row['currencyCode'], |
104
|
10 |
|
'foreign_exchange_buying', |
105
|
|
|
$date |
106
|
10 |
|
); |
107
|
|
|
|
108
|
10 |
|
$rates[] = $this->buildRate( |
109
|
10 |
|
$row['foreign_exchange_selling'] / $row['unit'], |
110
|
10 |
|
$row['currencyCode'], |
111
|
10 |
|
'foreign_exchange_selling', |
112
|
10 |
|
$this->date |
113
|
10 |
|
); |
114
|
|
|
|
115
|
10 |
|
$rates[] = $this->buildRate( |
116
|
10 |
|
$row['foreign_cash_buying'] / $row['unit'], |
117
|
10 |
|
$row['currencyCode'], |
118
|
10 |
|
'foreign_cash_buying', |
119
|
10 |
|
$this->date |
120
|
10 |
|
); |
121
|
|
|
|
122
|
10 |
|
$rates[] = $this->buildRate( |
123
|
10 |
|
$row['foreign_cash_selling'] / $row['unit'], |
124
|
10 |
|
$row['currencyCode'], |
125
|
10 |
|
'foreign_cash_selling', |
126
|
10 |
|
$this->date |
127
|
10 |
|
); |
128
|
|
|
|
129
|
10 |
|
} |
130
|
10 |
|
}); |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* @var Rate $rate |
134
|
|
|
*/ |
135
|
10 |
|
foreach ($rates as $key => $rate){ |
136
|
10 |
|
if (!$rate->getValue()) { |
137
|
10 |
|
unset($rates[$key]); |
138
|
10 |
|
} |
139
|
10 |
|
} |
140
|
|
|
|
141
|
|
|
|
142
|
10 |
|
return $rates; |
143
|
|
|
} |
144
|
|
|
|
145
|
10 |
|
private function parseRow(Crawler $crawler) |
146
|
|
|
{ |
147
|
|
|
$currentRow = array( |
148
|
|
|
'currencyCode' => '' |
149
|
10 |
|
); |
150
|
|
|
|
151
|
10 |
|
$crawler->filter('td')->each(function (Crawler $node, $i) use (&$currentRow) { |
152
|
|
|
|
153
|
|
|
switch ($i) { |
154
|
10 |
|
case 1: |
155
|
10 |
|
$currentRow['currencyCode'] = trim($node->text()); |
156
|
10 |
|
break; |
157
|
10 |
|
case 2: |
158
|
10 |
|
$currentRow['unit'] = (int)trim($node->text()); |
159
|
10 |
|
break; |
160
|
10 |
|
case 3: |
161
|
10 |
|
$currentRow['foreign_exchange_buying'] = (float)trim($node->text()); |
162
|
10 |
|
break; |
163
|
10 |
|
case 4: |
164
|
10 |
|
$currentRow['default'] = (float)trim($node->text()); |
165
|
10 |
|
break; |
166
|
10 |
|
case 5: |
167
|
10 |
|
$currentRow['foreign_exchange_selling'] = (float)trim($node->text()); |
168
|
10 |
|
break; |
169
|
10 |
|
case 6: |
170
|
10 |
|
$currentRow['foreign_cash_buying'] = (float)trim($node->text()); |
171
|
10 |
|
break; |
172
|
10 |
|
case 7: |
173
|
10 |
|
$currentRow['foreign_cash_selling'] = (float)trim($node->text()); |
174
|
10 |
|
break; |
175
|
|
|
} |
176
|
10 |
|
}); |
177
|
|
|
|
178
|
10 |
|
return strlen($currentRow['currencyCode']) === 3 ? $currentRow : null; |
179
|
|
|
} |
180
|
|
|
|
181
|
10 |
|
private function buildRate($value, $currencyCode, $rateType, $date) { |
182
|
|
|
|
183
|
10 |
|
return new Rate( |
184
|
10 |
|
Api::NAME, |
185
|
10 |
|
$value, |
186
|
10 |
|
$currencyCode, |
187
|
10 |
|
$rateType, |
188
|
10 |
|
$date, |
189
|
10 |
|
'RSD', |
190
|
10 |
|
new \DateTime('now'), |
191
|
10 |
|
new \DateTime('now') |
192
|
10 |
|
); |
193
|
|
|
} |
194
|
|
|
} |
195
|
|
|
|
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.