NbsBrowser   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 119
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 100%

Importance

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

5 Methods

Rating   Name   Duplication   Size   Complexity  
A getXmlDocument() 0 24 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 = 'https://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:yearInner' => $date->format('Y'),
53 3
            'index:inputCalendar1' => $date->format('d/m/Y'),
54 3
            'index:vrstaInner' => 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 2
                    case RateType::FOREIGN_CASH_BUYING:        // FALL TROUGH
60 1
                    case RateType::FOREIGN_CASH_SELLING:
61 1
                        return 2;
62
                    default:
63 1
                        return 3;
64
                }
65 3
            }, $rateType),
66 3
            'index:prikazInner' => 3, // XML
67 3
            'index:buttonShow' => 'Show',
68 3
            'index' => 'index',
69 3
            'javax.faces.ViewState' => $this->getFormCsrfToken(),
70
        ));
71
    }
72
73
    /**
74
     * Execute HTTP request and get raw body response.
75
     *
76
     * @param string $method HTTP Method.
77
     * @param array $params Params to send with request.
78
     * @return StreamInterface
79
     */
80 3
    private function request($method, array $query = array(), array $params = array())
81
    {
82 3
        $client = $this->getGuzzleClient();
83
84 3
        $response = $client->request($method, self::SOURCE, array(
85 3
            'cookies' => $this->getGuzzleCookieJar(),
86 3
            'form_params' => $params,
87 3
            'query' => $query,
88
        ));
89
90 3
        return $response->getBody();
91
    }
92
93
    /**
94
     * Get NBS's form CSRF token.
95
     *
96
     * @return string CSRF token.
97
     *
98
     * @throws \RuntimeException When API is changed.
99
     */
100 3
    private function getFormCsrfToken()
101
    {
102 3
        $crawler = new Crawler($this->request('GET')->getContents());
103
104 3
        $hiddens = $crawler->filter('input[type="hidden"]');
105
106
        /**
107
         * @var \DOMElement $hidden
108
         */
109 3
        foreach ($hiddens as $hidden) {
110
111 3
            if ($hidden->getAttribute('name') === 'javax.faces.ViewState') {
112 3
                return $hidden->getAttribute('value');
113
            }
114
        }
115
116
        throw new RuntimeException('FATAL ERROR: National Bank of Serbia changed it\'s API, unable to extract token.'); // @codeCoverageIgnore
117
    }
118
119
    /**
120
     * Get Guzzle Client.
121
     *
122
     * @return Client
123
     */
124 3
    private function getGuzzleClient()
125
    {
126 3
        if ($this->guzzleClient === null) {
127 3
            $this->guzzleClient = new Client(array('cookies' => true));
128
        }
129
130 3
        return $this->guzzleClient;
131
    }
132
133
    /**
134
     * Get Guzzle CookieJar.
135
     *
136
     * @return CookieJar
137
     */
138 3
    private function getGuzzleCookieJar()
139
    {
140 3
        if ($this->guzzleCookieJar === null) {
141 3
            $this->guzzleCookieJar = new CookieJar();
142
        }
143
144 3
        return $this->guzzleCookieJar;
145
    }
146
}
147