Completed
Push — master ( 622740...e78b73 )
by f
01:58
created

src/Russian/CardinalNumeralGenerator.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
namespace morphos\Russian;
3
4
use morphos\NumeralGenerator;
5
use morphos\S;
6
7
/**
8
 * Rules are from http://www.fio.ru/pravila/grammatika/sklonenie-imen-chislitelnykh/
9
 */
10
class CardinalNumeralGenerator extends NumeralGenerator implements Cases
11
{
12
    use RussianLanguage, CasesHelper;
13
14
    protected static $words = [
15
        1 => 'один',
16
        2 => 'два',
17
        3 => 'три',
18
        4 => 'четыре',
19
        5 => 'пять',
20
        6 => 'шесть',
21
        7 => 'семь',
22
        8 => 'восемь',
23
        9 => 'девять',
24
        10 => 'десять',
25
        11 => 'одиннадцать',
26
        12 => 'двенадцать',
27
        13 => 'тринадцать',
28
        14 => 'четырнадцать',
29
        15 => 'пятнадцать',
30
        16 => 'шестнадцать',
31
        17 => 'семнадцать',
32
        18 => 'восемнадцать',
33
        19 => 'девятнадцать',
34
        20 => 'двадцать',
35
        30 => 'тридцать',
36
        40 => 'сорок',
37
        50 => 'пятьдесят',
38
        60 => 'шестьдесят',
39
        70 => 'семьдесят',
40
        80 => 'восемьдесят',
41
        90 => 'девяносто',
42
        100 => 'сто',
43
        200 => 'двести',
44
        300 => 'триста',
45
        400 => 'четыреста',
46
        500 => 'пятьсот',
47
        600 => 'шестьсот',
48
        700 => 'семьсот',
49
        800 => 'восемьсот',
50
        900 => 'девятьсот',
51
    ];
52
53
    protected static $exponents = [
54
        '1000' => 'тысяча',
55
        '1000000' => 'миллион',
56
        '1000000000' => 'миллиард',
57
        '1000000000000' => 'триллион',
58
        '1000000000000000' => 'квадриллион',
59
    ];
60
61
    protected static $precalculated = [
62
        'один' => [
63
            self::MALE => [
64
                self::IMENIT => 'один',
65
                self::RODIT => 'одного',
66
                self::DAT => 'одному',
67
                self::VINIT => 'один',
68
                self::TVORIT => 'одним',
69
                self::PREDLOJ => 'одном',
70
            ],
71
            self::FEMALE => [
72
                self::IMENIT => 'одна',
73
                self::RODIT => 'одной',
74
                self::DAT => 'одной',
75
                self::VINIT => 'одну',
76
                self::TVORIT => 'одной',
77
                self::PREDLOJ => 'одной',
78
            ],
79
            self::NEUTER => [
80
                self::IMENIT => 'одно',
81
                self::RODIT => 'одного',
82
                self::DAT => 'одному',
83
                self::VINIT => 'одно',
84
                self::TVORIT => 'одним',
85
                self::PREDLOJ => 'одном',
86
            ],
87
        ],
88
        'два' => [
89
            self::MALE => [
90
                self::IMENIT => 'два',
91
                self::RODIT => 'двух',
92
                self::DAT => 'двум',
93
                self::VINIT => 'два',
94
                self::TVORIT => 'двумя',
95
                self::PREDLOJ => 'двух',
96
            ],
97
            self::FEMALE => [
98
                self::IMENIT => 'две',
99
                self::RODIT => 'двух',
100
                self::DAT => 'двум',
101
                self::VINIT => 'две',
102
                self::TVORIT => 'двумя',
103
                self::PREDLOJ => 'двух',
104
            ],
105
            self::NEUTER => [
106
                self::IMENIT => 'два',
107
                self::RODIT => 'двух',
108
                self::DAT => 'двум',
109
                self::VINIT => 'два',
110
                self::TVORIT => 'двумя',
111
                self::PREDLOJ => 'двух',
112
            ],
113
        ],
114
        'три' => [
115
            self::IMENIT => 'три',
116
            self::RODIT => 'трех',
117
            self::DAT => 'трем',
118
            self::VINIT => 'три',
119
            self::TVORIT => 'тремя',
120
            self::PREDLOJ => 'трех',
121
        ],
122
        'четыре' => [
123
            self::IMENIT => 'четыре',
124
            self::RODIT => 'четырех',
125
            self::DAT => 'четырем',
126
            self::VINIT => 'четыре',
127
            self::TVORIT => 'четырьмя',
128
            self::PREDLOJ => 'четырех',
129
        ],
130
        'двести' => [
131
            self::IMENIT => 'двести',
132
            self::RODIT => 'двухсот',
133
            self::DAT => 'двумстам',
134
            self::VINIT => 'двести',
135
            self::TVORIT => 'двумястами',
136
            self::PREDLOJ => 'двухстах',
137
        ],
138
        'восемьсот' => [
139
            self::IMENIT => 'восемьсот',
140
            self::RODIT => 'восьмисот',
141
            self::DAT => 'восьмистам',
142
            self::VINIT => 'восемьсот',
143
            self::TVORIT => 'восьмистами',
144
            self::PREDLOJ => 'восьмистах',
145
        ],
146
        'тысяча' => [
147
            self::IMENIT => 'тысяча',
148
            self::RODIT => 'тысяч',
149
            self::DAT => 'тысячам',
150
            self::VINIT => 'тысяч',
151
            self::TVORIT => 'тысячей',
152
            self::PREDLOJ => 'тысячах',
153
        ],
154
    ];
155
156
    /**
157
     * @param $number
158
     * @param string $gender
159
     * @return array
160
     * @throws \Exception
161
     */
162 31
    public static function getCases($number, $gender = self::MALE)
163
    {
164
        // simple numeral
165 31
        if (isset(self::$words[$number]) || isset(self::$exponents[$number])) {
166 31
            $word = isset(self::$words[$number]) ? self::$words[$number] : self::$exponents[$number];
167 31
            if (isset(self::$precalculated[$word])) {
168 19
                if (isset(self::$precalculated[$word][self::MALE])) {
169 9
                    return self::$precalculated[$word][$gender];
170
                } else {
171 16
                    return self::$precalculated[$word];
172
                }
173 22
            } elseif (($number >= 5 && $number <= 20) || $number == 30) {
174 12
                $prefix = S::slice($word, 0, -1);
175
                return [
176 12
                    self::IMENIT => $word,
177 12
                    self::RODIT => $prefix.'и',
178 12
                    self::DAT => $prefix.'и',
179 12
                    self::VINIT => $word,
180 12
                    self::TVORIT => $prefix.'ью',
181 12
                    self::PREDLOJ => $prefix.'и',
182
                ];
183 19
            } elseif (in_array($number, [40, 90, 100])) {
184 10
                $prefix = $number == 40 ? $word : S::slice($word, 0, -1);
185
                return [
186 10
                    self::IMENIT => $word,
187 10
                    self::RODIT => $prefix.'а',
188 10
                    self::DAT => $prefix.'а',
189 10
                    self::VINIT => $word,
190 10
                    self::TVORIT => $prefix.'а',
191 10
                    self::PREDLOJ => $prefix.'а',
192
                ];
193 16
            } elseif (($number >= 50 && $number <= 80)) {
194 8
                $prefix = S::slice($word, 0, -6);
195
                return [
196 8
                    self::IMENIT => $prefix.'ьдесят',
197 8
                    self::RODIT => $prefix.'идесяти',
198 8
                    self::DAT => $prefix.'идесяти',
199 8
                    self::VINIT => $prefix.'ьдесят',
200 8
                    self::TVORIT => $prefix.'ьюдесятью',
201 8
                    self::PREDLOJ => $prefix.'идесяти',
202
                ];
203 16
            } elseif (in_array($number, [300, 400])) {
204 5
                $prefix = S::slice($word, 0, -4);
205
                return [
206 5
                    self::IMENIT => $word,
207 5
                    self::RODIT => $prefix.'ехсот',
208 5
                    self::DAT => $prefix.'емстам',
209 5
                    self::VINIT => $word,
210 5
                    self::TVORIT => $prefix.($number == 300 ? 'е' : 'ь').'мястами',
211 5
                    self::PREDLOJ => $prefix.'ехстах',
212
                ];
213 11
            } elseif ($number >= 500 && $number <= 900) {
214 9
                $prefix = S::slice($word, 0, -4);
215
                return [
216 9
                    self::IMENIT => $word,
217 9
                    self::RODIT => $prefix.'исот',
218 9
                    self::DAT => $prefix.'истам',
219 9
                    self::VINIT => $word,
220 9
                    self::TVORIT => $prefix.'ьюстами',
221 9
                    self::PREDLOJ => $prefix.'истах',
222
                ];
223 2
            } elseif (isset(self::$exponents[$number])) {
224 2
                return NounDeclension::getCases($word, false);
225
            }
226 19
        } elseif ($number == 0) {
227
            return [
228
                self::IMENIT => 'ноль',
229
                self::RODIT => 'ноля',
230
                self::DAT => 'нолю',
231
                self::VINIT => 'ноль',
232
                self::TVORIT => 'нолём',
233
                self::PREDLOJ => 'ноле',
234
            ];
235
        }
236
        // compound numeral
237
        else {
238 19
            $parts = [];
239 19
            $result = [];
240
241 19
            foreach (array_reverse(self::$exponents, true) as $word_number => $word) {
242 19
                if ($number >= $word_number) {
243 12
                    $count = floor($number / $word_number);
244 12
                    $parts[] = self::getCases($count, ($word_number == 1000 ? self::FEMALE : self::MALE));
245
246 12
                    switch (NounPluralization::getNumeralForm($count)) {
247 12
                        case NounPluralization::ONE:
248 4
                            $parts[] = NounDeclension::getCases($word, false);
249 4
                            break;
250
251 11 View Code Duplication
                        case NounPluralization::TWO_FOUR:
0 ignored issues
show
This code seems to be duplicated across 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...
252 6
                            $part = NounPluralization::getCases($word);
253 6
                            if ($word_number != 1000) { // get dative case of word for 1000000, 1000000000 and 1000000000000
254 3
                                $part[Cases::IMENIT] = $part[Cases::VINIT] = NounDeclension::getCase($word, Cases::RODIT);
255
                            }
256 6
                            $parts[] = $part;
257 6
                            break;
258
259 8 View Code Duplication
                        case NounPluralization::FIVE_OTHER:
0 ignored issues
show
This code seems to be duplicated across 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...
260 8
                            $part = NounPluralization::getCases($word);
261 8
                            $part[Cases::IMENIT] = $part[Cases::VINIT] = $part[Cases::RODIT];
262 8
                            $parts[] = $part;
263 8
                            break;
264
                    }
265
266 19
                    $number = $number % ($count * $word_number);
267
                }
268
            }
269
270 19 View Code Duplication
            foreach (array_reverse(self::$words, true) as $word_number => $word) {
0 ignored issues
show
This code seems to be duplicated across 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...
271 19
                if ($number >= $word_number) {
272 19
                    $parts[] = self::getCases($word_number, $gender);
273 19
                    $number %= $word_number;
274
                }
275
            }
276
277
            // make one array with cases and delete 'o/об' prepositional from all parts except the last one
278 19
            foreach (array(self::IMENIT, self::RODIT, self::DAT, self::VINIT, self::TVORIT, self::PREDLOJ) as $case) {
279 19
                $result[$case] = [];
280 19
                foreach ($parts as $partN => $part) {
281 19
                    $result[$case][] = $part[$case];
282
                }
283 19
                $result[$case] = implode(' ', $result[$case]);
284
            }
285
286 19
            return $result;
287
        }
288
    }
289
290
    /**
291
     * @param $number
292
     * @param $case
293
     * @param string $gender
294
     * @return mixed|void
295
     */
296 23
    public static function getCase($number, $case, $gender = self::MALE)
297
    {
298 23
        $case = self::canonizeCase($case);
299 23
        $forms = self::getCases($number, $gender);
300 23
        return $forms[$case];
301
    }
302
}
303