Completed
Push — master ( 4db325...96560a )
by Simonas
8s
created

CurrencyRatesService::getCurrentDate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 5
ccs 0
cts 0
cp 0
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
crap 2
1
<?php
2
3
/*
4
 * This file is part of the ONGR package.
5
 *
6
 * (c) NFQ Technologies UAB <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ONGR\CurrencyExchangeBundle\Service;
13
14
use Elasticsearch\Common\Exceptions\Missing404Exception;
15
use ONGR\CurrencyExchangeBundle\Document\CurrencyDocument;
16
use ONGR\CurrencyExchangeBundle\Document\RatesObject;
17
use ONGR\CurrencyExchangeBundle\Driver\CurrencyDriverInterface;
18
use ONGR\CurrencyExchangeBundle\Exception\RatesNotLoadedException;
19
use ONGR\ElasticsearchBundle\Result\Result;
20
use ONGR\ElasticsearchDSL\Query\MatchAllQuery;
21
use ONGR\ElasticsearchDSL\Query\MatchQuery;
22
use ONGR\ElasticsearchDSL\Query\RangeQuery;
23
use ONGR\ElasticsearchDSL\Sort\FieldSort;
24
use ONGR\ElasticsearchBundle\Service\Manager;
25
use Psr\Log\LoggerAwareTrait;
26
use Stash\Interfaces\ItemInterface;
27
use Stash\Interfaces\PoolInterface;
28
use Symfony\Component\Validator\Constraints\DateTime;
29
30
/**
31
 * This class provides currency rates.
32
 */
