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

src/Russian/OrdinalNumeralGenerator.php (6 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
 *            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:
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...
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:
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...
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:
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...
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) {
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...
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) {
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...
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