Completed
Pull Request — master (#54)
by
unknown
02:40
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\RangeQuery;
22
use ONGR\ElasticsearchDSL\Sort\FieldSort;
23
use ONGR\ElasticsearchBundle\Service\Manager;
24
use Psr\Log\LoggerAwareTrait;
25
use Stash\Interfaces\ItemInterface;
26
use Stash\Interfaces\PoolInterface;
27
use Symfony\Component\Validator\Constraints\DateTime;
28
29
/**
30
 * This class provides currency rates.
31
 */
32
class CurrencyRatesService
33
{
34
    use LoggerAwareTrait;
35
36
    /**
37
     * @var null|array
38
     */
39
    public $rates = null;
40
41
    /**
42
     * @var CurrencyDriverInterface
43
     */
44
    private $driver;
45
46
    /**
47
     * @var PoolInterface
48
     */
49
    private $pool;
50
51
    /**
52
     * @var Manager
53
     */
54
    private $manager;
55
56
    /**
57
     * @param CurrencyDriverInterface $driver  Currency exchange driver.
58
     * @param Manager                 $manager ES Manager.
59
     * @param PoolInterface           $pool    Cache pool.
60 5
     */
61
    public function __construct(
62
        CurrencyDriverInterface $driver,
63
        Manager $manager,
64
        PoolInterface $pool
65 5
    ) {
66 5
        $this->driver = $driver;
67 5
        $this->manager = $manager;
68 5
        $this->pool = $pool;
69
    }
70
71
    /**
72
     * This method returns exchange rates.
73
     *
74
     * @param string $date
75
     *
76 4
     * @throws RatesNotLoadedException
77
     * @return array
78 4
     */
79 3
    public function getRates($date = '')
80
    {
81
        $date = $date == '' ? $this->getCurrentDate() : $date;
82 4
83 4
        if (isset($this->rates[$date])) {
84 4
            return $this->rates[$date];
85 1
        }
86
87
        $item = $this->getCachedRates();
88 3
        $this->rates = $item->get();
89 3
        if (isset($this->rates[$date])) {
90
            return $this->rates[$date];
91
        }
92
93 3
        $this->rates = $this->getRatesFromBackup($date);
94 3
        if (isset($this->rates[$date])) {
95 2
            return $this->rates[$date];
96
        } elseif ($date != $this->getCurrentDate()) {
97 1
            throw new RatesNotLoadedException('Currency rates for '.$date.' are not loaded and could not be loaded on demand');
98
        }
99
100
        $this->reloadRates();
101
        if (isset($this->rates[$date])) {
102
            return $this->rates[$date];
103
        }
104
        throw new RatesNotLoadedException('Currency rates for '.$date.' are not loaded and could not be loaded on demand');
105 3
    }
106
107 3
    /**
108 3
     * Returns currency rates from ES.
109 3
     *
110 3
     * @param string $date
111 3
     *
112 3
     * @return array
113 3
     */
114
    private function getRatesFromBackup($date = '')
115 3
    {
116 3
        $date = $date == '' ? $this->getCurrentDate() : $date;
117 1
        $rates = [];
118
        $repository = $this->manager->getRepository('ONGRCurrencyExchangeBundle:CurrencyDocument');
119 1
        $search = $repository->createSearch();
120
        $search->addFilter(
121
            new RangeQuery(
122 2
                'created_at',
123
                [
124
                    'gte' => $date.'T00:00:00',
125
                    'lte'   => $date.'T23:59:59',
126
                ]
127
            )
128
        );
129
        $search->setSize(1);
130
        try {
131
            $results = $repository->execute($search, Result::RESULTS_ARRAY);
132 2
        } catch (Missing404Exception $e) {
133
            $this->logger && $this->logger->notice('Failed to execute query. Please check ES configuration');
134
135
            return null;
136
        }
137
138
        if (count($results)) {
139
            foreach ($results[0]['rates'] as $data) {
140 2
                $rates[$data['name']] = $data['value'];
141
            }
142 2
            $this->logger && $this->logger->notice('Rates returned from ES. Cache updated.');
143 2
            $this->updateRatesCache($rates, new \DateTime($results[0]['created_at']));
144
145
            return [$date => $rates];
146
        }
147
148 4
        return null;
149
    }
150 4
151
    /**
152
     * Update rates in cache.
153
     *
154
     * @param array     $rates
155
     * @param \DateTime $createdAt
156
     */
157
    private function updateRatesCache($rates, \DateTime $createdAt = null)
158 3
    {
159
        $createdAt = $createdAt ? $createdAt : new \DateTime();
160 3
        $cache = [
161 3
            $createdAt->format('Y-m-d') => $rates
162
        ];
163
        $this->getCachedRates()->set($cache);
164 3
    }
165 3
166
    /**
167 3
     * @return ItemInterface
168 2
     */
169 2
    private function getCachedRates()
170 2
    {
171 2
        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...
172 2
    }
173 2
174 2
    /**
175 2
     * Reloads rates using given driver.
176 2
     *
177 2
     * @return array
178
     */
179 2
    public function reloadRates()
180
    {
181 1
        $date = $this->getCurrentDate();
182
        $rates = $this->driver->getRates();
183 1
184
        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...
185
            $this->rates = [
186
                $date => $rates
187
            ];
188
        }
189
190
        /** @var CurrencyDocument $document */
191 2
        $document = new CurrencyDocument();
192
        
193 2
        if ($this->rates[$date]) {
194
            foreach ($this->rates[$date] as $name => $value) {
195
                $ratesObject = new RatesObject();
196
                $ratesObject->setName($name);
197
                $ratesObject->setValue($value);
198
                $document->addRate($ratesObject);
199
            }
200
            $this->manager->persist($document);
201
            $this->manager->commit();
202
            $this->updateRatesCache($this->rates, $document->getCreatedAt());
203
204
            return $this->rates;
205
        }
206
        $this->logger && $this->logger->notice('Failed to retrieve currency rates from provider.');
207
208
        return null;
209
    }
210
211
    /**
212
     * Returns actual base currency name.
213
     *
214
     * @return string
215
     */
216
    public function getBaseCurrency()
217
    {
218
        return $this->driver->getBaseCurrency();
219
    }
220
221
    /**
222
     * Returns formatted current date
223
     *
224
     * @returns string
225
     */
226
    private function getCurrentDate()
227
    {
228
        $now = new \DateTime();
229
        return $now->format('Y-m-d');
230
    }
231
}
232