Completed
Push — master ( 61cac0...2c9208 )
by f
01:55
created

GeneralDeclension::declinateFirstDeclension()   D

Complexity

Conditions 9
Paths 24

Size

Total Lines 43
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 22
nc 24
nop 2
dl 0
loc 43
rs 4.909
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;
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
	);
55
56
	public function hasForms($word, $animateness = false) {
57
		$word = lower($word);
58
		if (in_array(slice($word, -1), array('у', 'и', 'е', 'о', 'ю')))
59
			return false;
60
		return true;
61
	}
62
63
	static public function getDeclension($word) {
64
		$word = lower($word);
65
		$last = slice($word, -1);
66
		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))) {
67
			return  1;
68
		} else if (in_array($last, ['а', 'я']) && slice($word, -2) != 'мя') {
69
			return 2;
70
		} else {
71
			return 3;
72
		}
73
	}
74
75
	public function getForms($word, $animateness = false) {
76
		$word = lower($word);
77
78
		if (isset($this->abnormalExceptions[$word])) {
79
			$prefix = slice($word, -1);
80
			return array(
81
				self::IMENIT => $word,
82
				self::RODIT => $prefix.'и',
83
				self::DAT => $prefix.'и',
84
				self::VINIT => $word,
85
				self::TVORIT => $prefix,
86
				self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'и',
87
			);
88
		}
89
90
		switch (self::getDeclension($word)) {
91
			case self::FIRST_DECLENSION:
92
				return $this->declinateFirstDeclension($word, $animateness);
93
			case self::SECOND_DECLENSION:
94
				return $this->declinateSecondDeclension($word);
95
			case self::THIRD_DECLENSION:
96
				return $this->declinateThirdDeclension($word);
97
		}
98
	}
99
100
	public function declinateFirstDeclension($word, $animateness = false) {
101
		$word = lower($word);
102
		$last = slice($word, -1);
103
		$soft_last = $last == 'й' || (in_array($last, ['ь', 'е', 'ё', 'ю', 'я']) && (self::isConsonant(slice($word, -2, -1)) || slice($word, -2, -1) == 'и'));
104
		$prefix = self::getPrefixOfFirstDeclension($word, $last);
105
		$forms =  array(
106
			Cases::IMENIT_1 => $word,
107
		);
108
109
		// RODIT_2
110
		$forms[Cases::RODIT_2] = $this->chooseVowelAfterConsonant($last, $soft_last, $prefix.'я', $prefix.'а');
111
112
		// DAT_3
113
		$forms[Cases::DAT_3] = $this->chooseVowelAfterConsonant($last, $soft_last, $prefix.'ю', $prefix.'у');
114
115
		// VINIT_4
116
		if (in_array($last, ['о', 'е', 'ё']))
117
			$forms[Cases::VINIT_4] = $word;
118
		else {
119
			$forms[Cases::VINIT_4] = self::getVinitCaseByAnimateness($forms, $animateness);
120
		}
121
122
		// TVORIT_5
123
		// if ($last == 'ь')
124
		// 	$forms[Cases::TVORIT_5] = $prefix.'ом';
125
		// else if ($last == 'й' || (self::isConsonant($last) && !RussianLanguage::isHissingConsonant($last)))
126
		// 	$forms[Cases::TVORIT_5] = $prefix.'ем';
127
		// else
128
		// 	$forms[Cases::TVORIT_5] = $prefix.'ом'; # http://morpher.ru/Russian/Spelling.aspx#sibilant
129
		if (RussianLanguage::isHissingConsonant($last) || $last == 'ц') {
130
			$forms[Cases::TVORIT_5] = $prefix.'ем';
131
		} else if (in_array($last, ['й'/*, 'ч', 'щ'*/]) || $soft_last) {
132
			$forms[Cases::TVORIT_5] = $prefix.'ем';
133
		} else {
134
			$forms[Cases::TVORIT_5] = $prefix.'ом';
135
		}
136
137
		// PREDLOJ_6
138
		$forms[Cases::PREDLOJ_6] = self::getPredCaseOf12Declensions($word, $last, $prefix);
139
		$forms[Cases::PREDLOJ_6] = $this->choosePrepositionByFirstLetter($forms[Cases::PREDLOJ_6], 'об', 'о').' '.$forms[Cases::PREDLOJ_6];
140
141
		return $forms;
142
	}
