Completed
Push — master ( 4465f9...18b3df )
by f
01:08
created

GeneralDeclension::declinateSecondDeclension()   C

Complexity

Conditions 12
Paths 30

Size

Total Lines 43
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 22
nc 30
nop 2
dl 0
loc 43
rs 5.1612
c 0
b 0
f 0

How to fix   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 GeneralDeclension extends \morphos\GeneralDeclension implements Cases {
10
	use RussianLanguage, CasesHelper;
11
12
	const FIRST_DECLENSION = 1;
13
	const SECOND_DECLENSION = 2;
14
	const THIRD_DECLENSION = 3;
15
16
	/**
17
	 * These words has 2 declension type.
18
	 */
19
	static protected $abnormalExceptions = array(
20
		'бремя',
21
		'вымя',
22
		'темя',
23
		'пламя',
24
		'стремя',
25
		'пламя',
26
		'время',
27
		'знамя',
28
		'имя',
29
		'племя',
30
		'семя',
31
		'путь' => array('путь', 'пути', 'пути', 'путь', 'путем', 'о пути'),
32
		'дитя' => array('дитя', 'дитяти', 'дитяти', 'дитя', 'дитятей', 'о дитяти')
33
	);
34
35
	static protected $masculineWithSoft = array(
36
		'олень',
37
		'конь',
38
		'ячмень',
39
		'путь',
40
		'зверь',
41
		'шкворень',
42
		'пельмень',
43
		'тюлень',
44
		'выхухоль',
45
		'табель',
46
		'рояль',
47
		'шампунь',
48
		'конь',
49
		'лось',
50
		'гвоздь',
51
		'медведь',
52
		'рубль',
53
		'дождь',
54
	);
55
56
	static protected $masculineWithSoftAndRunAwayVowels = array(
57
		'день',
58
		'пень',
59
		'парень',
60
		'камень',
61
		'корень',
62
		'трутень',
63
	);
64
65
	static protected $immutableWords = array(
66
		'евро',
67
		'пенни',
68
	);
69
70
	static public function isMutable($word, $animateness = false) {
0 ignored issues
show
Unused Code introduced by
The parameter $animateness is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
71
		$word = S::lower($word);
72 View Code Duplication
		if (in_array(S::slice($word, -1), array('у', 'и', 'е', 'о', 'ю')) || in_array($word, self::$immutableWords))
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...
73
			return false;
74
		return true;
75
	}
76
77
	static public function getDeclension($word) {
78
		$word = S::lower($word);
79
		$last = S::slice($word, -1);
80
		if (isset(self::$abnormalExceptions[$word]) || in_array($word, self::$abnormalExceptions))
81
			return 2;
82
83
		if (in_array($last, ['а', 'я']) && S::slice($word, -2) != 'мя') {
84
			return 1;
85
		} else if (self::isConsonant($last) || in_array($last, ['о', 'е', 'ё']) || ($last == 'ь' && self::isConsonant(S::slice($word, -2, -1)) && !self::isHissingConsonant(S::slice($word, -2, -1)) && (in_array($word, self::$masculineWithSoft)) || in_array($word, self::$masculineWithSoftAndRunAwayVowels))) {
86
			return 2;
87
		} else {
88
			return 3;
89
		}
90
	}
91
92
	static public function getCases($word, $animateness = false) {
93
		$word = S::lower($word);
94
95
		// Адъективное склонение (Сущ, образованные от прилагательных и причастий) - прохожий, существительное
96
		if (in_array(S::slice($word, -2), array('ой', 'ий', 'ый', 'ая', 'ое', 'ее')) && $word != 'гений') {
97
			return self::declinateAdjective($word, $animateness);
98
		}
99
100
		// Субстантивное склонение (существительные)
101
		if (in_array($word, self::$immutableWords)) {
102
			return array(
103
				self::IMENIT => $word,
104
				self::RODIT => $word,
105
				self::DAT => $word,
106
				self::VINIT => $word,
107
				self::TVORIT => $word,
108
				self::PREDLOJ => self::choosePrepositionByFirstLetter($word, 'об', 'о').' '.$word,
109
			);
110
		} else if (isset(self::$abnormalExceptions[$word])) {
111
			return array_combine(array(self::IMENIT, self::RODIT, self::DAT, self::VINIT, self::TVORIT, self::PREDLOJ), self::$abnormalExceptions[$word]);
112
		} else if (in_array($word, self::$abnormalExceptions)) {
113
			$prefix = S::slice($word, 0, -1);
114
			return array(
115
				self::IMENIT => $word,
116
				self::RODIT => $prefix.'ени',
117
				self::DAT => $prefix.'ени',
118
				self::VINIT => $word,
119
				self::TVORIT => $prefix.'енем',
120
				self::PREDLOJ => self::choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'ени',
121
			);
122
		}
123
124
		switch (self::getDeclension($word)) {
125
			case self::FIRST_DECLENSION:
126
				return self::declinateFirstDeclension($word);
127
			case self::SECOND_DECLENSION:
128
				return self::declinateSecondDeclension($word, $animateness);
129
			case self::THIRD_DECLENSION:
130
				return self::declinateThirdDeclension($word);
131
		}
132
	}
133
134
	static public function declinateFirstDeclension($word) {
135
		$word = S::lower($word);
136
		$prefix = S::slice($word, 0, -1);
137
		$last = S::slice($word, -1);
138
		$soft_last = self::checkLastConsonantSoftness($word);
139
		$forms =  array(
140
			Cases::IMENIT => $word,
141
		);
142
143
		// RODIT
144
		$forms[Cases::RODIT] = self::chooseVowelAfterConsonant($last, $soft_last || (in_array(S::slice($word, -2, -1), array('г', 'к', 'х'))), $prefix.'и', $prefix.'ы');
145
146
		// DAT
147
		$forms[Cases::DAT] = self::getPredCaseOf12Declensions($word, $last, $prefix);
148
149
		// VINIT
150
		$forms[Cases::VINIT] = self::chooseVowelAfterConsonant($last, $soft_last && S::slice($word, -2, -1) != 'ч', $prefix.'ю', $prefix.'у');
151
152
		// TVORIT
153 View Code Duplication
		if ($last == 'ь')
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...
154
			$forms[Cases::TVORIT] = $prefix.'ой';
155
		else {
156
			$forms[Cases::TVORIT] = self::chooseVowelAfterConsonant($last, $soft_last, $prefix.'ей', $prefix.'ой');
157
		}
158
159
		// 	if ($last == 'й' || (self::isConsonant($last) && !self::isHissingConsonant($last)) || self::checkLastConsonantSoftness($word))
160
		// 	$forms[Cases::TVORIT] = $prefix.'ей';
161
		// else
162
		// 	$forms[Cases::TVORIT] = $prefix.'ой'; # http://morpher.ru/Russian/Spelling.aspx#sibilant
163
164
		// PREDLOJ the same as DAT
165
		$forms[Cases::PREDLOJ] = self::choosePrepositionByFirstLetter($forms[Cases::DAT], 'об', 'о').' '.$forms[Cases::DAT];
166
		return $forms;
167
	}
168
169
	static public function declinateSecondDeclension($word, $animateness = false) {
170
		$word = S::lower($word);
171
		$last = S::slice($word, -1);
172
		$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) == 'и'));
