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