143
144
	public function declinateSecondDeclension($word) {
145
		$word = lower($word);
146
		$prefix = slice($word, 0, -1);
147
		$last = slice($word, -1);
148
		$soft_last = $this->checkLastConsonantSoftness($word);
149
		$forms =  array(
150
			Cases::IMENIT_1 => $word,
151
		);
152
153
		// RODIT_2
154
		$forms[Cases::RODIT_2] = $this->chooseVowelAfterConsonant($last, $soft_last || (in_array(slice($word, -2, -1), array('г', 'к', 'х'))), $prefix.'и', $prefix.'ы');
155
156
		// DAT_3
157
		$forms[Cases::DAT_3] = self::getPredCaseOf12Declensions($word, $last, $prefix);
158
159
		// VINIT_4
160
		$forms[Cases::VINIT_4] = $this->chooseVowelAfterConsonant($last, $soft_last && slice($word, -2, -1) != 'ч', $prefix.'ю', $prefix.'у');
161
162
		// TVORIT_5
163 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...
164
			$forms[Cases::TVORIT_5] = $prefix.'ой';
165
		else {
166
			$forms[Cases::TVORIT_5] = $this->chooseVowelAfterConsonant($last, $soft_last, $prefix.'ей', $prefix.'ой');
167
		}
168
169
		// 	if ($last == 'й' || (self::isConsonant($last) && !RussianLanguage::isHissingConsonant($last)) || $this->checkLastConsonantSoftness($word))
170
		// 	$forms[Cases::TVORIT_5] = $prefix.'ей';
171
		// else
172
		// 	$forms[Cases::TVORIT_5] = $prefix.'ой'; # http://morpher.ru/Russian/Spelling.aspx#sibilant
173
174
		// PREDLOJ_6 the same as DAT_3
175
		$forms[Cases::PREDLOJ_6] = $this->choosePrepositionByFirstLetter($forms[Cases::DAT_3], 'об', 'о').' '.$forms[Cases::DAT_3];
176
		return $forms;
177
	}
178
179
	public function declinateThirdDeclension($word) {
180
		$word = lower($word);
181
		$prefix = slice($word, 0, -1);
182
		return array(
183
			Cases::IMENIT_1 => $word,
184
			Cases::RODIT_2 => $prefix.'и',
185
			Cases::DAT_3 => $prefix.'и',
186
			Cases::VINIT_4 => $word,
187
			Cases::TVORIT_5 => $prefix.'ью',
188
			Cases::PREDLOJ_6 => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'и',
189
		);
190
	}
191
192
	public function getForm($word, $form, $animateness = false) {
193
		$forms = $this->getForms($word, $animateness);
194
		return $forms[$form];
195
	}
196
197
	static public function getPrefixOfFirstDeclension($word, $last) {
198
		if ($word == 'день')
199
			$prefix = 'дн';
200
		else if (in_array($last, ['о', 'е', 'ё', 'ь', 'й']))
201
			$prefix = slice($word, 0, -1);
202
		else
203
			$prefix = $word;
204
		return $prefix;
205
	}
206
207
	static public function getVinitCaseByAnimateness(array $forms, $animate) {
208
		if ($animate)
209
			return $forms[Cases::RODIT_2];
210
		else
211
			return $forms[Cases::IMENIT_1];
212
	}
213
214
	static public function getPredCaseOf12Declensions($word, $last, $prefix) {
215
		if (slice($word, -2) == 'ий') {
216
			if ($last == 'ё')
217
				return $prefix.'е';
218
			else
219
				return $prefix.'и';
220
		} else {
221
			return $prefix.'е';
222
		}
223
	}
224
}
225