GeographicalNamesInflection::getCases()   F
last analyzed

Complexity

Conditions 56
Paths 520

Size

Total Lines 368

Duplication

Lines 31
Ratio 8.42 %

Code Coverage

Tests 215
CRAP Score 57.235

Importance

Changes 0
Metric Value
cc 56
nc 520
nop 1
dl 31
loc 368
ccs 215
cts 232
cp 0.9267
crap 57.235
rs 0.5333
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 = [
14
        'сша',
15
        'оаэ',
16
        'ссср',
17
        'юар',
18
    ];
19
20
    protected static $delimiters = [
21
        ' ',
22
        '-на-',
23
        '-',
24
    ];
25
26
    protected static $ovAbnormalExceptions = [
27
        'осташков',
28
    ];
29
30
31
    protected static $immutableNames = [
32
        'алматы',
33
34
        // части
35
        'санкт',
36
        'йошкар',
37
        'улан',
38
        'ханты',
39
        'буда',
40
    ];
41
42
    protected static $runawayVowelsExceptions = [
43
        'торжо*к',
44
        'волоче*к',
45
        'орё*л',
46
        'египе*т',
47
        'лунине*ц',
48
        'городо*к',
49
        'новогрудо*к',
50
        'острове*ц',
51
    ];
52
53
    protected static $misspellings = [
54
        'орел' => 'орёл',
55
    ];
56
57
    /**
58
     * @return array|bool
59
     */
60 11 View Code Duplication
    protected static function getRunAwayVowelsList()
0 ignored issues
show
Duplication introduced by wapmorgan
This method seems to be duplicated in 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...
61
    {
62 11
        $runawayVowelsNormalized = [];
63 11
        foreach (static::$runawayVowelsExceptions as $word) {
64 11
            $runawayVowelsNormalized[str_replace('*', null, $word)] = S::indexOf($word, '*') - 1;
65
        }
66 11
        return $runawayVowelsNormalized;
67
    }
68
69
    /**
70
     * Проверяет, склоняемо ли название
71
     * @param string $name Название
72
     * @return bool
73
     */
74 2
    public static function isMutable($name)
75
    {
76 2
        $name = S::lower($name);
77
78
        // // ends with 'ы' or 'и': plural form
79
        // if (in_array(S::slice($name, -1), array('и', 'ы')))
80
        //     return false;
81
82 2
        if (in_array($name, static::$abbreviations, true) || in_array($name, static::$immutableNames, true)) {
83 2
            return false;
84
        }
85
86
        if (strpos($name, ' ') !== false) {
87
            // explode() is not applicable because Geographical unit may have few words
88
            $first_part = S::slice($name, 0, S::findFirstPosition($name, ' '));
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 76 can also be of type boolean; however, morphos\S::findFirstPosition() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 76 can also be of type boolean; however, morphos\S::slice() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
89
            $last_part = S::slice($name,
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 76 can also be of type boolean; however, morphos\S::slice() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
90
                S::findLastPosition($name, ' ') + 1);
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 76 can also be of type boolean; however, morphos\S::findLastPosition() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
91
92
            // город N, село N, хутор N, район N, поселок N, округ N, республика N
93
            // N область, N край
94
            if (in_array($first_part, ['город', 'село', 'хутор', 'район', 'поселок', 'округ', 'республика'], true)
95
                || in_array($last_part, ['край', 'область'], true)) {
96
                return true;
97
            }
98
99
            // пгт N
100
            if ($first_part === 'пгт')
101
                return false;
102
        }
103
104
        // ends with 'е' or 'о', but not with 'ово/ёво/ево/ино/ыно'
105
        if (in_array(S::slice($name, -1), ['е', 'о'], true)
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 76 can also be of type boolean; however, morphos\S::slice() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
106
            && !in_array(S::slice($name, -3, -1), ['ов', 'ёв', 'ев', 'ин', 'ын'], true)) {
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 76 can also be of type boolean; however, morphos\S::slice() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
107
            return false;
108
        }
109
        return true;
110
    }
