Completed
Push — master ( 708613...9f9161 )
by f
01:19
created

NounPluralization::declinateSubstative()   F

Complexity

Conditions 35
Paths 1008

Size

Total Lines 81
Code Lines 56

Duplication

Lines 12
Ratio 14.81 %

Importance

Changes 0
Metric Value
cc 35
eloc 56
nc 1008
nop 2
dl 12
loc 81
rs 2.4009
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 http://morpher.ru/Russian/Noun.aspx
8
 */
9
class NounPluralization extends \morphos\NounPluralization implements Cases
10
{
11
    use RussianLanguage, CasesHelper;
12
13
    const ONE = 1;
14
    const TWO_FOUR = 2;
15
    const FIVE_OTHER = 3;
16
17
    protected static $neuterExceptions = array(
18
        'поле',
19
        'море',
20
    );
21
22
    protected static $genitiveExceptions = array(
23
        'письмо' => 'писем',
24
        'пятно' => 'пятен',
25
        'кресло' => 'кресел',
26
        'коромысло' => 'коромысел',
27
        'ядро' => 'ядер',
28
        'блюдце' => 'блюдец',
29
        'полотенце' => 'полотенец',
30
    );
31
32
    protected static $immutableWords = array(
33
        'евро',
34
        'пенни',
35
    );
36
37
    protected static $runawayVowelsExceptions = array(
38
        'писе*ц',
39
        'песе*ц',
40
        'глото*к',
41
    );
42
43
    protected static $runawayVowelsNormalized = false;
44
45
    protected static function getRunAwayVowelsList()
46
    {
47
        if (self::$runawayVowelsNormalized === false) {
48
            self::$runawayVowelsNormalized = array();
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type boolean of property $runawayVowelsNormalized.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
49
            foreach (self::$runawayVowelsExceptions as $word) {
50
                self::$runawayVowelsNormalized[str_replace('*', null, $word)] = S::indexOf($word, '*') - 1;
51
            }
52
        }
53
        return self::$runawayVowelsNormalized;
54
    }
55
56
    public static function pluralize($word, $count = 2, $animateness = false)
57
    {
58
        switch (self::getNumeralForm($count)) {
59
            case self::ONE:
60
                return $word;
61
            case self::TWO_FOUR:
62
                return NounDeclension::getCase($word, self::RODIT, $animateness);
63
            case self::FIVE_OTHER:
64
                return NounPluralization::getCase($word, self::RODIT, $animateness);
65
        }
66
    }
67
68
    public static function getNumeralForm($count)
69
    {
70
        if ($count > 100) {
71
            $count %= 100;
72
        }
73
        $ending = $count % 10;
74
        if (($count > 20 && $ending == 1) || $count == 1) {
75
            return self::ONE;
76
        } elseif (($count > 20 && in_array($ending, range(2, 4))) || in_array($count, range(2, 4))) {
77
            return self::TWO_FOUR;
78
        } else {
79
            return self::FIVE_OTHER;
80
        }
81
    }
82
83
    public static function getCase($word, $case, $animateness = false)
84
    {
85
        $case = self::canonizeCase($case);
86
        $forms = self::getCases($word, $animateness);
87
        return $forms[$case];
88
    }
89
90
    public static function getCases($word, $animateness = false)
91
    {
92
        $word = S::lower($word);
93
94
        if (in_array($word, self::$immutableWords)) {
95
            return array(
96
                self::IMENIT => $word,
97
                self::RODIT => $word,
98
                self::DAT => $word,
99
                self::VINIT => $word,
100
                self::TVORIT => $word,
101
                self::PREDLOJ => self::choosePrepositionByFirstLetter($word, 'об', 'о').' '.$word,
102
            );
103
        }
104
105
        // Адъективное склонение (Сущ, образованные от прилагательных и причастий) - прохожий, существительное
106 View Code Duplication
        if (in_array(S::slice($word, -2), array('ой', 'ий', 'ый', 'ая', 'ое', 'ее')) && $word != 'гений') {
0 ignored issues
show
Duplication introduced by
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...
107
            return self::declinateAdjective($word, $animateness);
108
        }
109
110
        // Субстантивное склонение (существительные)
111
        return self::declinateSubstative($word, $animateness);
112
    }
113
114
    protected static function declinateSubstative($word, $animateness)
115
    {
116
        $prefix = S::slice($word, 0, -1);
117
        $last = S::slice($word, -1);
118
119
        $runaway_vowels_list = static::getRunAwayVowelsList();
120
        if (isset($runaway_vowels_list[$word])) {
121
            $vowel_offset = $runaway_vowels_list[$word];
122
            $word = S::slice($word, 0, $vowel_offset) . S::slice($word, $vowel_offset + 1);
123
        }
124
125
        if (($declension = NounDeclension::getDeclension($word)) == NounDeclension::SECOND_DECLENSION) {
126
            $soft_last = $last == 'й' || (in_array($last, ['ь', 'е', 'ё', 'ю', 'я']) && ((self::isConsonant(S::slice($word, -2, -1)) && !self::isHissingConsonant(S::slice($word, -2, -1))) || S::slice($word, -2, -1) == 'и'));
127
            $prefix = NounDeclension::getPrefixOfSecondDeclension($word, $last);
128
        } elseif ($declension == NounDeclension::FIRST_DECLENSION) {
129
            $soft_last = self::checkLastConsonantSoftness($word);
130
        } else {
131
            $soft_last = S::slice($word, -2) == 'сь';
132
        }
133
134
        $forms = array();
135
136
        if ($last == 'ч' || in_array(S::slice($word, -2), array('чь', 'сь')) || (self::isVowel($last) && in_array(S::slice($word, -2, -1), array('ч', 'к')))) { // before ч, чь, сь, ч+vowel, к+vowel
137
            $forms[Cases::IMENIT] = $prefix.'и';
138
        } elseif ($last == 'н' || $last == 'ц') {
139
            $forms[Cases::IMENIT] = $prefix.'ы';
140 View Code Duplication
        } else {
0 ignored issues
show
Duplication introduced by
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...
141
            $forms[Cases::IMENIT] = self::chooseVowelAfterConsonant($last, $soft_last, $prefix.'я', $prefix.'а');
142
        }
143
144
        // RODIT
145
        if (isset(self::$genitiveExceptions[$word])) {
146
            $forms[Cases::RODIT] = self::$genitiveExceptions[$word];
147
        } elseif (in_array($last, array('о', 'е'))) {
148
            // exceptions
149
            if (in_array($word, self::$neuterExceptions)) {
150
                $forms[Cases::RODIT] = $prefix.'ей';
151 View Code Duplication
            } elseif (S::slice($word, -2, -1) == 'и') {
0 ignored issues
show
Duplication introduced by
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...
152
                $forms[Cases::RODIT] = $prefix.'й';
153
            } else {
154
                $forms[Cases::RODIT] = $prefix;
155
            }
156
        } elseif (S::slice($word, -2) == 'ка') { // words ending with -ка: чашка, вилка, ложка, тарелка, копейка, батарейка
157
            if (S::slice($word, -3, -2) == 'л') {
158
                $forms[Cases::RODIT] = S::slice($word, 0, -2).'ок';
159 View Code Duplication
            } elseif (S::slice($word, -3, -2) == 'й') {
0 ignored issues
show
Duplication introduced by
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...
160
                $forms[Cases::RODIT] = S::slice($word, 0, -3).'ек';
161
            } else {
162
                $forms[Cases::RODIT] = S::slice($word, 0, -2).'ек';
163
            }
164
        } elseif (in_array($last, array('а'))) { // обида, ябеда
165
            $forms[Cases::RODIT] = $prefix;
166
        } elseif (in_array($last, array('я'))) { // молния
167
            $forms[Cases::RODIT] = $prefix.'й';
168
        } elseif (RussianLanguage::isHissingConsonant($last) || ($soft_last && $last != 'й') || in_array(S::slice($word, -2), array('чь', 'сь'))) {
169
            $forms[Cases::RODIT] = $prefix.'ей';
170 View Code Duplication
        } elseif ($last == 'й' || S::slice($word, -2) == 'яц') { // месяц
0 ignored issues
show
Duplication introduced by
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...
171
            $forms[Cases::RODIT] = $prefix.'ев';
172
        } else { // (self::isConsonant($last) && !RussianLanguage::isHissingConsonant($last))
173
            $forms[Cases::RODIT] = $prefix.'ов';
174
        }
175
176
        // DAT
177
        $forms[Cases::DAT] = self::chooseVowelAfterConsonant($last, $soft_last && S::slice($word, -2, -1) != 'ч', $prefix.'ям', $prefix.'ам');
178
179
        // VINIT
180
        $forms[Cases::VINIT] = NounDeclension::getVinitCaseByAnimateness($forms, $animateness);
181
182
        // TVORIT
183
        // my personal rule
184
        if ($last == 'ь' && $declension == NounDeclension::THIRD_DECLENSION && !in_array(S::slice($word, -2), array('чь', 'сь'))) {
185
            $forms[Cases::TVORIT] = $prefix.'ми';
186
        } else {
187
            $forms[Cases::TVORIT] = self::chooseVowelAfterConsonant($last, $soft_last && S::slice($word, -2, -1) != 'ч', $prefix.'ями', $prefix.'ами');
188
        }
189
190
        // PREDLOJ
191
        $forms[Cases::PREDLOJ] = self::chooseVowelAfterConsonant($last, $soft_last && S::slice($word, -2, -1) != 'ч', $prefix.'ях', $prefix.'ах');
192
        $forms[Cases::PREDLOJ] = self::choosePrepositionByFirstLetter($forms[Cases::PREDLOJ], 'об', 'о').' '.$forms[Cases::PREDLOJ];
193
        return $forms;
194
    }
195
196
    /**
197
     * Rules are from http://rusgram.narod.ru/1216-1231.html
198
     */
199
    protected static function declinateAdjective($word, $animateness)
200
    {
201
        $prefix = S::slice($word, 0, -2);
202
        $vowel = self::isHissingConsonant(S::slice($prefix, -1)) ? 'и' : 'ы';
203
        return array(
204
            Cases::IMENIT => $prefix.$vowel.'е',
205
            Cases::RODIT => $prefix.$vowel.'х',
206
            Cases::DAT => $prefix.$vowel.'м',
207
            Cases::VINIT => $prefix.$vowel.($animateness ? 'х' : 'е'),
208
            Cases::TVORIT => $prefix.$vowel.'ми',
209
            Cases::PREDLOJ => self::choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.$vowel.'х',
210
        );
211
    }
212
}
213