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

CurrencyConverterHelper   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 141
Duplicated Lines 100 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 4
dl 141
loc 141
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A initialize() 10 10 1
A convert() 7 7 1
A rate() 4 4 1
B getRateToUse() 32 32 10
A _formatConvert() 4 4 1
A _getRateFromAPI() 19 19 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace CurrencyConverter\View\Helper;
4
5
use Cake\View\Helper;
6
use Cake\ORM\TableRegistry;
7
use Cake\I18n\Time;
8
9
/**
10
 * @property \Cake\View\Helper\HtmlHelper $Html
11
 * @property \Cake\View\Helper\FormHelper $Form
12
 * @property \Cake\View\Helper\NumberHelper $Number
13
 */
14 View Code Duplication
class CurrencyConverterHelper extends Helper
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...
15
{
16
    /**
17
     * CurrencyratesTable Object
18
     * @var \Cake\ORM\Table
19
     */
20
    private $_currencyratesTable;
21
22
    /**
23
     * Default settings
24
     *
25
     * @var array
26
     */
27
    protected $_defaultConfig = [
28
        'database' => 2, // Use database to store rate
29
        'refresh' => 24, // Time interval for refreshing rate in database
30
        'decimal' => 2, // Number of decimal to use for convert number
31
    ];
32
33
    /**
34
     * @param array $config
35
     * @return void
36
     */
37
    public function initialize(array $config = []) {
38
39
        $config = $this->getConfig();
40
41
        $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...
42
        $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...
43
        $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...
44
45
        $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...
46
    }
47
48
    /**
49
     * Convert method take an amount as first parameter and convert it using $from currency and $to currency.
50
     *
51
     * @param float|string $amount the amount to convert.
52
     * @param string $from currency to convert from
53
     * @param string $to currency to convert to
54
     * @return float $amount converted
55
     */
56
    public function convert($amount, $from, $to)
57
    {
58
        $amount = floatval($amount);
59
        $rate = $this->getRateToUse($from, $to);
60
61
        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...
62
    }
63
64
    /**
65
     * Rate method return the rate of two currencies
66
     *
67
     * @param string $from currency to get the rate from
68
     * @param string $to currency to get the rate to
69
     * @return float|null $rate
70
     */
71
    public function rate($from, $to)
72
    {
73
        return $this->getRateToUse($from, $to);
74
    }
75
76
    /**
77
     * getRateToUse return rate to use
78
     * Using $from and $to parameters representing currency to deal with and the configuration settings
79
     * This method save or update currencyrates Table if necesseray too.
80
     *
81
     * @param string $from currency to get the rate from
82
     * @param string $to currency to get the rate to
83
     * @return float|null $rate
84
     */
85
    public function getRateToUse($from, $to)
86
    {
87
        if ($from == $to) return 1;
88
        if ($this->database) {
89
            // Get a currency rate from table
90
            $result = $this->_currencyratesTable->find('all')->where(['from_currency' => $from, 'to_currency' => $to])->first();
91
            // If currency rate is in table and it doesn't have to be updated
92
            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...
93
            // If currency rate is in table and it have to be updated
94
            if ($result && !$result->modified->wasWithinLast($this->refresh . ' hours')) {
95
                if ($rate = $this->_getRateFromAPI($from, $to)) {
96
                    $result->rate = $rate;
97
                    $this->_currencyratesTable->save($result);
0 ignored issues
show
Bug introduced by
It seems like $result defined by $this->_currencyratesTab...ency' => $to))->first() on line 90 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...
98
                }
99
                return $rate;
100
            }
101
            // If currency rate isn't in table
102
            if (!$result) {
103
                if ($rate = $this->_getRateFromAPI($from, $to)) {
104
                    $entity = $this->_currencyratesTable->newEntity([
105
                        'from_currency' => $from,
106
                        'to_currency' => $to,
107
                        'rate' => $rate
108
                    ]);
109
                    $this->_currencyratesTable->save($entity);
110
                }
111
                return $rate;
112
            }
113
        }
114
115
        return $this->_getRateFromAPI($from, $to);
116
    }
117
118
    /**
119
     * Format float number using configuration
120
     *
121
     * @return floatval
122
     */
123
    private function _formatConvert($number)
124
    {
125
        return number_format($number, $this->decimal);
126
    }
127
128
    /**
129
     * Call free.currencyconverterapi.com API to get a rate for one currency to an other one currency
130
     *
131
     * @param string $from the currency
132
     * @param string $to the currency
133
     * @return int|null $rate
134
     */
135
    private function _getRateFromAPI($from, $to)
136
    {
137
        $rate = null;
138
139
        $url = 'https://free.currencyconverterapi.com/api/v5/convert?q=' . $from . '_' . $to . '&compact=ultra';
140
        $request = @fopen($url, 'r');
141
142
        if ($request) {
143
            $response = fgets($request, 4096);
144
            fclose($request);
145
146
            $response = json_decode($response, true);
147
            if (isset($response[$from . '_' . $to])) {
148
                $rate = $response[$from . '_' . $to];
149
            }
150
        }
151
        
152
        return $rate;
153
    }
154
}