Completed
Push — master ( 13fe0a...7029b0 )
by f
02:11
created

src/Russian/GeographicalNamesInflection.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\S;
5
6
/**
7
 * Rules are from: https://ru.wikipedia.org/wiki/%D0%A1%D0%BA%D0%BB%D0%BE%D0%BD%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B3%D0%B5%D0%BE%D0%B3%D1%80%D0%B0%D1%84%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B8%D1%85_%D0%BD%D0%B0%D0%B7%D0%B2%D0%B0%D0%BD%D0%B8%D0%B9_%D0%B2_%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D0%BC_%D1%8F%D0%B7%D1%8B%D0%BA%D0%B5
8
 */
9
class GeographicalNamesInflection extends \morphos\BaseInflection implements Cases
10
{
11
    use RussianLanguage, CasesHelper;
12
13
    protected static $abbreviations = array(
14
        'сша',
15
        'оаэ',
16
        'ссср',
17
        'юар',
18
    );
19
20
    public static function isMutable($name)
21
    {
22
        $name = S::lower($name);
23
24
        // // ends with 'ы' or 'и': plural form
25
        // if (in_array(S::slice($name, -1), array('и', 'ы')))
26
        //     return false;
27
28
        if (in_array($name, self::$abbreviations)) {
29
            return false;
30
        }
31
32
        // N край
33
        if (S::slice($name, -5) == ' край') {
34
            return static::isMutable(S::slice($name, 0, -5));
35
        }
36
37
        // N область
38
        if (S::slice($name, -8) == ' область') {
39
            return true;
40
        }
41
42
        // город N
43
        if (S::slice($name, 0, 6) == 'город ') {
44
            return true;
45
        }
46
47
        // ends with 'е' or 'о', but not with 'ово/ёво/ево/ино/ыно'
48
        if (in_array(S::slice($name, -1), array('е', 'о')) && !in_array(S::slice($name, -3, -1), array('ов', 'ёв', 'ев', 'ин', 'ын'))) {
49
            return false;
50
        }
51
        return true;
52
    }
53
54
    public static function getCases($name)
55
    {
56
        $name = S::lower($name);
57
58
        // N край
59 View Code Duplication
        if (S::slice($name, -5) == ' край') {
60
            return self::composeCasesFromWords([static::getCases(S::slice($name, 0, -5)), NounDeclension::getCases('край')]);
61
        }
62
63
        // N область
64 View Code Duplication
        if (S::slice($name, -8) == ' область') {
65
            return self::composeCasesFromWords([static::getCases(S::slice($name, 0, -8)), NounDeclension::getCases('область')]);
66
        }
67
68
        // город N
69 View Code Duplication
        if (S::slice($name, 0, 6) == 'город ') {
70
            return self::composeCasesFromWords([
71
                NounDeclension::getCases('город'),
72
                array_fill_keys(self::getAllCases(), S::name(S::slice($name, -6)))
73
            ]);
74
        }
75
76
        // check for name of few words
77 View Code Duplication
        if (strpos($name, ' ') !== false) {
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...
78
            $parts = explode(' ', $name);
79
            $cases = array();
80
            $result = array();
81
            foreach ($parts as $i => $part) {
82
                $result[$i] = static::getCases($part);
83
            }
84
            return self::composeCasesFromWords($result);
85
        }
86
87
        if (!in_array($name, self::$abbreviations)) {
88
            if (S::slice($name, -2) == 'ий') {
89
                // Нижний, Русский
90
                $prefix = S::name(S::slice($name, 0, -2));
91
                return array(
92
                    self::IMENIT => $prefix.'ий',
93
                    self::RODIT => $prefix.(self::isVelarConsonant(S::slice($name, -3, -2)) ? 'ого' : 'его'),
94
                    self::DAT => $prefix.(self::isVelarConsonant(S::slice($name, -3, -2)) ? 'ому' : 'ему'),
95
                    self::VINIT => $prefix.'ий',
96
                    self::TVORIT => $prefix.'им',
97
                    self::PREDLOJ => $prefix.(self::chooseEndingBySonority($prefix, 'ем', 'ом')),
98
                );
99
            } else if (S::slice($name, -2) == 'ая') {
100
                // Ростовская
101
                $prefix = S::name(S::slice($name, 0, -2));
102
                return array(
103
                    self::IMENIT => $prefix.'ая',
104
                    self::RODIT => $prefix.'ой',
105
                    self::DAT => $prefix.'ой',
106
                    self::VINIT => $prefix.'ую',
107
                    self::TVORIT => $prefix.'ой',
108
                    self::PREDLOJ => $prefix.'ой',
109
                );
110
            } else if (S::slice($name, -2) == 'ый') {
111
                // Грозный, Благодарный
112
                $prefix = S::name(S::slice($name, 0, -2));
113
                return array(
114
                    self::IMENIT => $prefix.'ый',
115
                    self::RODIT => $prefix.'ого',
116
                    self::DAT => $prefix.'ому',
117
                    self::VINIT => $prefix.'ый',
118
                    self::TVORIT => $prefix.'ым',
119
                    self::PREDLOJ => $prefix.'ом',
120
                );
121
            } elseif (S::slice($name, -1) == 'а') {
122
                // Москва, Рига
123
                $prefix = S::name(S::slice($name, 0, -1));
124
                return array(
125
                    self::IMENIT => $prefix.'а',
126
                    self::RODIT => $prefix.(self::isVelarConsonant(S::slice($name, -2, -1)) ? 'и' : 'ы'),
127
                    self::DAT => $prefix.'е',
128
                    self::VINIT => $prefix.'у',
129
                    self::TVORIT => $prefix.'ой',
130
                    self::PREDLOJ => $prefix.'е',
131
                );
132
            } elseif (S::slice($name, -1) == 'я') {
133
                // Азия
134
                $prefix = S::name(S::slice($name, 0, -1));
135
                return array(
136
                    self::IMENIT => S::name($name),
137
                    self::RODIT => $prefix.'и',
138
                    self::DAT => $prefix.'и',
139
                    self::VINIT => $prefix.'ю',
140
                    self::TVORIT => $prefix.'ей',
141
                    self::PREDLOJ => $prefix.'и',
142
                );
143
            } elseif (S::slice($name, -1) == 'й') {
144
                // Ишимбай
145
                $prefix = S::name(S::slice($name, 0, -1));
146
                return array(
147
                    self::IMENIT => $prefix.'й',
148
                    self::RODIT => $prefix.'я',
149
                    self::DAT => $prefix.'ю',
150
                    self::VINIT => $prefix.'й',
151
                    self::TVORIT => $prefix.'ем',
152
                    self::PREDLOJ => $prefix.'е',
153
                );
154 View Code Duplication
            } elseif (self::isConsonant(S::slice($name, -1)) && S::slice($name, -2) != 'ов') {
155
                // Париж, Валаам, Киев
156
                $prefix = S::name($name);
157
                return array(
158
                    self::IMENIT => $prefix,
159
                    self::RODIT => $prefix.'а',
160
                    self::DAT => $prefix.'у',
161
                    self::VINIT => $prefix,
162
                    self::TVORIT => $prefix.(self::isVelarConsonant(S::slice($name, -2, -1)) ? 'ем' : 'ом'),
163
                    self::PREDLOJ => $prefix.'е',
164
                );
165
            } elseif (S::slice($name, -2) == 'ль') {
166
                // Ставрополь, Ярославль
167
                $prefix = S::name(S::slice($name, 0, -1));
168
                return array(
169
                    self::IMENIT => $prefix.'ь',
170
                    self::RODIT => $prefix.'я',
171
                    self::DAT => $prefix.'ю',
172
                    self::VINIT => $prefix.'ь',
173
                    self::TVORIT => $prefix.'ем',
174
                    self::PREDLOJ => $prefix.'е',
175
                );
176
            } elseif (S::slice($name, -2) == 'рь') {
177
                // Тверь
178
                $prefix = S::name(S::slice($name, 0, -1));
179
                return array(
180
                    self::IMENIT => $prefix.'ь',
181
                    self::RODIT => $prefix.'и',
182
                    self::DAT => $prefix.'и',
183
                    self::VINIT => $prefix.'ь',
184
                    self::TVORIT => $prefix.'ью',
185
                    self::PREDLOJ => $prefix.'и',
186
                );
187
            } elseif (S::slice($name, -2) == 'ки') {
188
                // Березники, Ессентуки
189
                $prefix = S::name(S::slice($name, 0, -1));
190
                return array(
191
                    self::IMENIT => $prefix.'и',
192
                    self::RODIT => $prefix.'ов',
193
                    self::DAT => $prefix.'ам',
194
                    self::VINIT => $prefix.'и',
195
                    self::TVORIT => $prefix.'ами',
196
                    self::PREDLOJ => $prefix.'ах',
197
                );
198
            } elseif (S::slice($name, -2) == 'мь') {
199
                // Пермь, Кемь
200
                $prefix = S::name(S::slice($name, 0, -1));
201
                return array(
202
                    self::IMENIT => $prefix.'ь',
203
                    self::RODIT => $prefix.'и',
204
                    self::DAT => $prefix.'и',
205
                    self::VINIT => $prefix.'ь',
206
                    self::TVORIT => $prefix.'ью',
207
                    self::PREDLOJ => $prefix.'и',
208
                );
209
            } elseif (S::slice($name, -2) == 'нь') {
210
                // Рязань, Назрань
211
                $prefix = S::name(S::slice($name, 0, -1));
212
                return array(
213
                    self::IMENIT => $prefix.'ь',
214
                    self::RODIT => $prefix.'и',
215
                    self::DAT => $prefix.'и',
216
                    self::VINIT => $prefix.'ь',
217
                    self::TVORIT => $prefix.'ью',
218
                    self::PREDLOJ => $prefix.'и',
219
                );
220 View Code Duplication
            } else if (S::slice($name, -2) == 'ые') {
221
                // Набережные
222
                $prefix = S::name(S::slice($name, 0, -1));
223
                return array(
224
                    self::IMENIT => $prefix.'е',
225
                    self::RODIT => $prefix.'х',
226
                    self::DAT => $prefix.'м',
227
                    self::VINIT => $prefix.'е',
228
                    self::TVORIT => $prefix.'ми',
229
                    self::PREDLOJ => $prefix.'х',
230
                );
231
            } else if (S::slice($name, -2) == 'ны') {
232
                // Челны
233
                $prefix = S::name(S::slice($name, 0, -1));
234
                return array(
235
                    self::IMENIT => $prefix.'ы',
236
                    self::RODIT => $prefix.'ов',
237
                    self::DAT => $prefix.'ам',
238
                    self::VINIT => $prefix.'ы',
239
                    self::TVORIT => $prefix.'ами',
240
                    self::PREDLOJ => $prefix.'ах',
241
                );
242
            }
243
244
            $suffixes = array('ов', 'ёв', 'ев', 'ин', 'ын');
245
            if ((in_array(S::slice($name, -1), array('е', 'о')) && in_array(S::slice($name, -3, -1), $suffixes)) || in_array(S::slice($name, -2), $suffixes)) {
246
                // ово, ёво, ...
247
                if (in_array(S::slice($name, -3, -1), $suffixes)) {
248
                    $prefix = S::name(S::slice($name, 0, -1));
249
                }
250
                // ов, её, ...
251
                elseif (in_array(S::slice($name, -2), $suffixes)) {
252
                    $prefix = S::name($name);
253
                }
254
                return array(
255
                    self::IMENIT => S::name($name),
256
                    self::RODIT => $prefix.'а',
257
                    self::DAT => $prefix.'у',
258
                    self::VINIT => S::name($name),
259
                    self::TVORIT => $prefix.'ым',
260
                    self::PREDLOJ => $prefix.'е',
261
                );
262
            }
263
        }
264
265
        // if no rules matches or name is immutable
266
        $name = in_array($name, self::$abbreviations) ? S::upper($name) : S::name($name);
267
        return array_fill_keys(array(self::IMENIT, self::RODIT, self::DAT, self::VINIT, self::TVORIT, self::PREDLOJ), $name);
268
    }
269
270
    public static function getCase($name, $case)
271
    {
272
        $case = self::canonizeCase($case);
273
        $forms = self::getCases($name);
274
        return $forms[$case];
275
    }
276
}
277