Test Failed
Pull Request — master (#140)
by Jordan
18:33
created

NumberFormatProvider::addDelimiter()   B

Complexity

Conditions 11
Paths 7

Size

Total Lines 29
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
dl 0
loc 29
rs 7.3166
c 0
b 0
f 0
eloc 15
nc 7
nop 3

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 Samsara\Fermat\Core\Provider;
4
5
use Samsara\Fermat\Core\Enums\Currency;
6
use Samsara\Fermat\Core\Enums\NumberFormat;
7
use Samsara\Fermat\Core\Enums\NumberGrouping;
8
9
/**
10
 *
11
 */
12
class NumberFormatProvider
13
{
14
15
    /**
16
     * @param string $number
17
     * @param Currency $currency
18
     * @param NumberFormat|null $format
19
     * @param NumberGrouping|null $grouping
20
     * @return string
21
     */
22
    public static function formatCurrency(
23
        string $number,
24
        Currency $currency,
25
        ?NumberFormat $format = null,
26
        ?NumberGrouping $grouping = null
27
    ): string
28
    {
29
        $number = self::formatNumber($number, $format, $grouping);
30
31
        if (str_starts_with($number, '(') || str_starts_with($number, '-') || str_starts_with($number, '+')) {
32
            $number = str_replace('(', '('.$currency->value, $number);
33
            $number = str_replace('-', '-'.$currency->value, $number);
34
            $number = str_replace('+', '+'.$currency->value, $number);
35
        } else {
36
            $number = $currency->value . $number;
37
        }
38
39
        return $number;
40
    }
41
42
    /**
43
     * @param string $number
44
     * @param NumberFormat|null $format
45
     * @param NumberGrouping|null $grouping
46
     * @return string
47
     */
48
    public static function formatNumber(
49
        string $number,
50
        ?NumberFormat $format = null,
51
        ?NumberGrouping $grouping = null
52
    ): string
53
    {
54
        $posNegChar = '';
55
56
        if (!is_null($format)) {
57
            $negative = str_starts_with($number, '-');
58
            $number = str_replace('-', '', $number);
59
            if (str_contains($number, '.')) {
60
                [$wholePart, $decimalPart] = explode('.', $number);
61
            } else {
62
                $wholePart = $number;
63
                $decimalPart = '';
64
            }
65
            if (!is_null($grouping)) {
66
                $wholePart = self::addDelimiter($wholePart, $format, $grouping);
67
            }
68
69
            $posNegChar = $negative ? self::getNegativeCharacter($format) : self::getPositiveCharacter($format);
70
71
            $number = $wholePart;
72
73
            if ($decimalPart) {
74
                $number .= self::getRadixCharacter($format) . $decimalPart;
75
            }
76
        }
77
78
        if (str_contains($posNegChar, '\N')) {
79
            $number = str_replace('\N', $number, $posNegChar);
80
        } else {
81
            $number = $posNegChar . $number;
82
        }
83
84
        return $number;
85
    }
86
87
    /**
88
     * @param string $number
89
     * @return string
90
     */
91
    public static function formatScientific(string $number): string
92
    {
93
        $negative = str_starts_with($number, '-') ? '-' : '';
94
        $imaginary = str_ends_with($number, 'i') ? 'i' : '';
95
        $number = str_replace('-', '', $number);
96
        $number = str_replace('i', '', $number);
97
        if (str_contains($number, '.')) {
98
            [$wholePart, $decimalPart] = explode('.', $number);
99
        } else {
100
            $wholePart = $number;
101
            $decimalPart = '';
102
        }
103
104
        $wholeSizeNonZero = strlen(ltrim($wholePart, '0'));
105
        $decimalSizeNonZero = strlen(ltrim($decimalPart, '0'));
106
107
        if ($wholeSizeNonZero) {
108
            $exponent = $wholeSizeNonZero;
109
            $exponent -= 1;
110
            $mantissa = substr($wholePart, 0, 1) . '.' . substr($wholePart, 1) . $decimalPart;
111
        } else {
112
            $exponent = strlen($decimalPart) - $decimalSizeNonZero;
113
            $exponent += 1;
114
            $mantissa = substr($decimalPart, $exponent-1, 1) . '.' . substr($decimalPart, $exponent);
115
            $exponent *= -1;
116
        }
117
118
        $mantissa = rtrim($mantissa, '0');
119
120
        return $negative . $mantissa . 'E' . $exponent . $imaginary;
121
    }
122
123
    /**
124
     * @param string $number
125
     * @param NumberFormat $format
126
     * @param NumberGrouping $grouping
127
     * @return string
128
     */
129
    public static function addDelimiter(
130
        string $number,
131
        NumberFormat $format = NumberFormat::English,
132
        NumberGrouping $grouping = NumberGrouping::Standard
133
    ): string
134
    {
135
        $numberArr = str_split($number);
136
        $numberArr = array_reverse($numberArr);
0 ignored issues
show
Bug introduced by
It seems like $numberArr can also be of type true; however, parameter $array of array_reverse() does only seem to accept array, 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

136
        $numberArr = array_reverse(/** @scrutinizer ignore-type */ $numberArr);
Loading history...
137
        $formatted = '';
138
139
        for ($i = 0;$i < count($numberArr);$i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
140
            $j = $i + 1;
141
142
            $formatted = $numberArr[$i].$formatted;
143
144
            if ($grouping == NumberGrouping::Standard) {
145
                if ($j % 3 == 0 && array_key_exists($i+1, $numberArr)) {
146
                    $formatted = self::getDelimiterCharacter($format).$formatted;
147
                }
148
            } elseif ($grouping == NumberGrouping::Indian) {
149
                if ($j == 3 && array_key_exists($i+1, $numberArr)) {
150
                    $formatted = self::getDelimiterCharacter($format).$formatted;
151
                } elseif (($j - 3) % 2 == 0 && ($j - 3) > 0 && array_key_exists($i+1, $numberArr)) {
152
                    $formatted = self::getDelimiterCharacter($format).$formatted;
153
                }
154
            }
155
        }
156
157
        return $formatted;
158
    }
159
160
    /**
161
     * @param NumberFormat $format
162
     * @return string
163
     */
164
    public static function getPositiveCharacter(NumberFormat $format): string
165
    {
166
        return match ($format) {
167
            NumberFormat::EnglishFinance,
168
            NumberFormat::EuropeanFinance,
169
            NumberFormat::TechnicalFinance => '+',
170
            default => ''
171
        };
172
    }
173
174
    /**
175
     * @param NumberFormat $format
176
     * @return string
177
     */
178
    public static function getNegativeCharacter(NumberFormat $format): string
179
    {
180
        return match ($format) {
181
            NumberFormat::EnglishFinance,
182
            NumberFormat::EuropeanFinance,
183
            NumberFormat::TechnicalFinance => '(\N)',
184
            default => '-',
185
        };
186
    }
187
188
    /**
189
     * @param NumberFormat $format
190
     * @return string
191
     */
192
    public static function getRadixCharacter(NumberFormat $format): string
193
    {
194
        return match ($format) {
195
            NumberFormat::EuropeanFinance,
196
            NumberFormat::European => ',',
197
            default => '.'
198
        };
199
    }
200
201
    /**
202
     * @param NumberFormat $format
203
     * @return string
204
     */
205
    public static function getDelimiterCharacter(NumberFormat $format): string
206
    {
207
        return match ($format) {
208
            NumberFormat::EnglishFinance,
209
            NumberFormat::English => ',',
210
            NumberFormat::EuropeanFinance,
211
            NumberFormat::European => '.',
212
            NumberFormat::TechnicalFinance,
213
            NumberFormat::Technical => ' ',
214
        };
215
    }
216
217
}