111
112
    /**
113
     * Получение всех форм названия
114
     * @param string $name
115
     * @return array
116
     * @throws \Exception
117
     */
118 44
    public static function getCases($name)
119
    {
120 44
        $name = S::lower($name);
121
122
        // Проверка на неизменяемость и сложное название
123 44
        if (in_array($name, static::$immutableNames, true)) {
124 2
            return array_fill_keys([static::IMENIT, static::RODIT, static::DAT, static::VINIT, static::TVORIT, static::PREDLOJ], S::name($name));
125
        }
126
127 44
        if (strpos($name, ' ') !== false) {
128 9
            $first_part = S::slice($name, 0, S::findFirstPosition($name, ' '));
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 120 can also be of type boolean; however, morphos\S::findFirstPosition() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 120 can also be of type boolean; however, morphos\S::slice() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
129
            // город N, село N, хутор N, пгт N
130 9
            if (in_array($first_part, ['город', 'село', 'хутор', 'пгт', 'район', 'поселок', 'округ', 'республика'], true)) {
131 3
                if ($first_part !== 'пгт')
132 3
                    return static::composeCasesFromWords([
133 3
                        $first_part !== 'республика'
134 2
                            ? NounDeclension::getCases($first_part)
0 ignored issues
show
Security Bug introduced by wapmorgan
It seems like $first_part defined by \morphos\S::slice($name,...stPosition($name, ' ')) on line 128 can also be of type false; however, morphos\Russian\NounDeclension::getCases() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
135 3
                            : array_map(['\\morphos\\S', 'name'], NounDeclension::getCases($first_part)),
136 3
                        array_fill_keys(static::getAllCases(), S::name(S::slice($name, S::length($first_part) + 1)))
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 120 can also be of type boolean; however, morphos\S::slice() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
137
                    ]);
138
                else
139
                    return array_fill_keys([static::IMENIT, static::RODIT, static::DAT, static::VINIT, static::TVORIT, static::PREDLOJ], 'пгт '.S::name(S::slice($name, 4)));
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 120 can also be of type boolean; however, morphos\S::slice() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
140
            }
141
142 6
            $last_part = S::slice($name,
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 120 can also be of type boolean; however, morphos\S::slice() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
143 6
                S::findLastPosition($name, ' ') + 1);
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 120 can also be of type boolean; however, morphos\S::findLastPosition() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
144
            // N область, N край
145 6
            if (in_array($last_part, ['край', 'область'], true)) {
146 2
                return static::composeCasesFromWords([static::getCases(S::slice($name, 0, S::findLastPosition($name, ' '))), NounDeclension::getCases($last_part)]);
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 120 can also be of type boolean; however, morphos\S::findLastPosition() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Bug introduced by wapmorgan
It seems like $name defined by \morphos\S::lower($name) on line 120 can also be of type boolean; however, morphos\S::slice() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
Security Bug introduced by wapmorgan
It seems like \morphos\S::slice($name,...stPosition($name, ' ')) targeting morphos\S::slice() can also be of type false; however, morphos\Russian\Geograph...sInflection::getCases() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
Security Bug introduced by wapmorgan
It seems like $last_part defined by \morphos\S::slice($name,...sition($name, ' ') + 1) on line 142 can also be of type false; however, morphos\Russian\NounDeclension::getCases() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
147
            }
148
        }
149
150
        // Сложное название с разделителем
151 41
        foreach (static::$delimiters as $delimiter) {
152 41
            if (strpos($name, $delimiter) !== false) {
153 7
                $parts = explode($delimiter, $name);
154 7
                $result = [];
155 7
                foreach ($parts as $i => $part) {
156 7
                    $result[$i] = static::getCases($part);
157
                }
158 41
                return static::composeCasesFromWords($result, $delimiter);
159
            }
160
        }
161
162
        // Исправление ошибок
163 41
        if (array_key_exists($name, static::$misspellings)) {
164
            $name = static::$misspellings[$name];
165
        }
166
167
        // Само склонение
168 41
        if (!in_array($name, static::$abbreviations, true)) {
169 39
            switch (S::slice($name, -2)) {
170
                // Нижний, Русский
171 39
                case 'ий':
172 3
                    $prefix = S::name(S::slice($name, 0, -2));
173
                    return [
174 3
                        static::IMENIT => $prefix.'ий',
175 3
                        static::RODIT => $prefix.(static::isVelarConsonant(S::slice($name, -3, -2)) ? 'ого' : 'его'),
176 3
                        static::DAT => $prefix.(static::isVelarConsonant(S::slice($name, -3, -2)) ? 'ому' : 'ему'),
177 3
                        static::VINIT => $prefix.'ий',
178 3
                        static::TVORIT => $prefix.'им',
179 3
                        static::PREDLOJ => $prefix.(static::chooseEndingBySonority($prefix, 'ем', 'ом')),
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $prefix defined by \morphos\S::name(\morphos\S::slice($name, 0, -2)) on line 172 can also be of type boolean; however, morphos\Russian\RussianL...hooseEndingBySonority() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
180
                    ];
181
182
                // Ростовская
183 38
                case 'ая':
184 1
                    $prefix = S::name(S::slice($name, 0, -2));
185
                    return [
186 1
                        static::IMENIT => $prefix.'ая',
187 1
                        static::RODIT => $prefix.'ой',
188 1
                        static::DAT => $prefix.'ой',
189 1
                        static::VINIT => $prefix.'ую',
190 1
                        static::TVORIT => $prefix.'ой',
191 1
                        static::PREDLOJ => $prefix.'ой',
192
                    ];
193
194
                // Россошь
195 37
                case 'шь':
196 1
                    $prefix = S::name(S::slice($name, 0, -1));
197
                    return [
198 1
                        static::IMENIT => $prefix.'ь',
199 1
                        static::RODIT => $prefix.'и',
200 1
                        static::DAT => $prefix.'и',
201 1
                        static::VINIT => $prefix.'ь',
202 1
                        static::TVORIT => $prefix.'ью',
203 1
                        static::PREDLOJ => $prefix.'и',
204
                    ];
205
206
                // Грозный, Благодарный
207 36
                case 'ый':
208 2
                    $prefix = S::name(S::slice($name, 0, -2));
209
                    return [
210 2
                        static::IMENIT => $prefix.'ый',
211 2
                        static::RODIT => $prefix.'ого',
212 2
                        static::DAT => $prefix.'ому',
213 2
                        static::VINIT => $prefix.'ый',
214 2
                        static::TVORIT => $prefix.'ым',
215 2
                        static::PREDLOJ => $prefix.'ом',
216
                    ];
217
218
                // Ставрополь, Ярославль, Электросталь
219 34
                case 'ль':
220 2
                    $prefix = S::name(S::slice($name, 0, -1));
221
222 2 View Code Duplication
                    if ($name === 'электросталь')
0 ignored issues
show
Duplication introduced by wapmorgan
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...
223
                        return [
224 1
                            static::IMENIT => $prefix.'ь',
225 1
                            static::RODIT => $prefix.'и',
226 1
                            static::DAT => $prefix.'и',
227 1
                            static::VINIT => $prefix.'ь',
228 1
                            static::TVORIT => $prefix.'ью',
229 1
                            static::PREDLOJ => $prefix.'и',
230
                        ];
231
232
                    return [
233 1
                        static::IMENIT => $prefix.'ь',
234 1
                        static::RODIT => $prefix.'я',
235 1
                        static::DAT => $prefix.'ю',
236 1
                        static::VINIT => $prefix.'ь',
237 1
                        static::TVORIT => $prefix.'ем',
238 1
                        static::PREDLOJ => $prefix.'е',
239
                    ];
240
241
                // Тверь, Анадырь
242 32
                case 'рь':
243 2
                    $prefix = S::name(S::slice($name, 0, -1));
244 2
                    $last_vowel = S::slice($prefix, -2, -1);
0 ignored issues
show
Bug introduced by wapmorgan
It seems like $prefix defined by \morphos\S::name(\morphos\S::slice($name, 0, -1)) on line 243 can also be of type boolean; however, morphos\S::slice() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
245
                    return [
246 2
                        static::IMENIT => $prefix . 'ь',
247 2
                        static::RODIT => $prefix . (static::isBinaryVowel($last_vowel) ? 'и' : 'я'),
248 2
                        static::DAT => $prefix . (static::isBinaryVowel($last_vowel) ? 'и' : 'ю'),
249 2
                        static::VINIT => $prefix . 'ь',
250 2
                        static::TVORIT => $prefix . (static::isBinaryVowel($last_vowel) ? 'ью' : 'ем'),
251 2
                        static::PREDLOJ => $prefix . (static::isBinaryVowel($last_vowel) ? 'и' : 'е'),
252
                    ];
253
254
                // Березники, Ессентуки
255 30
                case 'ки':
256
                // Старые Дороги
257 29
                case 'ги':
258
                // Ушачи, Ивацевичи
259 29
                case 'чи':
260 3
                    $prefix = S::name(S::slice($name, 0, -1));
261
                    return [
262 3
                        static::IMENIT => $prefix . 'и',
263 3
                        static::RODIT => ($name === 'луки'
264 1
                            ? $prefix
265 2
                            : (S::slice($name, -2) === 'чи'
266 1
                                ? $prefix . 'ей'
267 3
                                : $prefix . 'ов')),
268 3
                        static::DAT => $prefix . 'ам',
269 3
                        static::VINIT => $prefix . 'и',
270 3
                        static::TVORIT => $prefix . 'ами',
271 3
                        static::PREDLOJ => $prefix . 'ах',
272
                    ];
273
274
                // Пермь, Кемь
275 28
                case 'мь':
276 1
                    $prefix = S::name(S::slice($name, 0, -1));
277
                    return [
278 1
                        static::IMENIT => $prefix . 'ь',
279 1
                        static::RODIT => $prefix . 'и',
280 1
                        static::DAT => $prefix . 'и',
281 1
                        static::VINIT => $prefix . 'ь',
282 1
                        static::TVORIT => $prefix . 'ью',
283 1
                        static::PREDLOJ => $prefix . 'и',
284
                    ];
285
286
                // Рязань, Назрань
287 27
                case 'нь':
288 1
                    $prefix = S::name(S::slice($name, 0, -1));
289
                    return [
290 1
                        static::IMENIT => $prefix . 'ь',
291 1
                        static::RODIT => $prefix . 'и',
292 1
                        static::DAT => $prefix . 'и',
293 1
                        static::VINIT => $prefix . 'ь',
294 1
                        static::TVORIT => $prefix . 'ью',
295 1
                        static::PREDLOJ => $prefix . 'и',
296
                    ];
297
298
                // Набережные
299 26
                case 'ые':
300 1
                    $prefix = S::name(S::slice($name, 0, -1));
301
                    return [
302 1
                        static::IMENIT => $prefix . 'е',
303 1
                        static::RODIT => $prefix . 'х',
304 1
                        static::DAT => $prefix . 'м',
305 1
                        static::VINIT => $prefix . 'е',
306 1
                        static::TVORIT => $prefix . 'ми',
307 1
                        static::PREDLOJ => $prefix . 'х',
308
                    ];
309
310
                // Челны
311 26
                case 'ны':
312
                // Мосты
313 25
                case 'ты':
314
                // Столбцы
315 25
                case 'цы':
316 2
                    $prefix = S::name(S::slice($name, 0, -1));
317
                    return [
318 2
                        static::IMENIT => $prefix . 'ы',
319 2
                        static::RODIT => $prefix . 'ов',
320 2
                        static::DAT => $prefix . 'ам',
321 2
                        static::VINIT => $prefix . 'ы',
322 2
                        static::TVORIT => $prefix . 'ами',
323 2
                        static::PREDLOJ => $prefix . 'ах',
324
                    ];
325
326
                // Великие
327 24
                case 'ие':
328 1
                    $prefix = S::name(S::slice($name, 0, -1));
329
                    return [
330 1
                        static::IMENIT => $prefix.'е',
331 1
                        static::RODIT => $prefix.'х',
332 1
                        static::DAT => $prefix.'м',
333 1
                        static::VINIT => $prefix.'е',
334 1
                        static::TVORIT => $prefix.'ми',
335 1
                        static::PREDLOJ => $prefix.'х',
336
                    ];
337
338
                // Керчь
339 23
                case 'чь':
340 1
                    $prefix = S::name(S::slice($name, 0, -1));
341
                    return [
342 1
                        static::IMENIT => $prefix.'ь',
343 1
                        static::RODIT => $prefix.'и',
344 1
                        static::DAT => $prefix.'и',
345 1
                        static::VINIT => $prefix.'ь',
346 1
                        static::TVORIT => $prefix.'ью',
347 1
                        static::PREDLOJ => $prefix.'и',
348
                    ];
349
350
                //
351 22
                case 'чи':
352
                    $prefix = S::name(S::slice($name, 0, -1));
353
                    return [
354
                        static::IMENIT => $prefix.'и',
355
                        static::RODIT => $prefix.'ей',
356
                        static::DAT => $prefix.'ам',
357
                        static::VINIT => $prefix.'и',
358
                        static::TVORIT => $prefix.'ами',
359
                        static::PREDLOJ => $prefix.'ах',
360
                    ];
361
362
                // Глубокое
363 22
                case 'ое':
364 1
                    $prefix = S::name(S::slice($name, 0, -2));
365
                    return [
366 1
                        static::IMENIT => $prefix.'ое',
367 1
                        static::RODIT => $prefix.'ого',
368 1
                        static::DAT => $prefix.'ому',
369 1
                        static::VINIT => $prefix.'ое',
370 1
                        static::TVORIT => $prefix.'им',
371 1
                        static::PREDLOJ => $prefix.'ом',
372
                    ];
373
374
            }
375
376 21
            switch (S::slice($name, -1)) {
377 21
                case 'р':
378
                    // Бор
379
                    $prefix = S::name(S::slice($name, 0, -1));
380
                    return [
381
                        static::IMENIT => $prefix.'р',
382
                        static::RODIT => $prefix.'ра',
383
                        static::DAT => $prefix.'ру',
384
                        static::VINIT => $prefix.'р',
385
                        static::TVORIT => $prefix.'ром',
386
                        static::PREDLOJ => $prefix.'ре',
387
                    ];
388
389 21 View Code Duplication
                case 'ы':
0 ignored issues
show
Duplication introduced by Pavel Nappsel
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...
390
                    // Чебоксары, Шахты
391 1
                    $prefix = S::name(S::slice($name, 0, -1));
392
                    return [
393 1
                        static::IMENIT => $prefix.'ы',
394 1
                        static::RODIT => $prefix,
395 1
                        static::DAT => $prefix.'ам',
396 1
                        static::VINIT => $prefix.'ы',
397 1
                        static::TVORIT => $prefix.'ами',
398 1
                        static::PREDLOJ => $prefix.'ах',
399
                    ];
400
401 20
                case 'я':
402
                    // Азия
403 1
                    $prefix = S::name(S::slice($name, 0, -1));
404
                    return [
405 1
                        static::IMENIT => S::name($name),
406 1
                        static::RODIT => $prefix.'и',
407 1
                        static::DAT => $prefix.'и',
408 1
                        static::VINIT => $prefix.'ю',
409 1
                        static::TVORIT => $prefix.'ей',
410 1
                        static::PREDLOJ => $prefix.'и',
411
                    ];
412
413 19 View Code Duplication
                case 'а':
0 ignored issues
show
Duplication introduced by wapmorgan
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...
414
                    // Москва, Рига
415 5
                    $prefix = S::name(S::slice($name, 0, -1));
416
                    return [
417 5
                        static::IMENIT => $prefix.'а',
418 5
                        static::RODIT => $prefix.(static::isVelarConsonant(S::slice($name, -2, -1)) ? 'и' : 'ы'),
419 5
                        static::DAT => $prefix.'е',
420 5
                        static::VINIT => $prefix.'у',
421 5
                        static::TVORIT => $prefix.'ой',
422 5
                        static::PREDLOJ => $prefix.'е',
423
                    ];
424
425 14
                case 'й':
426
                    // Ишимбай
427 2
                    $prefix = S::name(S::slice($name, 0, -1));
428
                    return [
429 2
                        static::IMENIT => $prefix . 'й',
430 2
                        static::RODIT => $prefix . 'я',
431 2
                        static::DAT => $prefix . 'ю',
432 2
                        static::VINIT => $prefix . 'й',
433 2
                        static::TVORIT => $prefix . 'ем',
434 2
                        static::PREDLOJ => $prefix . 'е',
435
                    ];
436
            }
437
438 12
            if (static::isConsonant(S::slice($name,  -1)) && !in_array($name, static::$ovAbnormalExceptions, true)) {
439 11
                $runaway_vowels_list = static::getRunAwayVowelsList();
440
441
                // if run-away vowel in name
442 11
                if (isset($runaway_vowels_list[$name])) {
443 4
                    $runaway_vowel_offset = $runaway_vowels_list[$name];
444 4
                    $prefix = S::name(S::slice($name, 0, $runaway_vowel_offset) . S::slice($name, $runaway_vowel_offset + 1));
445
                } else {
446 7
                    $prefix = S::name($name);
447
                }
448
449
                // Париж, Валаам, Киев
450
                return [
451 11
                    static::IMENIT => S::name($name),
452 11
                    static::RODIT => $prefix . 'а',
453 11
                    static::DAT => $prefix . 'у',
454 11
                    static::VINIT => S::name($name),
455 11
                    static::TVORIT => $prefix . (static::isVelarConsonant(S::slice($name, -2, -1)) ? 'ем' : 'ом'),
456 11
                    static::PREDLOJ => $prefix . 'е',
457
                ];
458
            }
459
460
            // ов, ово, ёв, ёво, ев, ево, ...
461 2
            $suffixes = ['ов', 'ёв', 'ев', 'ин', 'ын'];
462 2
            if ((in_array(S::slice($name, -1), ['е', 'о'], true) && in_array(S::slice($name, -3, -1), $suffixes, true)) || in_array(S::slice($name, -2), $suffixes, true)) {
463
                // ово, ёво, ...
464 1
                if (in_array(S::slice($name, -3, -1), $suffixes, true)) {
465
                    $prefix = S::name(S::slice($name, 0, -1));
466
                }
467
                // ов, её, ...
468 1
                elseif (in_array(S::slice($name, -2), $suffixes, true)) {
469 1
                    $prefix = S::name($name);
470
                }
471
                return [
472 1
                    static::IMENIT => S::name($name),
473 1
                    static::RODIT => $prefix.'а',
474 1
                    static::DAT => $prefix.'у',
475 1
                    static::VINIT => S::name($name),
476 1
                    static::TVORIT => $prefix.'ым',
477 1
                    static::PREDLOJ => $prefix.'е',
478
                ];
479
            }
480
        }
481
482
        // if no rules matches or name is immutable
483 3
        $name = in_array($name, static::$abbreviations, true) ? S::upper($name) : S::name($name);
484 3
        return array_fill_keys([static::IMENIT, static::RODIT, static::DAT, static::VINIT, static::TVORIT, static::PREDLOJ], $name);
485
    }
486
487
    /**
488
     * Получение одной формы (падежа) названия.
489
     * @param string $name  Название
490
     * @param integer $case Падеж. Одна из констант \morphos\Russian\Cases или \morphos\Cases.
491
     * @see \morphos\Russian\Cases
492
     * @return string
493
     * @throws \Exception
494
     */
495
    public static function getCase($name, $case)
496
    {
497
        $case = static::canonizeCase($case);
498
        $forms = static::getCases($name);
499
        return $forms[$case];
500
    }
501
}
502