Completed
Push — master ( 6a872b...95bb87 )
by f
01:14
created

src/Russian/OrdinalNumeralGenerator.php (1 issue)

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
 *            and http://school-collection.edu.ru/dlrstore-wrapper/ebbc76cf-46b6-4d51-ad92-d9a84db35cfa/[I-RUS_06-05]_[TE_16-SU]/[I-RUS_06-05]_[TE_16-SU].html
10
 */
11
class OrdinalNumeralGenerator extends NumeralGenerator implements Cases
12
{
13
    use RussianLanguage, CasesHelper;
14
15
    protected static $words = array(
16
        1 => 'первый',
17
        2 => 'второй',
18
        3 => 'третий',
19
        4 => 'четвертый',
20
        5 => 'пятый',
21
        6 => 'шестой',
22
        7 => 'седьмой',
23
        8 => 'восьмой',
24
        9 => 'девятый',
25
        10 => 'десятый',
26
        11 => 'одиннадцатый',
27
        12 => 'двенадцатый',
28
        13 => 'тринадцатый',
29
        14 => 'четырнадцатый',
30
        15 => 'пятнадцатый',
31
        16 => 'шестнадцатый',
32
        17 => 'семнадцатый',
33
        18 => 'восемнадцатый',
34
        19 => 'девятнадцатый',
35
        20 => 'двадцатый',
36
        30 => 'тридцатый',
37
        40 => 'сороковой',
38
        50 => 'пятьдесятый',
39
        60 => 'шестьдесятый',
40
        70 => 'семьдесятый',
41
        80 => 'восемьдесятый',
42
        90 => 'девяностый',
43
        100 => 'сотый',
44
        200 => 'двухсотый',
45
        300 => 'трехсотый',
46
        400 => 'четырехсотый',
47
        500 => 'пятисотый',
48
        600 => 'шестисотый',
49
        700 => 'семисотый',
50
        800 => 'восемисотый',
51
        900 => 'девятисотый',
52
    );
53
54
    protected static $exponents = array(
55
        1000 => 'тысячный',
56
        1000000 => 'миллионный',
57
        1000000000 => 'миллиардный',
58
        1000000000000 => 'триллионный',
59
    );
60
61
    protected static $multipliers = array(
62
        2 => 'двух',
63
        3 => 'трех',
64
        4 => 'четырех',
65
        5 => 'пяти',
66
        6 => 'шести',
67
        7 => 'седьми',
68
        8 => 'восьми',
69
        9 => 'девяти',
70
        10 => 'десяти',
71
        11 => 'одиннадцати',
72
        12 => 'двенадцати',
73
        13 => 'тринадцати',
74
        14 => 'четырнадцати',
75
        15 => 'пятнадцати',
76
        16 => 'шестнадцати',
77
        17 => 'семнадцати',
78
        18 => 'восемнадцати',
79
        19 => 'девятнадцати',
80
        20 => 'двадцати',
81
        30 => 'тридцати',
82
        40 => 'сорока',
83
        50 => 'пятьдесяти',
84
        60 => 'шестьдесяти',
85
        70 => 'семьдесяти',
86
        80 => 'восемьдесяти',
87
        90 => 'девяности',
88
        100 => 'сто',
89
        200 => 'двухста',
90
        300 => 'трехста',
91
        400 => 'четырехста',
92
        500 => 'пятиста',
93
        600 => 'шестиста',
94
        700 => 'семиста',
95
        800 => 'восемиста',
96
        900 => 'девятиста',
97
    );
98
99
    public static function getCases($number, $gender = self::MALE)
100
    {
101
        // simple numeral
102
        if (isset(self::$words[$number]) || isset(self::$exponents[$number])) {
103
            $word = isset(self::$words[$number]) ? self::$words[$number] : self::$exponents[$number];
104
            // special rules for 3
105
            if ($number == 3) {
106
                $prefix = S::slice($word, 0, -2);
107
                return array(
108
                    self::IMENIT => $prefix.($gender == self::MALE ? 'ий' : ($gender == self::FEMALE ? 'ья' : 'ье')),
109
                    self::RODIT => $prefix.($gender == self::FEMALE ? 'ьей' : 'ьего'),
110
                    self::DAT => $prefix.($gender == self::FEMALE ? 'ьей' : 'ьему'),
111
                    self::VINIT => $prefix.($gender == self::FEMALE ? 'ью' : 'ьего'),
112
                    self::TVORIT => $prefix.($gender == self::FEMALE ? 'ьей' : 'ьим'),
113
                    self::PREDLOJ => self::choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.($gender == self::FEMALE ? 'ьей' : 'ьем'),
114
                );
115
            } else {
116
                switch ($gender) {
117 View Code Duplication
                    case self::MALE:
118
                        $prefix = S::slice($word, 0, $number == 40 ? -1 : -2);
119
                        return array(
120
                            self::IMENIT => $word,
121
                            self::RODIT => $prefix.'ого',
122
                            self::DAT => $prefix.'ому',
123
                            self::VINIT => $word,
124
                            self::TVORIT => $prefix.'ым',
125
                            self::PREDLOJ => self::choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'ом',
126
                        );
127
128 View Code Duplication
                    case self::FEMALE:
129
                        $prefix = S::slice($word, 0, $number == 40 ? -1 : -2);
130
                        return array(
131
                            self::IMENIT => $prefix.'ая',
132
                            self::RODIT => $prefix.'ой',
133
                            self::DAT => $prefix.'ой',
134
                            self::VINIT => $prefix.'ую',
135
                            self::TVORIT => $prefix.'ой',
136
                            self::PREDLOJ => self::choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'ой',
137
                        );
138
139 View Code Duplication
                    case self::NEUTER:
140
                        $prefix = S::slice($word, 0, $number == 40 ? -1 : -2);
141
                        return array(
142
                            self::IMENIT => $prefix.'ое',
143
                            self::RODIT => $prefix.'ого',
144
                            self::DAT => $prefix.'ому',
145
                            self::VINIT => $prefix.'ое',
146
                            self::TVORIT => $prefix.'ым',
147
                            self::PREDLOJ => self::choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'ом',
148
                        );
149
                }
150
            }
151
        }
152
        // compound numeral
153
        else {
154
            $ordinal_part = null;
155
            $ordinal_prefix = null;
156
            $cardinal_part = array();
0 ignored issues
show
$cardinal_part 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...
157
            $result = array();
158
159
            // test for exponents. If smaller summand of number is an exponent, declinate it
160
            foreach (array_reverse(self::$exponents, true) as $word_number => $word) {
161
                if ($number >= $word_number && ($number % $word_number) == 0) {
162
                    $count = floor($number / $word_number) % 1000;
163
                    $number -= ($count * $word_number);
164
                    foreach (array_reverse(self::$multipliers, true) as $multiplier => $multipliers_word) {
165
                        if ($count >= $multiplier) {
166
                            $ordinal_prefix .= $multipliers_word;
167
                            $count -= $multiplier;
168
                        }
169
                    }
170
                    $ordinal_part = self::getCases($word_number, $gender);
171
                    foreach ($ordinal_part as $case => $ordinal_word) {
172 View Code Duplication
                        if ($case == self::PREDLOJ) {
173
                            list(, $ordinal_part[$case]) = explode(' ', $ordinal_part[$case]);
174
                            $ordinal_part[$case] = self::choosePrepositionByFirstLetter($ordinal_prefix, 'об', 'о').' '.$ordinal_prefix.$ordinal_part[$case];
175
                        } else {
176
                            $ordinal_part[$case] = $ordinal_prefix.$ordinal_part[$case];
177
                        }
178
                    }
179
180
                    break;
181
                }
182
            }
183
184
            // otherwise, test if smaller summand is just a number with it's own name
185
            if (empty($ordinal_part)) {
186
                // get the smallest number with it's own name
187
                foreach (self::$words as $word_number => $word) {
188
                    if ($number >= $word_number) {
189
                        if ($word_number <= 9) {
190
                            if ($number % 10 == 0) {
191
                                continue;
192
                            }
193
                            // check for case when word_number smaller than should be used (e.g. 1,2,3 when it can be 4 (number: 344))
194
                            if (($number % 10) > $word_number) {
195
                                continue;
196
                            }
197
                            // check that there is no two-digits number with it's own name (e.g. 13 for 113)
198
                            if (isset(self::$words[$number % 100]) && $number % 100 > $word_number) {
199
                                continue;
200
                            }
201
                        } elseif ($word_number <= 90) {
202
                            // check for case when word_number smaller than should be used (e.g. 10, 11, 12 when it can be 13)
203
                            if (($number % 100) > $word_number) {
204
                                continue;
205
                            }
206
                        }
207
                        $ordinal_part = self::getCases($word_number, $gender);
208
                        $number -= $word_number;
209
                        break;
210
                    }
211
                }
212
            }
213
214
            // if number has second summand, get cardinal form of it
215
            if ($number > 0) {
216
                $cardinal_part = CardinalNumeralGenerator::getCase($number, self::IMENIT, $gender);
217
218
                // make one array with cases and delete 'o/об' prepositional from all parts except the last one
219
                foreach (array(self::IMENIT, self::RODIT, self::DAT, self::VINIT, self::TVORIT, self::PREDLOJ) as $case) {
220 View Code Duplication
                    if ($case == self::PREDLOJ) {
221
                        list(, $ordinal_part[$case]) = explode(' ', $ordinal_part[$case]);
222
                        $result[$case] = self::choosePrepositionByFirstLetter($cardinal_part, 'об', 'о').' '.$cardinal_part.' '.$ordinal_part[$case];
223
                    } else {
224
                        $result[$case] = $cardinal_part.' '.$ordinal_part[$case];
225
                    }
226
                }
227
            } else {
228
                $result = $ordinal_part;
229
            }
230
231
            return $result;
232
        }
233
    }
234
235
    public static function getCase($number, $case, $gender = self::MALE)
236
    {
237
        $case = self::canonizeCase($case);
238
        $forms = self::getCases($number, $gender);
239
        return $forms[$case];
240
    }
241
}
242