173
		$prefix = self::getPrefixOfSecondDeclension($word, $last);
174
		$forms =  array(
175
			Cases::IMENIT => $word,
176
		);
177
178
		// RODIT
179
		$forms[Cases::RODIT] = self::chooseVowelAfterConsonant($last, $soft_last, $prefix.'я', $prefix.'а');
180
181
		// DAT
182
		$forms[Cases::DAT] = self::chooseVowelAfterConsonant($last, $soft_last, $prefix.'ю', $prefix.'у');
183
184
		// VINIT
185
		if (in_array($last, ['о', 'е', 'ё']))
186
			$forms[Cases::VINIT] = $word;
187
		else {
188
			$forms[Cases::VINIT] = self::getVinitCaseByAnimateness($forms, $animateness);
189
		}
190
191
		// TVORIT
192
		// if ($last == 'ь')
193
		// 	$forms[Cases::TVORIT] = $prefix.'ом';
194
		// else if ($last == 'й' || (self::isConsonant($last) && !self::isHissingConsonant($last)))
195
		// 	$forms[Cases::TVORIT] = $prefix.'ем';
196
		// else
197
		// 	$forms[Cases::TVORIT] = $prefix.'ом'; # http://morpher.ru/Russian/Spelling.aspx#sibilant
198
		if (self::isHissingConsonant($last) || (in_array($last, ['ь', 'е', 'ё', 'ю', 'я']) && self::isHissingConsonant(S::slice($word, -2, -1))) || $last == 'ц') {
199
			$forms[Cases::TVORIT] = $prefix.'ем';
200
		} else if (in_array($last, ['й'/*, 'ч', 'щ'*/]) || $soft_last) {
201
			$forms[Cases::TVORIT] = $prefix.'ем';
202
		} else {
203
			$forms[Cases::TVORIT] = $prefix.'ом';
204
		}
205
206
		// PREDLOJ
207
		$forms[Cases::PREDLOJ] = self::getPredCaseOf12Declensions($word, $last, $prefix);
208
		$forms[Cases::PREDLOJ] = self::choosePrepositionByFirstLetter($forms[Cases::PREDLOJ], 'об', 'о').' '.$forms[Cases::PREDLOJ];
