Passed
Pull Request — master (#14)
by
unknown
03:12
created

CurrencyConverterComponent::getRateToUse()   B

Complexity

Conditions 10
Paths 8

Size

Total Lines 31
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 16.8468

Importance

Changes 0
Metric Value
cc 10
eloc 18
nc 8
nop 2
dl 0
loc 31
ccs 13
cts 22
cp 0.5909
crap 16.8468
rs 7.6666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace CurrencyConverter\Controller\Component;
4
5
use Cake\Controller\Component;
6
use Cake\Datasource\ConnectionManager;
7
use Cake\ORM\TableRegistry;
8
use Cake\I18n\Time;
9
10
/**
11
 * CurrencyConverter Component to convert currency.
12
 *
13
 * Convert an amount number from one currency to an other currency
14
 * Return currency rate from one currency to an other
15
 * output type from HTML to JSON format.
16
 */
17
class CurrencyConverterComponent extends Component
18
{
19
    /**
20
     * CurrencyratesTable Object
21
     * @var \Cake\ORM\Table
22
     */
23
    private $_currencyratesTable;
24
25
    /**
26
     * Default CurrencyConverterComponent settings.
27
     *
28
     * When calling CurrencyConverterComponent() these settings will be merged with the configuration
29
     * you provide.
30
     *
31
     * - `database` - Mention if Component have to store currency rate in database
32
     * - `refresh` - Time interval for Component to refresh currency rate in database
33
     * - `decimal` - Number of decimal to use when formatting amount float number
34
     *
35
     * @var array
36
     */
37
    protected $_defaultConfig = [
38
        'database' => true, // Mention if Component have to store currency rate in database
39 8
        'refresh' => 24, // Time interval for Component to refresh currency rate in database
40
        'decimal' => 2, // Number of decimal to use when formatting amount float number
41
    ];
42
43
    /**
44
     * @param array $config
45
     * @return void
46
     */
47 8
    public function initialize(array $config = []) {
48 8
49 8
        $config = $this->getConfig();
50 8
51 8
        $this->database = $config['database'];
0 ignored issues
show
Bug Best Practice introduced by
The property database does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
52 8
        $this->refresh = $config['refresh'];
0 ignored issues
show
Bug Best Practice introduced by
The property refresh does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
53 8
        $this->decimal = $config['decimal'];
0 ignored issues
show
Bug Best Practice introduced by
The property decimal does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
54
55 8
        $this->_currencyratesTable = TableRegistry::get('CurrencyConverter.Currencyrates');
0 ignored issues
show
Deprecated Code introduced by
The function Cake\ORM\TableRegistry::get() has been deprecated: 3.6.0 Use \Cake\ORM\Locator\TableLocator::get() instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

55
        $this->_currencyratesTable = /** @scrutinizer ignore-deprecated */ TableRegistry::get('CurrencyConverter.Currencyrates');

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
56 7
    }
57
58 7
    /**
59 5
     * Convert method take an amount as first parameter and convert it using $from currency and $to currency.
60 5
     *
61
     * @param float|string $amount the amount to convert.
62 5
     * @param string $from currency to convert from
63
     * @param string $to currency to convert to
64 5
     * @return float $amount converted
65 5
     */
66
    public function convert($amount, $from, $to)
67 5
    {
68
        $amount = floatval($amount);
69
        $rate = $this->getRateToUse($from, $to);
70 2
71
        return $convert = $this->_formatConvert($rate * $amount);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $convert = $this-...onvert($rate * $amount) returns the type CurrencyConverter\Controller\Component\floatval which is incompatible with the documented return type double.
Loading history...
Unused Code introduced by
The assignment to $convert is dead and can be removed.
Loading history...
72 2
    }
73
74
    /**
75 1
     * Rate method return the rate of two currencies
76
     *
77
     * @param string $from currency to get the rate from
78 7
     * @param string $to currency to get the rate to
79
     * @return float|null $rate
80 7
     */
81 1
    public function rate($from, $to)
82 1
    {
83
        return $this->getRateToUse($from, $to);
84 7
    }
85 1
86 1
    /**
87 7
     * getRateToUse return rate to use
88
     * Using $from and $to parameters representing currency to deal with and the configuration settings
89 5
     * This method save or update currencyrates Table if necesseray too.
90
     *
91 5
     * @param string $from currency to get the rate from
92 5
     * @param string $to currency to get the rate to
93
     * @return float|null $rate
94 5
     */
95 5
    public function getRateToUse($from, $to)
96
    {
97 5
        if ($from == $to) return 1;
98 2
        if ($this->database) {
99
            // Get a currency rate from table
100 2
            $result = $this->_currencyratesTable->find('all')->where(['from_currency' => $from, 'to_currency' => $to])->first();
101 2
            // If currency rate is in table and it doesn't have to be updated
102 2
            if ($result && $result->modified->wasWithinLast($this->refresh . ' hours')) return $rate = $result->rate;
0 ignored issues
show
Bug introduced by
Accessing rate on the interface Cake\Datasource\EntityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
Unused Code introduced by
The assignment to $rate is dead and can be removed.
Loading history...
Bug introduced by
Accessing modified on the interface Cake\Datasource\EntityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
103
            // If currency rate is in table and it have to be updated
104 2
            if ($result && !$result->modified->wasWithinLast($this->refresh . ' hours')) {
105
                if ($rate = $this->_getRateFromAPI($from, $to)) {
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $rate is correct as $this->_getRateFromAPI($from, $to) targeting CurrencyConverter\Contro...nent::_getRateFromAPI() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
106
                    $result->rate = $rate;
107 2
                    $this->_currencyratesTable->save($result);
0 ignored issues
show
Bug introduced by
It seems like $result can also be of type array; however, parameter $entity of Cake\ORM\Table::save() does only seem to accept Cake\Datasource\EntityInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

107
                    $this->_currencyratesTable->save(/** @scrutinizer ignore-type */ $result);
Loading history...
108
                }
109 5
                return $rate;
110
            }
111 5
            // If currency rate isn't in table
112 3
            if (!$result) {
113 3
                if ($rate = $this->_getRateFromAPI($from, $to)) {
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $rate is correct as $this->_getRateFromAPI($from, $to) targeting CurrencyConverter\Contro...nent::_getRateFromAPI() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
114 5
                    $entity = $this->_currencyratesTable->newEntity([
115
                        'from_currency' => $from,
116
                        'to_currency' => $to,
117
                        'rate' => $rate
118
                    ]);
119
                    $this->_currencyratesTable->save($entity);
120
                }
121
                return $rate;
122
            }
123
        }
124
125
        return $this->_getRateFromAPI($from, $to);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->_getRateFromAPI($from, $to) targeting CurrencyConverter\Contro...nent::_getRateFromAPI() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
126
    }
127
128
    /**
129
     * Format float number using configuration
130
     *
131
     * @return floatval
0 ignored issues
show
Bug introduced by
The type CurrencyConverter\Controller\Component\floatval was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
132 3
     */
133
    private function _formatConvert($number)
134 3
    {
135
        return number_format($number, $this->decimal);
0 ignored issues
show
Bug Best Practice introduced by
The expression return number_format($number, $this->decimal) returns the type string which is incompatible with the documented return type CurrencyConverter\Controller\Component\floatval.
Loading history...
136
    }
137 3
138 3
    /**
139 3
     * Call free.currencyconverterapi.com API to get a rate for one currency to an other one currency
140 3
     *
141 3
     * @param string $from the currency
142 3
     * @param string $to the currency
143
     * @return int|null $rate
144 3
     */
145 3
    private function _getRateFromAPI($from, $to)
146 3
    {
147
        $rate = null;
148 2
149
        $url = 'https://free.currencyconverterapi.com/api/v5/convert?q=' . $from . '_' . $to . '&compact=ultra';
150
        $request = @fopen($url, 'r');
151 2
152 2
        if ($request) {
0 ignored issues
show
introduced by
$request is of type false|resource, thus it always evaluated to false.
Loading history...
153 2
            $response = fgets($request, 4096);
154 2
            fclose($request);
155 2
            $response = json_decode($response, true);
156 2
            if (isset($response[$from . '_' . $to])) {
157
                $rate = $response[$from . '_' . $to];
158
            }
159 5
        }
160
        
161 5
        return $rate;
162
    }
163
}