Completed
Push — master ( fcdd09...de389f )
by f
21s queued 11s
created

GeographicalNamesInflection::getCases()   F

Complexity

Conditions 60
Paths 705

Size

Total Lines 368

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 216
CRAP Score 62.5038

Importance

Changes 0
Metric Value
cc 60
nc 705
nop 1
dl 0
loc 368
ccs 216
cts 237
cp 0.9114
crap 62.5038
rs 0.3277
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
    ];
43
44
    protected static $runawayVowelsExceptions = [
45
        'торжо*к',
46
        'волоче*к',
47
        'орё*л',
48
        'египе*т',
49
        'лунине*ц',
50
        'городо*к',
51
        'новогрудо*к',
52
        'острове*ц',
53
    ];
54
55
    protected static $misspellings = [
56
        'орел' => 'орёл',
57
    ];
58
59
    /**
60
     * @return array|bool
61
     */
62 12 View Code Duplication
    protected static function getRunAwayVowelsList()
0 ignored issues
show
Duplication introduced by
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...
63
    {
64 12
        $runawayVowelsNormalized = [];
65 12
        foreach (static::$runawayVowelsExceptions as $word) {
66 12
            $runawayVowelsNormalized[str_replace('*', null, $word)] = S::indexOf($word, '*') - 1;
67
        }
68 12
        return $runawayVowelsNormalized;
69
    }
70
71
    /**
72
     * Проверяет, склоняемо ли название
73
     * @param string $name Название
74
     * @return bool
75
     */
76 2
    public static function isMutable($name)
77
    {
78 2
        $name = S::lower($name);
79
80
        // // ends with 'ы' or 'и': plural form
81
        // if (in_array(S::slice($name, -1), array('и', 'ы')))
82
        //     return false;
83
84 2
        if (in_array($name, static::$abbreviations, true) || in_array($name, static::$immutableNames, true)) {
85 2
            return false;
86
        }
87
88
        if (strpos($name, ' ') !== false) {
89
            // explode() is not applicable because Geographical unit may have few words
90
            $first_part = S::slice($name, 0, S::findFirstPosition($name, ' '));
0 ignored issues
show
Bug introduced by
It seems like $name defined by \morphos\S::lower($name) on line 78 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
It seems like $name defined by \morphos\S::lower($name) on line 78 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...
91
            $last_part = S::slice($name,
0 ignored issues
show
Bug introduced by
It seems like $name defined by \morphos\S::lower($name) on line 78 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...
92
                S::findLastPosition($name, ' ') + 1);
0 ignored issues
show
Bug introduced by
It seems like $name defined by \morphos\S::lower($name) on line 78 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...
93
94
            // город N, село N, хутор N, район N, поселок N, округ N, республика N
95
            // N область, N край, N район, N волость
96
            if (in_array($first_part, ['город', 'село', 'хутор', 'район', 'поселок', 'округ', 'республика'], true)
97
                || in_array($last_part, ['край', 'область', 'район', 'волость'], true)) {
98
                return true;
99
            }
100
101
            // пгт N
102
            if ($first_part === 'пгт')
103
                return false;
104
        }
105
106
        // ends with 'е' or 'о', but not with 'ово/ёво/ево/ино/ыно'
107
        if (in_array(S::slice($name, -1), ['е', 'о'], true)
0 ignored issues
show
Bug introduced by
It seems like $name defined by \morphos\S::lower($name) on line 78 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...
108
            && !in_array(S::slice($name, -3, -1), ['ов', 'ёв', 'ев', 'ин', 'ын'], true)) {
0 ignored issues
show
Bug introduced by
It seems like $name defined by \morphos\S::lower($name) on line 78 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...
109
            return false;
110
        }
111
        return true;
112
    }
113
114
    /**
115
     * Получение всех форм названия
116
     * @param string $name
117
     * @return array
118
     * @throws \Exception
119
     */
120 45
    public static function getCases($name)