209
210
		return $forms;
211
	}
212
213
	static public function declinateThirdDeclension($word) {
214
		$word = S::lower($word);
215
		$prefix = S::slice($word, 0, -1);
216
		return array(
217
			Cases::IMENIT => $word,
218
			Cases::RODIT => $prefix.'и',
219
			Cases::DAT => $prefix.'и',
220
			Cases::VINIT => $word,
221
			Cases::TVORIT => $prefix.'ью',
222
			Cases::PREDLOJ => self::choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'и',
223
		);
224
	}
225
226
	/**
227
	 * Rules are from http://rusgram.narod.ru/1216-1231.html
228
	 */
229
	static public function declinateAdjective($word, $animateness) {
0 ignored issues
show
Unused Code introduced by
The parameter $animateness is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
230
		$prefix = S::slice($word, 0, -2);
0 ignored issues
show
Unused Code introduced by
$prefix is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
231
232
		switch (S::slice($word, -2)) {
233
			// Male adjectives
234
			case 'ой':
235 View Code Duplication
			case 'ый':
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...
236
				$prefix = S::slice($word, 0, -2);
237
				return array(
238
					Cases::IMENIT => $word,
239
					Cases::RODIT => $prefix.'ого',
240
					Cases::DAT => $prefix.'ому',
241
					Cases::VINIT => $word,
242
					Cases::TVORIT => $prefix.'ым',
243
					Cases::PREDLOJ => self::choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'ом',
244
				);
245
246 View Code Duplication
			case 'ий':
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...
247
				$prefix = S::slice($word, 0, -2);
248
				return array(
249
					Cases::IMENIT => $word,
250
					Cases::RODIT => $prefix.'его',
251
					Cases::DAT => $prefix.'ему',
252
					Cases::VINIT => $prefix.'его',
253
					Cases::TVORIT => $prefix.'им',
254
					Cases::PREDLOJ => self::choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'ем',
255
				);
256
257
			// Neuter adjectives
258
			case 'ое':
259
			case 'ее':
260
				$prefix = S::slice($word, 0, -1);
261
				return array(
262
					Cases::IMENIT => $word,
263
					Cases::RODIT => $prefix.'го',
264
					Cases::DAT => $prefix.'му',
265
					Cases::VINIT => $word,
266
					Cases::TVORIT => S::slice($word, 0, -2).(S::slice($word, -2, -1) == 'о' ? 'ы' : 'и').'м',
267
					Cases::PREDLOJ => self::choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'м',
268
				);
269
270
			// Female adjectives
271
			case 'ая':
272
				$prefix = S::slice($word, 0, -2);
273
				$ending = self::isHissingConsonant(S::slice($prefix, -1)) ? 'ей' : 'ой';
274
				return array(
275
					Cases::IMENIT => $word,
276
					Cases::RODIT => $prefix.$ending,
277
					Cases::DAT => $prefix.$ending,
278
					Cases::VINIT => $prefix.'ую',
279
					Cases::TVORIT => $prefix.$ending,
280
					Cases::PREDLOJ => self::choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.$ending,
281
				);
282
		}
283
	}
284
285
	static public function getCase($word, $case, $animateness = false) {
286
		$case = self::canonizeCase($case);
287
		$forms = self::getCases($word, $animateness);
288
		return $forms[$case];
289
	}
290
291
	static public function getPrefixOfSecondDeclension($word, $last) {
292
		// слова с бегающей гласной в корне
293
		if (in_array($word, self::$masculineWithSoftAndRunAwayVowels))
294
			$prefix = S::slice($word, 0, -3).S::slice($word, -2, -1);
295
		else if (in_array($last, ['о', 'е', 'ё', 'ь', 'й']))
296
			$prefix = S::slice($word, 0, -1);
297
		// уменьшительные формы слов (котенок) и слова с суффиксом ок
298
		else if (S::slice($word, -2) == 'ок' && S::length($word) > 3)
299
			$prefix = S::slice($word, 0, -2).'к';
300
		else
301
			$prefix = $word;
302
		return $prefix;
303
	}
304
305
	static public function getVinitCaseByAnimateness(array $forms, $animate) {
306
		if ($animate)
307
			return $forms[Cases::RODIT];
308
		else
309
			return $forms[Cases::IMENIT];
310
	}
311
312
	static public function getPredCaseOf12Declensions($word, $last, $prefix) {
313
		if (in_array(S::slice($word, -2), array('ий', 'ие'))) {
314
			if ($last == 'ё')
315
				return $prefix.'е';
316
			else
317
				return $prefix.'и';
318
		} else {
319
			return $prefix.'е';
320
		}
321
	}
322
}
323