Completed
Push — 2.1.x ( 7ab7e8 )
by f
23:20
created

GeneralDeclension   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 231
Duplicated Lines 4.76 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 11
loc 231
rs 8.439
c 0
b 0
f 0
wmc 47
lcom 1
cbo 2

12 Methods

Rating   Name   Duplication   Size   Complexity  
A hasForms() 0 3 1
B getDeclension() 0 11 8
A getForms() 0 11 4
C declinateFirstDeclension() 0 42 8
B declinateSecondDeclension() 0 34 2
A declinateThirdDeclension() 0 12 1
C pluralizeAllDeclensions() 11 44 11
A getForm() 0 4 1
A getPrefixOfFirstDeclension() 0 7 2
A getVinitCaseByAnimateness() 0 6 2
A getPredCaseOf12Declensions() 0 10 3
A chooseVowelAfterConsonant() 0 7 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like GeneralDeclension often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use GeneralDeclension, and based on these observations, apply Extract Interface, too.

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