121
    {
122 45
        $name = S::lower($name);
123
124
        // Проверка на неизменяемость и сложное название
125 45
        if (in_array($name, static::$immutableNames, true)) {
126 2
            return array_fill_keys(
127 2
                [static::IMENIT, static::RODIT, static::DAT, static::VINIT, static::TVORIT, static::PREDLOJ, static::LOCATIVE]
128 2
                , S::name($name));
129
        }
130
131 45
        if (strpos($name, ' ') !== false) {
132 9
            $first_part = S::slice($name, 0, S::findFirstPosition($name, ' '));
0 ignored issues
show
Bug introduced by
It seems like $name defined by \morphos\S::lower($name) on line 122 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
It seems like $name defined by \morphos\S::lower($name) on line 122 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...
133
            // город N, село N, хутор N, пгт N
134 9
            if (in_array($first_part, ['город', 'село', 'хутор', 'пгт', 'район', 'поселок', 'округ', 'республика'], true)) {
135 3
                if ($first_part === 'пгт')
136
                    return array_fill_keys(
137
                        [static::IMENIT, static::RODIT, static::DAT, static::VINIT, static::TVORIT, static::PREDLOJ, static::LOCATIVE],
138
                        'пгт '.S::name(S::slice($name, 4)));
0 ignored issues
show
Bug introduced by
It seems like $name defined by \morphos\S::lower($name) on line 122 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...
139
140 3
                if ($first_part === 'республика') {
141 1
                    $prefix = array_map(['\\morphos\\S', 'name'], NounDeclension::getCases($first_part));
142
                } else {
143 2
                    $prefix = NounDeclension::getCases($first_part);
0 ignored issues
show
Security Bug introduced by
It seems like $first_part defined by \morphos\S::slice($name,...stPosition($name, ' ')) on line 132 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...
144
                }
145 3
                $prefix[Cases::LOCATIVE] = $prefix[Cases::PREDLOJ];
146
147 3
                return static::composeCasesFromWords([$prefix,
148 3
                    array_fill_keys(
149 3
                        array_merge(static::getAllCases(), [\morphos\Russian\Cases::LOCATIVE]),
150 3
                        S::name(S::slice($name, S::length($first_part) + 1)))
0 ignored issues
show
Bug introduced by
It seems like $name defined by \morphos\S::lower($name) on line 122 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...
151
                ]);
152
            }
153
154 6
            $last_part = S::slice($name,
0 ignored issues
show
Bug introduced by
It seems like $name defined by \morphos\S::lower($name) on line 122 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...
155 6
                S::findLastPosition($name, ' ') + 1);
0 ignored issues
show
Bug introduced by
It seems like $name defined by \morphos\S::lower($name) on line 122 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...
156
            // N область, N край
157 6
            if (in_array($last_part, ['край', 'область', 'район', 'волость'], true)) {
158 2
                $last_part_cases = NounDeclension::getCases($last_part);
0 ignored issues
show
Security Bug introduced by
It seems like $last_part defined by \morphos\S::slice($name,...sition($name, ' ') + 1) on line 154 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...
159 2
                $last_part_cases[Cases::LOCATIVE] = $last_part_cases[Cases::PREDLOJ];
160 2
                return static::composeCasesFromWords(
161
                    [
162 2
                        static::getCases(S::slice($name, 0, S::findLastPosition($name, ' '))),
0 ignored issues
show
Bug introduced by
It seems like $name defined by \morphos\S::lower($name) on line 122 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
It seems like $name defined by \morphos\S::lower($name) on line 122 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
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...
163 2
                        $last_part_cases,
164
                    ]);
165
            }
166
        }
167
168
        // Сложное название с разделителем
169 42
        foreach (static::$delimiters as $delimiter) {
170 42
            if (strpos($name, $delimiter) !== false) {
171 7
                $parts = explode($delimiter, $name);
172 7
                $result = [];
173 7
                foreach ($parts as $i => $part) {
174 7
                    $result[$i] = static::getCases($part);
175
                }
176 42
                return static::composeCasesFromWords($result, $delimiter);
177
            }
178
        }
179
180
        // Исправление ошибок
181 42
        if (array_key_exists($name, static::$misspellings)) {
182
            $name = static::$misspellings[$name];
183
        }
184
185
        // Само склонение
186 42
        if (!in_array($name, static::$abbreviations, true)) {
187 40
            switch (S::slice($name, -2)) {
188
                // Нижний, Русский
189 40
                case 'ий':
190 3
                    $prefix = S::name(S::slice($name, 0, -2));
191
                    return [
192 3
                        static::IMENIT => $prefix.'ий',
193 3
                        static::RODIT => $prefix.(static::isVelarConsonant(S::slice($name, -3, -2)) ? 'ого' : 'его'),
194 3
                        static::DAT => $prefix.(static::isVelarConsonant(S::slice($name, -3, -2)) ? 'ому' : 'ему'),
195 3
                        static::VINIT => $prefix.'ий',
196 3
                        static::TVORIT => $prefix.'им',
197 3
                        static::PREDLOJ => $prefix.(static::chooseEndingBySonority($prefix, 'ем', 'ом')),
0 ignored issues
show
Bug introduced by
It seems like $prefix defined by \morphos\S::name(\morphos\S::slice($name, 0, -2)) on line 190 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...
198 3
                        static::LOCATIVE => $prefix.(static::chooseEndingBySonority($prefix, 'ем', 'ом')),
0 ignored issues
show
Bug introduced by
It seems like $prefix defined by \morphos\S::name(\morphos\S::slice($name, 0, -2)) on line 190 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...
199
                    ];
200
201
                // Ростовская
202 39
                case 'ая':
203 1
                    $prefix = S::name(S::slice($name, 0, -2));
204
                    return [
205 1
                        static::IMENIT => $prefix.'ая',
206 1
                        static::RODIT => $prefix.'ой',
207 1
                        static::DAT => $prefix.'ой',
208 1
                        static::VINIT => $prefix.'ую',
209 1
                        static::TVORIT => $prefix.'ой',
210 1
                        static::PREDLOJ => $prefix.'ой',
211 1
                        static::LOCATIVE => $prefix.'ой',
212
                    ];
213
214
                // Нижняя, Верхняя, Средняя
215 38
                case 'яя':
216
                    $prefix = S::name(S::slice($name, 0, -2));
217
                    return [
218
                        static::IMENIT => $prefix.'яя',
219
                        static::RODIT => $prefix.'ей',
220
                        static::DAT => $prefix.'ей',
221
                        static::VINIT => $prefix.'юю',
222
                        static::TVORIT => $prefix.'ей',
223
                        static::PREDLOJ => $prefix.'ей',
224
                        static::LOCATIVE => $prefix.'ей',
225
                    ];
226
227
                // Россошь
228 38
                case 'шь':
229
                // Пермь, Кемь
230 37
                case 'мь':
231
                // Рязань, Назрань
232 36
                case 'нь':
233
                // Сысерть
234 35
                case 'ть':
235
                // Керчь
236 35
                case 'чь':
237 4
                    $prefix = S::name(S::slice($name, 0, -1));
238
                    return [
239 4
                        static::IMENIT => $prefix.'ь',
240 4
                        static::RODIT => $prefix.'и',
241 4
                        static::DAT => $prefix.'и',
242 4
                        static::VINIT => $prefix.'ь',
243 4
                        static::TVORIT => $prefix.'ью',
244 4
                        static::PREDLOJ => $prefix.'и',
245 4
                        static::LOCATIVE => $prefix.'и',
246
                    ];
247
248
                // Грозный, Благодарный
249 34
                case 'ый':
250 2
                    $prefix = S::name(S::slice($name, 0, -2));
251
                    return [
252 2
                        static::IMENIT => $prefix.'ый',
253 2
                        static::RODIT => $prefix.'ого',
254 2
                        static::DAT => $prefix.'ому',
255 2
                        static::VINIT => $prefix.'ый',
256 2
                        static::TVORIT => $prefix.'ым',
257 2
                        static::PREDLOJ => $prefix.'ом',
258 2
                        static::LOCATIVE => $prefix.'ом',
259
                    ];
260
261
                // Ставрополь, Ярославль, Электросталь
262 32
                case 'ль':
263 2
                    $prefix = S::name(S::slice($name, 0, -1));
264
265 2
                    if ($name === 'электросталь')
266
                        return [
267 1
                            static::IMENIT => $prefix.'ь',
268 1
                            static::RODIT => $prefix.'и',
269 1
                            static::DAT => $prefix.'и',
270 1
                            static::VINIT => $prefix.'ь',
271 1
                            static::TVORIT => $prefix.'ью',
272 1
                            static::PREDLOJ => $prefix.'и',
273 1
                            static::LOCATIVE => $prefix.'и',
274
                        ];
275
276
                    return [
277 1
                        static::IMENIT => $prefix.'ь',
278 1
                        static::RODIT => $prefix.'я',
279 1
                        static::DAT => $prefix.'ю',
280 1
                        static::VINIT => $prefix.'ь',
281 1
                        static::TVORIT => $prefix.'ем',
282 1
                        static::PREDLOJ => $prefix.'е',
283 1
                        static::LOCATIVE => $prefix.'е',
284
                    ];
285
286
                // Тверь, Анадырь
287 30
                case 'рь':
288 2
                    $prefix = S::name(S::slice($name, 0, -1));
289 2
                    $last_vowel = S::slice($prefix, -2, -1);
0 ignored issues
show
Bug introduced by
It seems like $prefix defined by \morphos\S::name(\morphos\S::slice($name, 0, -1)) on line 288 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...
290
                    return [
291 2
                        static::IMENIT => $prefix . 'ь',
292 2
                        static::RODIT => $prefix . (static::isBinaryVowel($last_vowel) ? 'и' : 'я'),
293 2
                        static::DAT => $prefix . (static::isBinaryVowel($last_vowel) ? 'и' : 'ю'),
294 2
                        static::VINIT => $prefix . 'ь',
295 2
                        static::TVORIT => $prefix . (static::isBinaryVowel($last_vowel) ? 'ью' : 'ем'),
296 2
                        static::PREDLOJ => $prefix . (static::isBinaryVowel($last_vowel) ? 'и' : 'е'),
297 2
                        static::LOCATIVE => $prefix . (static::isBinaryVowel($last_vowel) ? 'и' : 'е'),
298
                    ];
299
300
                // Березники, Ессентуки
301 28
                case 'ки':
302
                // Старые Дороги
303 27
                case 'ги':
304
                // Ушачи, Ивацевичи
305 27
                case 'чи':
306 3
                    $prefix = S::name(S::slice($name, 0, -1));
307
                    return [
308 3
                        static::IMENIT => $prefix . 'и',
309 3
                        static::RODIT => ($name === 'луки'
310 1
                            ? $prefix
311 2
                            : (S::slice($name, -2) === 'чи'
312 1
                                ? $prefix . 'ей'
313 3
                                : $prefix . 'ов')),
314 3
                        static::DAT => $prefix . 'ам',
315 3
                        static::VINIT => $prefix . 'и',
316 3
                        static::TVORIT => $prefix . 'ами',
317 3
                        static::PREDLOJ => $prefix . 'ах',
318 3
                        static::LOCATIVE => $prefix . 'ах',
319
                    ];
320
321
                // Набережные
322 26
                case 'ые':
323
                // Великие
324 26
                case 'ие':
325 2
                    $prefix = S::name(S::slice($name, 0, -1));
326
                    return [
327 2
                        static::IMENIT => $prefix . 'е',
328 2
                        static::RODIT => $prefix . 'х',
329 2
                        static::DAT => $prefix . 'м',
330 2
                        static::VINIT => $prefix . 'е',
331 2
                        static::TVORIT => $prefix . 'ми',
332 2
                        static::PREDLOJ => $prefix . 'х',
333 2
                        static::LOCATIVE => $prefix . 'х',
334
                    ];
335
336
                // Челны
337 25
                case 'ны':
338
                // Мосты
339 24
                case 'ты':
340
                // Столбцы
341 24
                case 'цы':
342 2
                    $prefix = S::name(S::slice($name, 0, -1));
343
                    return [
344 2
                        static::IMENIT => $prefix . 'ы',
345 2
                        static::RODIT => $prefix . 'ов',
346 2
                        static::DAT => $prefix . 'ам',
347 2
                        static::VINIT => $prefix . 'ы',
348 2
                        static::TVORIT => $prefix . 'ами',
349 2
                        static::PREDLOJ => $prefix . 'ах',
350 2
                        static::LOCATIVE => $prefix . 'ах',
351
                    ];
352
353
                // Глубокое
354 23
                case 'ое':
355 1
                    $prefix = S::name(S::slice($name, 0, -2));
356
                    return [
357 1
                        static::IMENIT => $prefix.'ое',
358 1
                        static::RODIT => $prefix.'ого',
359 1
                        static::DAT => $prefix.'ому',
360 1
                        static::VINIT => $prefix.'ое',
361 1
                        static::TVORIT => $prefix.'им',
362 1
                        static::PREDLOJ => $prefix.'ом',
363 1
                        static::LOCATIVE => $prefix.'ом',
364
                    ];
365
366
            }
367
368 22
            switch (S::slice($name, -1)) {
369 22
                case 'р':
370
                    // Бор
371
                    $prefix = S::name(S::slice($name, 0, -1));
372
                    return [
373
                        static::IMENIT => $prefix.'р',
374
                        static::RODIT => $prefix.'ра',
375
                        static::DAT => $prefix.'ру',
376
                        static::VINIT => $prefix.'р',
377
                        static::TVORIT => $prefix.'ром',
378
                        static::PREDLOJ => $prefix.'ре',
379
                        static::LOCATIVE => $prefix.'ру',
380
                    ];
381
382 22
                case 'ы':
383
                    // Чебоксары, Шахты
384 1
                    $prefix = S::name(S::slice($name, 0, -1));
385
                    return [
386 1
                        static::IMENIT => $prefix.'ы',
387 1
                        static::RODIT => $prefix,
388 1
                        static::DAT => $prefix.'ам',
389 1
                        static::VINIT => $prefix.'ы',
390 1
                        static::TVORIT => $prefix.'ами',
391 1
                        static::PREDLOJ => $prefix.'ах',
392 1
                        static::LOCATIVE => $prefix.'ах',
393
                    ];
394
395 21
                case 'я':
396
                    // Азия
397 1
                    $prefix = S::name(S::slice($name, 0, -1));
398
                    return [
399 1
                        static::IMENIT => S::name($name),
400 1
                        static::RODIT => $prefix.'и',
401 1
                        static::DAT => $prefix.'и',
402 1
                        static::VINIT => $prefix.'ю',
403 1
                        static::TVORIT => $prefix.'ей',
404 1
                        static::PREDLOJ => $prefix.'и',
405 1
                        static::LOCATIVE => $prefix.'и',
406
                    ];
407
408 20
                case 'а':
409
                    // Москва, Рига
410 5
                    $prefix = S::name(S::slice($name, 0, -1));
411
                    return [
412 5
                        static::IMENIT => $prefix.'а',
413 5
                        static::RODIT => $prefix.(static::isVelarConsonant(S::slice($name, -2, -1)) || static::isHissingConsonant(S::slice($name, -2, -1)) ? 'и' : 'ы'),
414 5
                        static::DAT => $prefix.'е',
415 5
                        static::VINIT => $prefix.'у',
416 5
                        static::TVORIT => $prefix.'ой',
417 5
                        static::PREDLOJ => $prefix.'е',
418 5
                        static::LOCATIVE => $prefix.'е',
419
                    ];
420
421 15
                case 'й':
422
                    // Ишимбай
423 2
                    $prefix = S::name(S::slice($name, 0, -1));
424
                    return [
425 2
                        static::IMENIT => $prefix . 'й',
426 2
                        static::RODIT => $prefix . 'я',
427 2
                        static::DAT => $prefix . 'ю',
428 2
                        static::VINIT => $prefix . 'й',
429 2
                        static::TVORIT => $prefix . 'ем',
430 2
                        static::PREDLOJ => $prefix . 'е',
431 2
                        static::LOCATIVE => $prefix . 'е',
432
                    ];
433
            }
434
435 13
            if (static::isConsonant(S::slice($name,  -1)) && !in_array($name, static::$ovAbnormalExceptions, true)) {
436 12
                $runaway_vowels_list = static::getRunAwayVowelsList();
437
438
                // if run-away vowel in name
439 12
                if (isset($runaway_vowels_list[$name])) {
440 4
                    $runaway_vowel_offset = $runaway_vowels_list[$name];
441 4
                    $prefix = S::name(S::slice($name, 0, $runaway_vowel_offset) . S::slice($name, $runaway_vowel_offset + 1));
442
                } else {
443 8
                    $prefix = S::name($name);
444
                }
445
446
                // Париж, Валаам, Киев
447
                return [
448 12
                    static::IMENIT => S::name($name),
449 12
                    static::RODIT => $prefix . 'а',
450 12
                    static::DAT => $prefix . 'у',
451 12
                    static::VINIT => S::name($name),
452 12
                    static::TVORIT => $prefix . (static::isVelarConsonant(S::slice($name, -2, -1)) ? 'ем' : 'ом'),
453 12
                    static::PREDLOJ => $prefix . 'е',
454 12
                    static::LOCATIVE => $prefix.($name === 'крым' ? 'у' : 'е'),
455
                ];
456
            }
457
458
            // ов, ово, ёв, ёво, ев, ево, ...
459 2
            $suffixes = ['ов', 'ёв', 'ев', 'ин', 'ын'];
460 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)) {
461
                // ово, ёво, ...
462 1
                if (in_array(S::slice($name, -3, -1), $suffixes, true)) {
463
                    $prefix = S::name(S::slice($name, 0, -1));
464
                }
465
                // ов, её, ...
466 1
                elseif (in_array(S::slice($name, -2), $suffixes, true)) {
467 1
                    $prefix = S::name($name);
468
                }
469
470
                return [
471 1
                    static::IMENIT => S::name($name),
472 1
                    static::RODIT => $prefix.'а',
473 1
                    static::DAT => $prefix.'у',
474 1
                    static::VINIT => S::name($name),
475 1
                    static::TVORIT => $prefix.'ым',
476 1
                    static::PREDLOJ => $prefix.'е',
477 1
                    static::LOCATIVE => $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(
485 3
            [static::IMENIT, static::RODIT, static::DAT, static::VINIT, static::TVORIT, static::PREDLOJ, static::LOCATIVE],
486 3
        $name);
487
    }
488
489
    /**
490
     * Получение одной формы (падежа) названия.
491
     * @param string $name  Название
492
     * @param integer $case Падеж. Одна из констант \morphos\Russian\Cases или \morphos\Cases.
493
     * @see \morphos\Russian\Cases
494
     * @return string
495
     * @throws \Exception
496
     */
497
    public static function getCase($name, $case)
498
    {
499
        $case = static::canonizeCase($case);
500
        $forms = static::getCases($name);
501
        return $forms[$case];
502
    }
503
}
504