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

src/Russian/LastNamesInflection.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 http://gramma.ru/SPR/?id=2.8
8
 */
9
class LastNamesInflection extends \morphos\NamesInflection implements Cases
10
{
11
    use RussianLanguage, CasesHelper;
12
13
    protected static $menPostfixes = array('ов', 'ев' ,'ин' ,'ын', 'ой', 'ий');
14
    protected static $womenPostfixes = array('ва', 'на', 'ая', 'яя');
15
16
    public static function isMutable($name, $gender = null)
17
    {
18
        $name = S::lower($name);
19
        if ($gender === null) {
20
            $gender = self::detectGender($name);
21
        }
22
        // составная фамилия - разбить на части и проверить по отдельности
23
        if (strpos($name, '-') !== false) {
24
            foreach (explode('-', $name) as $part) {
25
                if (static::isMutable($part, $gender))
26
                    return true;
27
            }
28
            return false;
29
        }
30
31 View Code Duplication
        if (in_array(S::slice($name, -1), array('а', 'я'))) {
32
            return true;
33
        }
34
35
        if ($gender == self::MALE) {
36
            // Несклоняемые фамилии (Фоминых, Седых / Стецко, Писаренко)
37
            if (in_array(S::slice($name, -2), ['ых', 'ко']))
38
                return false;
39
40
            // Несклоняемые, образованные из родительного падежа личного или прозвищного имени главы семьи
41
            // суффиксы: ово, аго
42
            if (in_array(S::slice($name, -3), ['ово', 'аго']))
43
                return false;
44
45
            // Типичные суффикс мужских фамилий
46 View Code Duplication
            if (in_array(S::slice($name, -2), array('ов', 'ев', 'ин', 'ын', 'ий', 'ой'))) {
47
                return true;
48
            }
49
50
            // Согласная на конце
51
            if (self::isConsonant(S::slice($name, -1))) {
52
                return true;
53
            }
54
55
            // Мягкий знак на конце
56
            if (S::slice($name, -1) == 'ь') {
57
                return true;
58
            }
59
60 View Code Duplication
        } else {
61
            // Типичные суффиксы женских фамилий
62
            if (in_array(S::slice($name, -2), ['ва', 'на', 'ая'])) {
63
                return true;
64
            }
65
        }
66
67
        return false;
68
    }
69
70
    public static function detectGender($name)
71
    {
72
        $name = S::lower($name);
73
        if (in_array(S::slice($name, -2), self::$menPostfixes)) {
74
            return self::MALE;
75
        }
76
        if (in_array(S::slice($name, -2), self::$womenPostfixes)) {
77
            return self::FEMALE;
78
        }
79
80
        return null;
81
    }
82
83
    public static function getCases($name, $gender = null)
84
    {
85
        $name = S::lower($name);
86
        if ($gender === null) {
87
            $gender = self::detectGender($name);
88
        }
89
90
        // составная фамилия - разбить на части и склонять по отдельности
91 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...
92
            $parts = explode('-', $name);
93
            $cases = [];
94
            foreach ($parts as $i => $part) {
95
                $parts[$i] = static::getCases($part, $gender);
96
            }
97
98
            return self::composeCasesFromWords($parts, '-');
99
        }
100
        if (!static::isMutable($name, $gender)) {
101
            $prefix = S::name($name);
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
        }
111
112
        if ($gender == self::MALE) {
113
            if (in_array(S::slice($name, -2), array('ов', 'ев', 'ин', 'ын'))) {
114
                $prefix = S::name($name);
115
                return array(
116
                    self::IMENIT => $prefix,
117
                    self::RODIT => $prefix.'а',
118
                    self::DAT => $prefix.'у',
119
                    self::VINIT => $prefix.'а',
120
                    self::TVORIT => $prefix.'ым',
121
                    self::PREDLOJ => $prefix.'е'
122
                );
123 View Code Duplication
            } elseif (in_array(S::slice($name, -4), array('ский', 'ской', 'цкий', 'цкой'))) {
124
                $prefix = S::name(S::slice($name, 0, -2));
125
                return array(
126
                    self::IMENIT => S::name($name),
127
                    self::RODIT => $prefix.'ого',
128
                    self::DAT => $prefix.'ому',
129
                    self::VINIT => $prefix.'ого',
130
                    self::TVORIT => $prefix.'им',
131
                    self::PREDLOJ => $prefix.'ом'
132
                );
133
            // Верхний / Убогий / Толстой
134
            // Верхнего / Убогого / Толстого
135
            // Верхнему / Убогому / Толстому
136
            // Верхним / Убогим / Толстым
137
            // О Верхнем / Об Убогом / О Толстом
138
            } else if (in_array(S::slice($name, -2), ['ой', 'ый', 'ий'])) {
139
                $prefix = S::name(S::slice($name, 0, -2));
140
                return array(
141
                    self::IMENIT => S::name($name),
142
                    self::RODIT => $prefix.'ого',
143
                    self::DAT => $prefix.'ому',
144
                    self::VINIT => $prefix.'ого',
145
                    self::TVORIT => $prefix.'ым',
146
                    self::PREDLOJ => $prefix.'ом'
147
                );
148
            }
149
150
        } else {
151 View Code Duplication
            if (in_array(S::slice($name, -3), array('ова', 'ева', 'ина', 'ына'))) {
152
                $prefix = S::name(S::slice($name, 0, -1));
153
                return array(
154
                    self::IMENIT => S::name($name),
155
                    self::RODIT => $prefix.'ой',
156
                    self::DAT => $prefix.'ой',
157
                    self::VINIT => $prefix.'у',
158
                    self::TVORIT => $prefix.'ой',
159
                    self::PREDLOJ => $prefix.'ой'
160
                );
161
            }
162
163
            if (in_array(S::slice($name, -2), array('ая'))) {
164
                $prefix = S::name(S::slice($name, 0, -2));
165
                return array(
166
                    self::IMENIT => S::name($name),
167
                    self::RODIT => $prefix.'ой',
168
                    self::DAT => $prefix.'ой',
169
                    self::VINIT => $prefix.'ую',
170
                    self::TVORIT => $prefix.'ой',
171
                    self::PREDLOJ => $prefix.'ой'
172
                );
173
            }
174
        }
175
176
        if (S::slice($name, -1) == 'я') {
177
            $prefix = S::name(S::slice($name, 0, -1));
178
            return array(
179
                self::IMENIT => S::name($name),
180
                self::RODIT => $prefix.'и',
181
                self::DAT => $prefix.'е',
182
                self::VINIT => $prefix.'ю',
183
                self::TVORIT => $prefix.'ей',
184
                self::PREDLOJ => $prefix.'е'
185
            );
186 View Code Duplication
        } elseif (S::slice($name, -1) == 'а') {
187
            $prefix = S::name(S::slice($name, 0, -1));
188
            return array(
189
                self::IMENIT => S::name($name),
190
                self::RODIT => $prefix.(self::isDeafConsonant(S::slice($name, -2, -1)) ? 'и' : 'ы'),
191
                self::DAT => $prefix.'е',
192
                self::VINIT => $prefix.'у',
193
                self::TVORIT => $prefix.'ой',
194
                self::PREDLOJ => $prefix.'е'
195
            );
196
        } elseif (self::isConsonant(S::slice($name, -1)) && S::slice($name, -2) != 'ых') {
197
            $prefix = S::name($name);
198
            return array(
199
                self::IMENIT => S::name($name),
200
                self::RODIT => $prefix.'а',
201
                self::DAT => $prefix.'у',
202
                self::VINIT => $prefix.'а',
203
                self::TVORIT => $prefix.'ом',
204
                self::PREDLOJ => $prefix.'е'
205
            );
206
        } elseif (S::slice($name, -1) == 'ь' && $gender == self::MALE) {
207
            $prefix = S::name(S::slice($name, 0, -1));
208
            return array(
209
                self::IMENIT => S::name($name),
210
                self::RODIT => $prefix.'я',
211
                self::DAT => $prefix.'ю',
212
                self::VINIT => $prefix.'я',
213
                self::TVORIT => $prefix.'ем',
214
                self::PREDLOJ => $prefix.'е'
215
            );
216
        }
217
218
        $name = S::name($name);
219
        return array_fill_keys(array(self::IMENIT, self::RODIT, self::DAT, self::VINIT, self::TVORIT, self::PREDLOJ), $name);
220
    }
221
222
    public static function getCase($name, $case, $gender = null)
223
    {
224
        if (!static::isMutable($name, $gender)) {
225
            return $name;
226
        } else {
227
            $case = self::canonizeCase($case);
228
            $forms = self::getCases($name, $gender);
229
            return $forms[$case];
230
        }
231
    }
232
}
233