Test Failed
Pull Request — master (#14)
by
unknown
13:32
created

CurrencyConverterComponent::getRateToUse()   B

Complexity

Conditions 10
Paths 8

Size

Total Lines 32

Duplication

Lines 32
Ratio 100 %

Code Coverage

Tests 13
CRAP Score 16.8468

Importance

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

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 View Code Duplication
class CurrencyConverterComponent extends Component
0 ignored issues
show
Duplication introduced by
This class 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...
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 introduced by
The property database does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
52 8
        $this->refresh = $config['refresh'];
0 ignored issues
show
Bug introduced by
The property refresh does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
53 8
        $this->decimal = $config['decimal'];
0 ignored issues
show
Bug introduced by
The property decimal does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
54
55 8
        $this->_currencyratesTable = TableRegistry::get('CurrencyConverter.Currencyrates');
0 ignored issues
show
Deprecated Code introduced by
The method Cake\ORM\TableRegistry::get() has been deprecated with message: 3.6.0 Use \Cake\ORM\Locator\TableLocator::get() instead.

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

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class 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
Unused Code introduced by
$convert 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...
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
Unused Code introduced by
$rate 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...
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)) {
106
                    $result->rate = $rate;
107 2
                    $this->_currencyratesTable->save($result);
0 ignored issues
show
Bug introduced by
It seems like $result defined by $this->_currencyratesTab...ency' => $to))->first() on line 100 can also be of type array; however, Cake\ORM\Table::save() does only seem to accept object<Cake\Datasource\EntityInterface>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

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)) {
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);
126
    }
127
128
    /**
129
     * Format float number using configuration
130
     *
131
     * @return floatval
132 3
     */
133
    private function _formatConvert($number)
134 3
    {
135
        return number_format($number, $this->decimal);
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) {
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
}