Completed
Push — master ( bc5cbf...29e0b0 )
by f
02:20
created

FirstNamesDeclension::isMutable()   C

Complexity

Conditions 9
Paths 7

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
nc 7
dl 0
loc 22
c 0
b 0
f 0
cc 9
eloc 12
nop 2
rs 6.412
1
<?php
2
namespace morphos\Russian;
3
4
/**
5
 * Rules are from: http://www.imena.org/decl_mn.html
6
 * and http://www.imena.org/decl_fn.html
7
 */
8
class FirstNamesDeclension extends \morphos\NamesDeclension implements Cases {
9
	use RussianLanguage, CasesHelper;
10
11
	protected $exceptions = array(
12
		'лев' => array(
13
			self::IMENIT => 'Лев',
14
			self::RODIT => 'Льва',
15
			self::DAT => 'Льву',
16
			self::VINIT => 'Льва',
17
			self::TVORIT => 'Львом',
18
			self::PREDLOJ => 'о Льве',
19
		),
20
		'павел' => array(
21
			self::IMENIT => 'Павел',
22
			self::RODIT => 'Павла',
23
			self::DAT => 'Павлу',
24
			self::VINIT => 'Павла',
25
			self::TVORIT => 'Павлом',
26
			self::PREDLOJ => 'о Павле',
27
		)
28
	);
29
30
	static protected $menNames = array(
31
		'абрам',
32
		'аверьян',
33
		'авраам',
34
		'агафон',
35
		'адам',
36
		'азар',
37
		'акакий',
38
		'аким',
39
		'аксён',
40
		'александр',
41
		'алексей',
42
		'альберт',
43
		'анатолий',
44
		'андрей',
45
		'андрон',
46
		'антип',
47
		'антон',
48
		'аполлон',
49
		'аристарх',
50
		'аркадий',
51
		'арнольд',
52
		'арсений',
53
		'арсентий',
54
		'артем',
55
		'артём',
56
		'артемий',
57
		'артур',
58
		'аскольд',
59
		'афанасий',
60
		'богдан',
61
		'борис',
62
		'борислав',
63
		'бронислав',
64
		'вадим',
65
		'валентин',
66
		'валерий',
67
		'варлам',
68
		'василий',
69
		'венедикт',
70
		'вениамин',
71
		'веньямин',
72
		'венцеслав',
73
		'виктор',
74
		'вилен',
75
		'виталий',
76
		'владилен',
77
		'владимир',
78
		'владислав',
79
		'владлен',
80
		'всеволод',
81
		'всеслав',
82
		'вячеслав',
83
		'гавриил',
84
		'геннадий',
85
		'георгий',
86
		'герман',
87
		'глеб',
88
		'григорий',
89
		'давид',
90
		'даниил',
91
		'данил',
92
		'данила',
93
		'демьян',
94
		'денис',
95
		'димитрий',
96
		'дмитрий',
97
		'добрыня',
98
		'евгений',
99
		'евдоким',
100
		'евсей',
101
		'егор',
102
		'емельян',
103
		'еремей',
104
		'ермолай',
105
		'ерофей',
106
		'ефим',
107
		'захар',
108
		'иван',
109
		'игнат',
110
		'игорь',
111
		'илларион',
112
		'иларион',
113
		'илья',
114
		'иосиф',
115
		'казимир',
116
		'касьян',
117
		'кирилл',
118
		'кондрат',
119
		'константин',
120
		'кузьма',
121
		'лавр',
122
		'лаврентий',
123
		'лазарь',
124
		'ларион',
125
		'лев',
126
		'леонард',
127
		'леонид',
128
		'лука',
129
		'максим',
130
		'марат',
131
		'мартын',
132
		'матвей',
133
		'мефодий',
134
		'мирон',
135
		'михаил',
136
		'моисей',
137
		'назар',
138
		'никита',
139
		'николай',
140
		'олег',
141
		'осип',
142
		'остап',
143
		'павел',
144
		'панкрат',
145
		'пантелей',
146
		'парамон',
147
		'пётр',
148
		'петр',
149
		'платон',
150
		'потап',
151
		'прохор',
152
		'роберт',
153
		'ростислав',
154
		'савва',
155
		'савелий',
156
		'семён',
157
		'семен',
158
		'сергей',
159
		'сидор',
160
		'спартак',
161
		'тарас',
162
		'терентий',
163
		'тимофей',
164
		'тимур',
165
		'тихон',
166
		'ульян',
167
		'фёдор',
168
		'федор',
169
		'федот',
170
		'феликс',
171
		'фирс',
172
		'фома',
173
		'харитон',
174
		'харлам',
175
		'эдуард',
176
		'эммануил',
177
		'эраст',
178
		'юлиан',
179
		'юлий',
180
		'юрий',
181
		'яков',
182
		'ян',
183
		'ярослав',
184
	);
185
186
	static protected $womenNames = array(
187
		'авдотья',
188
		'аврора',
189
		'агата',
190
		'агния',
191
		'агриппина',
192
		'ада',
193
		'аксинья',
194
		'алевтина',
195
		'александра',
196
		'алёна',
197
		'алена',
198
		'алина',
199
		'алиса',
200
		'алла',
201
		'альбина',
202
		'амалия',
203
		'анастасия',
204
		'ангелина',
205
		'анжела',
206
		'анжелика',
207
		'анна',
208
		'антонина',
209
		'анфиса',
210
		'арина',
211
		'белла',
212
		'божена',
213
		'валентина',
214
		'валерия',
215
		'ванда',
216
		'варвара',
217
		'василина',
218
		'василиса',
219
		'вера',
220
		'вероника',
221
		'виктория',
222
		'виола',
223
		'виолетта',
224
		'вита',
225
		'виталия',
226
		'владислава',
227
		'власта',
228
		'галина',
229
		'глафира',
230
		'дарья',
231
		'диана',
232
		'дина',
233
		'ева',
234
		'евгения',
235
		'евдокия',
236
		'евлампия',
237
		'екатерина',
238
		'елена',
239
		'елизавета',
240
		'ефросиния',
241
		'ефросинья',
242
		'жанна',
243
		'зиновия',
244
		'злата',
245
		'зоя',
246
		'ивонна',
247
		'изольда',
248
		'илона',
249
		'инга',
250
		'инесса',
251
		'инна',
252
		'ирина',
253
		'ия',
254
		'капитолина',
255
		'карина',
256
		'каролина',
257
		'кира',
258
		'клавдия',
259
		'клара',
260
		'клеопатра',
261
		'кристина',
262
		'ксения',
263
		'лада',
264
		'лариса',
265
		'лиана',
266
		'лидия',
267
		'лилия',
268
		'лина',
269
		'лия',
270
		'лора',
271
		'любава',
272
		'любовь',
273
		'людмила',
274
		'майя',
275
		'маргарита',
276
		'марианна',
277
		'мариетта',
278
		'марина',
279
		'мария',
280
		'марья',
281
		'марта',
282
		'марфа',
283
		'марьяна',
284
		'матрёна',
285
		'матрена',
286
		'матрона',
287
		'милена',
288
		'милослава',
289
		'мирослава',
290
		'муза',
291
		'надежда',
292
		'настасия',
293
		'настасья',
294
		'наталия',
295
		'наталья',
296
		'нелли',
297
		'ника',
298
		'нина',
299
		'нинель',
300
		'нонна',
301
		'оксана',
302
		'олимпиада',
303
		'ольга',
304
		'пелагея',
305
		'полина',
306
		'прасковья',
307
		'раиса',
308
		'рената',
309
		'римма',
310
		'роза',
311
		'роксана',
312
		'руфь',
313
		'сарра',
314
		'светлана',
315
		'серафима',
316
		'снежана',
317
		'софья',
318
		'софия',
319
		'стелла',
320
		'степанида',
321
		'стефания',
322
		'таисия',
323
		'таисья',
324
		'тамара',
325
		'татьяна',
326
		'ульяна',
327
		'устиния',
328
		'устинья',
329
		'фаина',
330
		'фёкла',
331
		'фекла',
332
		'феодора',
333
		'хаврония',
334
		'христина',
335
		'эвелина',
336
		'эдита',
337
		'элеонора',
338
		'элла',
339
		'эльвира',
340
		'эмилия',
341
		'эмма',
342
		'юдифь',
343
		'юлиана',
344
		'юлия',
345
		'ядвига',
346
		'яна',
347
		'ярослава',
348
	);
349
350
	public function isMutable($name, $gender) {
351
		//var_dump(upper(slice($name, -1)));
352
		$name = lower($name);
353
		// man rules
354
		if ($gender === self::MAN) {
355
			// soft consonant
356
			if (lower(slice($name, -1)) == 'ь' && in_array(upper(slice($name, -2, -1)), self::$consonants)) {
357
				return true;
358
			} else if (in_array(upper(slice($name, -1)), array_diff(self::$consonants, array('Й', /*'Ч', 'Щ'*/)))) { // hard consonant
359
				return true;
360
			} else if (slice($name, -1) == 'й') {
361
				return true;
362
			}
363
		}
364
365
		// common rules
366
		if ((in_array(slice($name, -1), array('а', 'я')) && !in_array(upper(slice($name, -2, -1)), self::$vowels)) || in_array(slice($name, -2), array('ия', 'ья', 'ея'))) {
367
			return true;
368
		}
369
370
		return false;
371
	}
372
373
374
375
	public function detectGender($name) {
376
		$name = lower($name);
377
		if (in_array($name, self::$menNames))
378
			return self::MAN;
379
		else if (in_array($name, self::$womenNames))
380
			return self::WOMAN;
381
382
		return null;
383
	}
384
385
	public function getCases($name, $gender) {
386
		$name = lower($name);
387
		if ($gender == self::MAN) {
388
			if (in_array(upper(slice($name, -1)), array_diff(self::$consonants, array('Й', /*'Ч', 'Щ'*/)))) { // hard consonant
389
				$prefix = name($name);
390
				// special cases for Лев, Павел
391
				if (isset($this->exceptions[$name]))
392
					return $this->exceptions[$name];
393
				else {
394
					return array(
395
						self::IMENIT => $prefix,
396
						self::RODIT => $prefix.'а',
397
						self::DAT => $prefix.'у',
398
						self::VINIT => $prefix.'а',
399
						self::TVORIT => RussianLanguage::isHissingConsonant(slice($name, -1)) || slice($name, -1) == 'ц' ? $prefix.'ем' : $prefix.'ом',
400
						self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'е',
401
					);
402
				}
403
			} else if (slice($name, -1) == 'ь' && in_array(upper(slice($name, -2, -1)), self::$consonants)) { // soft consonant
404
				$prefix = name(slice($name, 0, -1));
405
				return array(
406
					self::IMENIT => $prefix.'ь',
407
					self::RODIT => $prefix.'я',
408
					self::DAT => $prefix.'ю',
409
					self::VINIT => $prefix.'я',
410
					self::TVORIT => $prefix.'ем',
411
					self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'е',
412
				);
413
			} else if (in_array(slice($name, -2), array('ай', 'ей', 'ой', 'уй', 'яй', 'юй', 'ий'))) {
414
				$prefix = name(slice($name, 0, -1));
415
				$postfix = slice($name, -2) == 'ий' ? 'и' : 'е';
416
				return array(
417
					self::IMENIT => $prefix.'й',
418
					self::RODIT => $prefix.'я',
419
					self::DAT => $prefix.'ю',
420
					self::VINIT => $prefix.'я',
421
					self::TVORIT => $prefix.'ем',
422
					self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.$postfix,
423
				);
424
			} else if (slice($name, -1) == 'а' && ($before = slice($name, -2, -1)) && self::isConsonant($before) && !in_array($before, array(/*'г', 'к', 'х', */'ц'))) {
425
				$prefix = name(slice($name, 0, -1));
426
				$postfix = (RussianLanguage::isHissingConsonant($before) || in_array($before, array('г', 'к', 'х'))) ? 'и' : 'ы';
427
				return array(
428
					self::IMENIT => $prefix.'а',
429
					self::RODIT => $prefix.$postfix,
430
					self::DAT => $prefix.'е',
431
					self::VINIT => $prefix.'у',
432
					self::TVORIT => $prefix.'ой',
433
					self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'е',
434
				);
435
			} else if (slice($name, -2) == 'ия') {
436
				$prefix = name(slice($name, 0, -1));
437
				return array(
438
					self::IMENIT => $prefix.'я',
439
					self::RODIT => $prefix.'и',
440
					self::DAT => $prefix.'и',
441
					self::VINIT => $prefix.'ю',
442
					self::TVORIT => $prefix.'ей',
443
					self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'и',
444
				);
445
			} else if (slice($name, -2) == 'ло' || slice($name, -2) == 'ко') {
446
				$prefix = name(slice($name, 0, -1));
447
				$postfix = slice($name, -2, -1) == 'к' ? 'и' : 'ы';
448
				return array(
449
					self::IMENIT => $prefix.'о',
450
					self::RODIT =>  $prefix.$postfix,
451
					self::DAT => $prefix.'е',
452
					self::VINIT => $prefix.'у',
453
					self::TVORIT => $prefix.'ой',
454
					self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'е',
455
				);
456
			}
457
		} else if ($gender == self::WOMAN) {
458
			if (slice($name, -1) == 'а' && !in_array(upper($before = (slice($name, -2, -1))), self::$vowels)) {
459
				$prefix = name(slice($name, 0, -1));
460
				if ($before != 'ц') {
461
					$postfix = (RussianLanguage::isHissingConsonant($before) || in_array($before, array('г', 'к', 'х'))) ? 'и' : 'ы';
462
					return array(
463
						self::IMENIT => $prefix.'а',
464
						self::RODIT => $prefix.$postfix,
465
						self::DAT => $prefix.'е',
466
						self::VINIT => $prefix.'у',
467
						self::TVORIT => $prefix.'ой',
468
						self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'е',
469
					);
470
				} else {
471
					return array(
472
						self::IMENIT => $prefix.'а',
473
						self::RODIT => $prefix.'ы',
474
						self::DAT => $prefix.'е',
475
						self::VINIT => $prefix.'у',
476
						self::TVORIT => $prefix.'ей',
477
						self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'е',
478
					);
479
				}
480
			} else if (slice($name, -1) == 'ь' && self::isConsonant(slice($name, -2, -1))) {
481
				$prefix = name(slice($name, 0, -1));
482
				return array(
483
					self::IMENIT => $prefix.'ь',
484
					self::RODIT => $prefix.'и',
485
					self::DAT => $prefix.'и',
486
					self::VINIT => $prefix.'ь',
487
					self::TVORIT => $prefix.'ью',
488
					self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'и',
489
				);
490
			} else if (RussianLanguage::isHissingConsonant(slice($name, -1))) {
491
				$prefix = name($name);
492
				return array(
493
					self::IMENIT => $prefix,
494
					self::RODIT => $prefix.'и',
495
					self::DAT => $prefix.'и',
496
					self::VINIT => $prefix,
497
					self::TVORIT => $prefix.'ью',
498
					self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'и',
499
				);
500
			}
501
		}
502
503
		// common rules for ия and я
504
		if (slice($name, -1) == 'я' && slice($name, -2, -1) != 'и') {
505
			$prefix = name(slice($name, 0, -1));
506
			return array(
507
				self::IMENIT => $prefix.'я',
508
				self::RODIT => $prefix.'и',
509
				self::DAT => $prefix.'е',
510
				self::VINIT => $prefix.'ю',
511
				self::TVORIT => $prefix.'ей',
512
				self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'е',
513
			);
514 View Code Duplication
		} else if (slice($name, -2) == 'ия') {
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...
515
			$prefix = name(slice($name, 0, -1));
516
			return array(
517
				self::IMENIT => $prefix.'я',
518
				self::RODIT => $prefix.'и',
519
				self::DAT => $prefix.'и',
520
				self::VINIT => $prefix.'ю',
521
				self::TVORIT => $prefix.'ей',
522
				self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'и',
523
			);
524
		}
525
526
		$name = name($name);
527
        return array_fill_keys(array(self::IMENIT, self::RODIT, self::DAT, self::VINIT, self::TVORIT), $name) + array(self::PREDLOJ => $this->choosePrepositionByFirstLetter($name, 'об', 'о').' '.$name);
528
	}
529
530 View Code Duplication
	public function getCase($name, $case, $gender) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
531
		$case = self::canonizeCase($case);
532
		$forms = $this->getCases($name, $gender);
533
		if ($forms !== false)
534
			if (isset($forms[$case]))
535
				return $forms[$case];
536
			else
537
				return $name;
538
		else
539
			return $name;
540
	}
541
}
542