Completed
Push — master ( ee79c6...acd82f )
by Nikola
03:33 queued 01:47
created

NbsBrowser   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 122
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 97.5%

Importance

Changes 0
Metric Value
wmc 13
lcom 1
cbo 6
dl 0
loc 122
ccs 39
cts 40
cp 0.975
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
B getXmlDocument() 0 27 5
A request() 0 12 1
A getFormCsrfToken() 0 18 3
A getGuzzleClient() 0 8 2
A getGuzzleCookieJar() 0 8 2
1
<?php
2
/*
3
 * This file is part of the Exchange Rate package, an RunOpenCode project.
4
 *
5
 * Implementation of exchange rate crawler for National Bank of Serbia, http://www.nbs.rs.
6
 *
7
 * (c) 2017 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\NationalBankOfSerbia\Util;
13
14
use GuzzleHttp\Client;
15
use GuzzleHttp\Cookie\CookieJar;
16
use Psr\Http\Message\StreamInterface;
17
use RunOpenCode\ExchangeRate\NationalBankOfSerbia\Enum\RateType;
18
use RunOpenCode\ExchangeRate\NationalBankOfSerbia\Exception\RuntimeException;
19
use Symfony\Component\DomCrawler\Crawler;
20
21
/**
22
 * Class NbsBrowser
23
 *
24
 * Browser browses trough web site of National Bank of Serbia and fetches documents with rates.
25
 *
26
 * @package RunOpenCode\ExchangeRate\NationalBankOfSerbia\Util
27
 */
28
class NbsBrowser
29
{
30
    const SOURCE = 'http://www.nbs.rs/kursnaListaModul/naZeljeniDan.faces';
31
    /**
32
     * @var Client
33
     */
34
    private $guzzleClient;
35
36
    /**
37
     * @var CookieJar
38
     */
39
    private $guzzleCookieJar;
40
41
    /**
42
     * Get XML document with rates.
43
     *
44
     * @param \DateTime $date
45
     * @param string $rateType
46
     * @return StreamInterface
47
     */
48 3
    public function getXmlDocument(\DateTime $date, $rateType)
49
    {
50 3
        return $this->request('POST', array(), array(
51 3
            'index:brKursneListe:' => '',
52 3
            'index:year' => $date->format('Y'),
53 3
            'index:inputCalendar1' => $date->format('d/m/Y'),
54 3
            'index:vrsta' => call_user_func(function($rateType) {
55
                switch ($rateType) {
56 3
                    case RateType::FOREIGN_EXCHANGE_BUYING:     // FALL TROUGH
57 2
                    case RateType::FOREIGN_EXCHANGE_SELLING:
58 1
                        return 1;
59
                        // break;
60 2
                    case RateType::FOREIGN_CASH_BUYING:        // FALL TROUGH
61 1
                    case RateType::FOREIGN_CASH_SELLING:
62 1
                        return 2;
63
                        // break;
64
                    default:
65 1
                        return 3;
66
                        // break;
67
                }
68 3
            }, $rateType),
69 3
            'index:prikaz' => 3, // XML
70 3
            'index:buttonShow' => 'Show',
71 3
            'index' => 'index',
72 3
            'javax.faces.ViewState' => $this->getFormCsrfToken()
73
        ));
74
    }
75
76
    /**
77
     * Execute HTTP request and get raw body response.
78
     *
79
     * @param string $method HTTP Method.
80
     * @param array $params Params to send with request.
81
     * @return StreamInterface
82
     */
83 3
    private function request($method, array $query = array(), array $params = array())
84
    {
85 3
        $client = $this->getGuzzleClient();
86
87 3
        $response = $client->request($method, self::SOURCE, array(
88 3
            'cookies' => $this->getGuzzleCookieJar(),
89 3
            'form_params' => $params,
90 3
            'query' => $query
91
        ));
92
93 3
        return $response->getBody();
94
    }
95
96
    /**
97
     * Get NBS's form CSRF token.
98
     *
99
     * @return string CSRF token.
100
     *
101
     * @throws \RuntimeException When API is changed.
102
     */
103 3
    private function getFormCsrfToken()
104
    {
105 3
        $crawler = new Crawler($this->request('GET')->getContents());
106
107 3
        $hiddens = $crawler->filter('input[type="hidden"]');
108
109
        /**
110
         * @var \DOMElement $hidden
111
         */
112 3
        foreach ($hiddens as $hidden) {
113
114 3
            if ($hidden->getAttribute('name') === 'javax.faces.ViewState') {
115 3
                return $hidden->getAttribute('value');
116
            }
117
        }
118
119
        throw new RuntimeException('FATAL ERROR: National Bank of Serbia changed it\'s API, unable to extract token.');
120
    }
121
122
    /**
123
     * Get Guzzle Client.
124
     *
125
     * @return Client
126
     */
127 3
    private function getGuzzleClient()
128
    {
129 3
        if ($this->guzzleClient === null) {
130 3
            $this->guzzleClient = new Client(array('cookies' => true));
131
        }
132
133 3
        return $this->guzzleClient;
134
    }
135
136
    /**
137
     * Get Guzzle CookieJar.
138
     *
139
     * @return CookieJar
140
     */
141 3
    private function getGuzzleCookieJar()
142
    {
143 3
        if ($this->guzzleCookieJar === null) {
144 3
            $this->guzzleCookieJar = new CookieJar();
145
        }
146
147 3
        return $this->guzzleCookieJar;
148
    }
149
}
150