33
class CurrencyRatesService
34
{
35
    use LoggerAwareTrait;
36
37
    /**
38
     * @var null|array
39
     */
40
    public $rates = null;
41
42
    /**
43
     * @var CurrencyDriverInterface
44
     */
45
    private $driver;
46
47
    /**
48
     * @var PoolInterface
49
     */
50
    private $pool;
51
52
    /**
53
     * @var Manager
54
     */
55
    private $manager;
56
57
    /**
58
     * @param CurrencyDriverInterface $driver  Currency exchange driver.
59
     * @param Manager                 $manager ES Manager.
60 5
     * @param PoolInterface           $pool    Cache pool.
61
     */
62
    public function __construct(
63
        CurrencyDriverInterface $driver,
64
        Manager $manager,
65 5
        PoolInterface $pool
66 5
    ) {
67 5
        $this->driver = $driver;
68 5
        $this->manager = $manager;
69
        $this->pool = $pool;
70
    }
71
72
    /**
73
     * This method returns exchange rates.
74
     *
75
     * @param string|null $date
76 4
     *
77
     * @throws RatesNotLoadedException
78 4
     * @return array
79 3
     */
80
    public function getRates($date = null)
81
    {
82 4
        $date = $date ? $date : $this->getCurrentDate();
83 4
84 4
        if (isset($this->rates[$date])) {
85 1
            return $this->rates[$date];
86
        }
87
88 3
        $item = $this->getCachedRates();
89 3
        $this->rates = $item->get();
90
        if (isset($this->rates[$date])) {
91
            return $this->rates[$date];
92
        }
93 3
94 3
        $this->rates = $this->getRatesFromBackup($date);
95 2
        if (isset($this->rates[$date])) {
96
            return $this->rates[$date];
97 1
        } elseif ($date != $this->getCurrentDate()) {
98
            throw new RatesNotLoadedException(
99
                'Currency rates for '.$date.' are not loaded and could not be loaded on demand'
100
            );
101
        }
102
103
        $this->reloadRates();
104
        if (isset($this->rates[$date])) {
105 3
            return $this->rates[$date];
106
        }
107 3
        throw new RatesNotLoadedException(
108 3
            'Currency rates for '.$date.' are not loaded and could not be loaded on demand'
109 3
        );
110 3
    }
111 3
112 3
    /**
113 3
     * Returns currency rates from ES.
114
     *
115 3
     * @param string|null $date
116 3
     *
117 1
     * @return array
118
     */
119 1
    private function getRatesFromBackup($date = null)
120
    {
121
        $date = $date ? $date : $this->getCurrentDate();
122 2
        $rates = [];
123
        $currency = $this->getCurrencyFromEs($date);
124
125
        if (!empty($currency)) {
126
            foreach ($currency['rates'] as $data) {
127
                $rates[$data['name']] = $data['value'];
128
            }
129
            $this->logger && $this->logger->notice('Rates returned from ES. Cache updated.');
130
            $this->updateRatesCache($rates, new \DateTime($currency['created_at']));
131
132 2
            return [$date => $rates];
133
        }
134
135
        return null;
136
    }
137
138
    /**
139
     * Update rates in cache.
140 2
     *
141
     * @param array     $rates
142 2
     * @param \DateTime $createdAt
143 2
     */
144
    private function updateRatesCache($rates, \DateTime $createdAt = null)
145
    {
146
        $createdAt = $createdAt ? $createdAt : new \DateTime();
147
        $cache = [
148 4
            $createdAt->format('Y-m-d') => $rates
149
        ];
150 4
        $this->getCachedRates()->set($cache);
151
    }
152
153
    /**
154
     * @return ItemInterface
155
     */
156
    private function getCachedRates()
157
    {
158 3
        return $this->pool->getItem('ongr_currency');
0 ignored issues
show
Unused Code introduced by
The call to PoolInterface::getItem() has too many arguments starting with 'ongr_currency'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
159
    }
160 3
161 3
    /**
162
     * Reloads rates using given driver.
163
     *
164 3
     * @return array
165 3
     */
166
    public function reloadRates()
167 3
    {
168 2
        $date = $this->getCurrentDate();
169 2
170 2
        $esCurrency = $this->getCurrencyFromEs($date);
171 2
        if (!empty($esCurrency)) {
172 2
            $this->rates = [
173 2
                $date => $esCurrency['rates']
174 2
            ];
175 2
            return $this->rates;
176 2
        }
177 2
178
        $rates = $this->driver->getRates();
179 2
180
        if ($rates) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $rates of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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.

Loading history...
181 1
            $this->rates = [
182
                $date => $rates
183 1
            ];
184
        }
185
186
        /** @var CurrencyDocument $document */
187
        $document = new CurrencyDocument();
188
        
189
        if ($this->rates[$date]) {
190
            foreach ($this->rates[$date] as $name => $value) {
191 2
                $ratesObject = new RatesObject();
192
                $ratesObject->setName($name);
193 2
                $ratesObject->setValue($value);
194
                $document->addRate($ratesObject);
195
            }
196
            $this->manager->persist($document);
197
            $this->manager->commit();
198
            $this->updateRatesCache($this->rates, $document->getCreatedAt());
199
200
            return $this->rates;
201
        }
202
        $this->logger && $this->logger->notice('Failed to retrieve currency rates from provider.');
203
204
        return null;
205
    }
206
207
    /**
208
     * Returns actual base currency name.
209
     *
210
     * @return string
211
     */
212
    public function getBaseCurrency()
213
    {
214
        return $this->driver->getBaseCurrency();
215
    }
216
217
    /**
218
     * Returns formatted current date
219
     *
220
     * @returns string
221
     */
222
    private function getCurrentDate()
223
    {
224
        $now = new \DateTime();
225
        return $now->format('Y-m-d');
226
    }
227
228
    /**
229
     * Returns an array representing a currency for a specific date from ES
230
     *
231
     * @param string $date
232
     *
233
     * @returns array
234
     */
235
    private function getCurrencyFromEs($date)
236
    {
237
        $repository = $this->manager->getRepository('ONGRCurrencyExchangeBundle:CurrencyDocument');
238
        $search = $repository->createSearch();
239
        $search->addQuery(
240
            new MatchQuery('date', $date)
241
        );
242
        $search->setSize(1);
243
        try {
244
            $results = $repository->execute($search, Result::RESULTS_ARRAY);
245
        } catch (Missing404Exception $e) {
246
            $this->logger && $this->logger->notice('Failed to execute query. Please check ES configuration');
247
248
            return null;
249
        }
250
251
        return count($results) > 0 ? $results[0] : [];
252
    }
253
}
254