Completed
Push — master ( 09400a...df0401 )
by f
01:58
created

GeneralDeclension   B

Complexity

Total Complexity 36

Size/Duplication

Total Lines 214
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 0
loc 214
rs 8.8
c 0
b 0
f 0
wmc 36
lcom 1
cbo 2

10 Methods

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