Completed
Push — master ( f49bd8...7f7e0b )
by
unknown
02:39
created

NationalBankOfSerbiaDomCrawlerSource::load()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 11
ccs 0
cts 0
cp 0
rs 9.4286
cc 1
eloc 6
nc 1
nop 1
crap 2
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 {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if 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.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
52
            // Baciti exception.
53
        }
54
55
    }
56
57 View Code Duplication
    protected function validateRateType($rateType)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
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;
0 ignored issues
show
Unused Code introduced by
$jar is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
102
        $client = new GoutteClient();
103
        $client->setClient($guzzleClient);
104
105
        $crawler = $this->getCrawler($date);
0 ignored issues
show
Unused Code introduced by
$crawler is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
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;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
138
                    case 'foreign_exchange_buying':     // FALL TROUGH
139
                    case 'foreign_exchange_selling':
140
                        return 2;
141
                        break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
142
                    default:
143
                        return 3;
144
                        break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
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