Issues (3)

src/Converter.php (2 issues)

Labels
Severity
1
<?php
2
3
declare(strict_types=1);
4
5
namespace MeepozZza\CyrillicCurrencyConverter;
6
7
class Converter
8
{
9
    protected const NULL = 'ноль';
10
11
    protected const UNITS = [
12
        ['', 'один', 'два', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь', 'девять'],
13
        ['', 'одна', 'две', 'три', 'четыре', 'пять', 'шесть', 'семь', 'восемь', 'девять'],
14
    ];
15
16
    protected const TEENS = ['десять', 'одиннадцать', 'двенадцать', 'тринадцать', 'четырнадцать', 'пятнадцать', 'шестнадцать', 'семнадцать', 'восемнадцать', 'девятнадцать'];
17
18
    protected const TENS = [2 => 'двадцать', 'тридцать', 'сорок', 'пятьдесят', 'шестьдесят', 'семьдесят', 'восемьдесят', 'девяносто'];
19
20
    protected const HUNDREDS = ['', 'сто', 'двести', 'триста', 'четыреста', 'пятьсот', 'шестьсот', 'семьсот', 'восемьсот', 'девятьсот'];
21
22
    protected const CURRENCY_UNITS = [
23
        ['копейка', 'копейки', 'копеек', 1],
24
        ['рубль', 'рубля', 'рублей', 0],
25
        ['тысяча', 'тысячи', 'тысяч', 1],
26
        ['миллион', 'миллиона', 'миллионов', 0],
27
        ['миллиард', 'милиарда', 'миллиардов', 0],
28
    ];
29
30
    public function __construct(protected bool $keepRemainderAsNumber = false)
31
    {
32
    }
33
34
    /**
35
     * Convert number to string.
36
     *
37
     * @param string|int|float $number
38
     * @return string
39
     */
40
    public function convertNumberToString(string|int|float $number): string
41
    {
42
        [$rubbles, $kopecks] = explode('.', sprintf('%015.2f', floatval($number)));
43
44
        $out = [];
45
46
        $this->convertRubbles($rubbles, $out);
47
        $this->convertKopecks($kopecks, $out);
48
49
        return trim(preg_replace('/ {2,}/', ' ', implode(' ', $out)));
50
    }
51
52
    protected function convertRubbles(string $rubbles, array &$out): void
53
    {
54
        if (intval($rubbles) > 0) {
55
            foreach (str_split($rubbles, 3) as $key => $rubble) {
56
                if (! intval($rubble)) {
57
                    continue;
58
                }
59
60
                $currencyUnitKey = count(static::CURRENCY_UNITS) - $key - 1;
61
                $gender = static::CURRENCY_UNITS[$currencyUnitKey][3];
62
                [$rubbleUnitOne, $rubbleUnitTwo, $rubbleUnitThree] = array_map('intval', str_split($rubble));
0 ignored issues
show
It seems like str_split($rubble) can also be of type true; however, parameter $array of array_map() 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

62
                [$rubbleUnitOne, $rubbleUnitTwo, $rubbleUnitThree] = array_map('intval', /** @scrutinizer ignore-type */ str_split($rubble));
Loading history...
63
                $out[] = static::HUNDREDS[$rubbleUnitOne];
64
65
                if ($rubbleUnitTwo > 1) {
66
                    $out[] = static::TENS[$rubbleUnitTwo].' '.static::UNITS[$gender][$rubbleUnitThree];
67
                } else {
68
                    $out[] = $rubbleUnitTwo > 0 ? static::TEENS[$rubbleUnitThree] : static::UNITS[$gender][$rubbleUnitThree];
69
                }
70
71
                if ($currencyUnitKey > 1) {
72
                    $out[] = $this->morphCurrencyWord((int) $rubble, $currencyUnitKey);
73
                }
74
            }
75
        } else {
76
            $out[] = static::NULL;
77
        }
78
79
        $out[] = $this->morphCurrencyWord(intval($rubbles), 1);
80
    }
81
82
    protected function convertKopecks(string $kopecks, array &$out): void
83
    {
84
        if (intval($kopecks) > 0) {
85
            foreach (str_split($kopecks, 2) as $kopeck) {
86
                if (! intval($kopeck)) {
87
                    continue;
88
                }
89
                if ($this->keepRemainderAsNumber) {
90
                    $out[] = $kopeck;
91
                } else {
92
                    $gender = static::CURRENCY_UNITS[0][3];
93
                    [$kopeckUnitOne, $kopeckUnitTwo] = array_map('intval', str_split($kopeck));
0 ignored issues
show
It seems like str_split($kopeck) can also be of type true; however, parameter $array of array_map() 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

93
                    [$kopeckUnitOne, $kopeckUnitTwo] = array_map('intval', /** @scrutinizer ignore-type */ str_split($kopeck));
Loading history...
94
                    if ($kopeckUnitOne > 1) {
95
                        $out[] = static::TENS[$kopeckUnitOne].' '.static::UNITS[$gender][$kopeckUnitTwo];
96
                    } else {
97
                        $out[] = $kopeckUnitOne > 0 ? static::TEENS[$kopeckUnitTwo] : static::UNITS[$gender][$kopeckUnitTwo];
98
                    }
99
                }
100
101
                $out[] = $this->morphCurrencyWord((int) $kopeck, 0);
102
            }
103
        } else {
104
            $out[] = $this->keepRemainderAsNumber ? '00' : static::NULL;
105
            $out[] = $this->morphCurrencyWord(0, 0);
106
        }
107
    }
108
109
    protected function morphCurrencyWord(int $number, int $currencyUnitKey): string
110
    {
111
        $number = abs($number) % 100;
112
113
        if ($number > 10 && $number < 20) {
114
            return static::CURRENCY_UNITS[$currencyUnitKey][2];
115
        }
116
117
        $number %= 10;
118
119
        if ($number > 1 && $number < 5) {
120
            return static::CURRENCY_UNITS[$currencyUnitKey][1];
121
        }
122
123
        if ($number == 1) {
124
            return static::CURRENCY_UNITS[$currencyUnitKey][0];
125
        }
126
127
        return static::CURRENCY_UNITS[$currencyUnitKey][2];
128
    }
129
}
130