Completed
Push — master ( 2c1e58...2722e4 )
by f
02:18
created

GeneralDeclension::declinateFirstDeclension()   B

Complexity

Conditions 4
Paths 2

Size

Total Lines 34
Code Lines 16

Duplication

Lines 5
Ratio 14.71 %

Importance

Changes 0
Metric Value
cc 4
eloc 16
nc 2
nop 1
dl 5
loc 34
rs 8.5806
c 0
b 0
f 0
1
<?php
2
namespace morphos\Russian;
3
4
/**
5
 * Rules are from http://morpher.ru/Russian/Noun.aspx
6
 */
7
class GeneralDeclension extends \morphos\GeneralDeclension implements Cases {
8
	use RussianLanguage, CasesHelper;
9
10
	const FIRST_DECLENSION = 1;
11
	const SECOND_DECLENSION = 2;
12
	const THIRD_DECLENSION = 3;
13
14
	protected $abnormalExceptions = array(
15
		'бремя',
16
		'вымя',
17
		'темя',
18
		'пламя',
19
		'стремя',
20
		'пламя',
21
		'время',
22
		'знамя',
23
		'имя',
24
		'племя',
25
		'семя',
26
	);
27
28
	static protected $masculineWithSoft = array(
29
		'камень',
30
		'олень',
31
		'конь',
32
		'ячмень',
33
		'путь',
34
		'парень',
35
		'зверь',
36
		'шкворень',
37
		'пень',
38
		'пельмень',
39
		'тюлень',
40
		'выхухоль',
41
		'табель',
42
		'рояль',
43
		'шампунь',
44
		'конь',
45
		'лось',
46
		'гвоздь',
47
		'медведь',
48
		'день',
49
		'рубль',
50
	);
51
52
	static protected $immutableWords = array(
53
		'евро',
54
		'пенни',
55
	);
56
57
	public function isMutable($word, $animateness = false) {
58
		$word = lower($word);
59
		if (in_array(slice($word, -1), array('у', 'и', 'е', 'о', 'ю')) || in_array($word, self::$immutableWords))
60
			return false;
61
		return true;
62
	}
63
64
	static public function getDeclension($word) {
65
		$word = lower($word);
66
		$last = slice($word, -1);
67
		if (in_array($last, ['а', 'я']) && slice($word, -2) != 'мя') {
68
			return 1;
69
		} else if (self::isConsonant($last) || in_array($last, ['о', 'е', 'ё']) || ($last == 'ь' && self::isConsonant(slice($word, -2, -1)) && !RussianLanguage::isHissingConsonant(slice($word, -2, -1)) && in_array($word, self::$masculineWithSoft))) {
70
			return 2;
71
		} else {
72
			return 3;
73
		}
74
	}
75
76
	public function getCases($word, $animateness = false) {
77
		$word = lower($word);
78
79
		if (in_array($word, self::$immutableWords)) {
80
			return array(
81
				self::IMENIT => $word,
82
				self::RODIT => $word,
83
				self::DAT => $word,
84
				self::VINIT => $word,
85
				self::TVORIT => $word,
86
				self::PREDLOJ => $this->choosePrepositionByFirstLetter($word, 'об', 'о').' '.$word,
87
			);
88
		} else if (isset($this->abnormalExceptions[$word])) {
89
			$prefix = slice($word, -1);
90
			return array(
91
				self::IMENIT => $word,
92
				self::RODIT => $prefix.'и',
93
				self::DAT => $prefix.'и',
94
				self::VINIT => $word,
95
				self::TVORIT => $prefix,
96
				self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'и',
97
			);
98
		}
99
100
		switch (self::getDeclension($word)) {
101
			case self::FIRST_DECLENSION:
102
				return $this->declinateFirstDeclension($word);
103
			case self::SECOND_DECLENSION:
104
				return $this->declinateSecondDeclension($word, $animateness);
105
			case self::THIRD_DECLENSION:
106
				return $this->declinateThirdDeclension($word);
107
		}
108
	}
109
110
	public function declinateFirstDeclension($word) {
111
		$word = lower($word);
112
		$prefix = slice($word, 0, -1);
113
		$last = slice($word, -1);
114
		$soft_last = $this->checkLastConsonantSoftness($word);
115
		$forms =  array(
116
			Cases::IMENIT => $word,
117
		);
118
119
		// RODIT
120
		$forms[Cases::RODIT] = $this->chooseVowelAfterConsonant($last, $soft_last || (in_array(slice($word, -2, -1), array('г', 'к', 'х'))), $prefix.'и', $prefix.'ы');
121
122
		// DAT
123
		$forms[Cases::DAT] = self::getPredCaseOf12Declensions($word, $last, $prefix);
124
125
		// VINIT
126
		$forms[Cases::VINIT] = $this->chooseVowelAfterConsonant($last, $soft_last && slice($word, -2, -1) != 'ч', $prefix.'ю', $prefix.'у');
127
128
		// TVORIT
129 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...
130
			$forms[Cases::TVORIT] = $prefix.'ой';
131
		else {
132
			$forms[Cases::TVORIT] = $this->chooseVowelAfterConsonant($last, $soft_last, $prefix.'ей', $prefix.'ой');
133
		}
134
135
		// 	if ($last == 'й' || (self::isConsonant($last) && !RussianLanguage::isHissingConsonant($last)) || $this->checkLastConsonantSoftness($word))
136
		// 	$forms[Cases::TVORIT] = $prefix.'ей';
137
		// else
138
		// 	$forms[Cases::TVORIT] = $prefix.'ой'; # http://morpher.ru/Russian/Spelling.aspx#sibilant
139
140
		// PREDLOJ the same as DAT
141
		$forms[Cases::PREDLOJ] = $this->choosePrepositionByFirstLetter($forms[Cases::DAT], 'об', 'о').' '.$forms[Cases::DAT];
142
		return $forms;
143
	}
144
145
	public function declinateSecondDeclension($word, $animateness = false) {
146
		$word = lower($word);
147
		$last = slice($word, -1);
148
		$soft_last = $last == 'й' || (in_array($last, ['ь', 'е', 'ё', 'ю', 'я']) && (self::isConsonant(slice($word, -2, -1)) || slice($word, -2, -1) == 'и'));
149
		$prefix = self::getPrefixOfFirstDeclension($word, $last);
150
		$forms =  array(
151
			Cases::IMENIT => $word,
152
		);
153
154
		// RODIT
155
		$forms[Cases::RODIT] = $this->chooseVowelAfterConsonant($last, $soft_last, $prefix.'я', $prefix.'а');
156
157
		// DAT
158
		$forms[Cases::DAT] = $this->chooseVowelAfterConsonant($last, $soft_last, $prefix.'ю', $prefix.'у');
159
160
		// VINIT
161
		if (in_array($last, ['о', 'е', 'ё']))
162
			$forms[Cases::VINIT] = $word;
163
		else {
164
			$forms[Cases::VINIT] = self::getVinitCaseByAnimateness($forms, $animateness);
165
		}
166
167
		// TVORIT
168
		// if ($last == 'ь')
169
		// 	$forms[Cases::TVORIT] = $prefix.'ом';
170
		// else if ($last == 'й' || (self::isConsonant($last) && !RussianLanguage::isHissingConsonant($last)))
171
		// 	$forms[Cases::TVORIT] = $prefix.'ем';
172
		// else
173
		// 	$forms[Cases::TVORIT] = $prefix.'ом'; # http://morpher.ru/Russian/Spelling.aspx#sibilant
174
		if (RussianLanguage::isHissingConsonant($last) || $last == 'ц') {
175
			$forms[Cases::TVORIT] = $prefix.'ем';
176
		} else if (in_array($last, ['й'/*, 'ч', 'щ'*/]) || $soft_last) {
177
			$forms[Cases::TVORIT] = $prefix.'ем';
178
		} else {
179
			$forms[Cases::TVORIT] = $prefix.'ом';
180
		}
181
182
		// PREDLOJ
183
		$forms[Cases::PREDLOJ] = self::getPredCaseOf12Declensions($word, $last, $prefix);
184
		$forms[Cases::PREDLOJ] = $this->choosePrepositionByFirstLetter($forms[Cases::PREDLOJ], 'об', 'о').' '.$forms[Cases::PREDLOJ];
185
186
		return $forms;
187
	}
188
189
	public function declinateThirdDeclension($word) {
190
		$word = lower($word);
191
		$prefix = slice($word, 0, -1);
192
		return array(
193
			Cases::IMENIT => $word,
194
			Cases::RODIT => $prefix.'и',
195
			Cases::DAT => $prefix.'и',
196
			Cases::VINIT => $word,
197
			Cases::TVORIT => $prefix.'ью',
198
			Cases::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'и',
199
		);
200
	}
201
202
	public function getCase($word, $case, $animateness = false) {
203
		$case = self::canonizeCase($case);
204
		$forms = $this->getCases($word, $animateness);
205
		return $forms[$case];
206
	}
207
208
	static public function getPrefixOfFirstDeclension($word, $last) {
209
		if ($word == 'день')
210
			$prefix = 'дн';
211
		else if (in_array($last, ['о', 'е', 'ё', 'ь', 'й']))
212
			$prefix = slice($word, 0, -1);
213
		else
214
			$prefix = $word;
215
		return $prefix;
216
	}
217
218
	static public function getVinitCaseByAnimateness(array $forms, $animate) {
219
		if ($animate)
220
			return $forms[Cases::RODIT];
221
		else
222
			return $forms[Cases::IMENIT];
223
	}
224
225
	static public function getPredCaseOf12Declensions($word, $last, $prefix) {
226
		if (slice($word, -2) == 'ий') {
227
			if ($last == 'ё')
228
				return $prefix.'е';
229
			else
230
				return $prefix.'и';
231
		} else {
232
			return $prefix.'е';
233
		}
234
	}
235
}
236