Completed
Push — master ( a68159...5a5ec3 )
by f
02:24
created

CardinalNumeral   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 281
Duplicated Lines 2.85 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
dl 8
loc 281
rs 8.6
c 0
b 0
f 0
wmc 37
lcom 1
cbo 5

3 Methods

Rating   Name   Duplication   Size   Complexity  
F getCases() 8 120 34
A getCase() 0 5 1
A generate() 0 6 2

How to fix   Duplicated Code   

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:

1
<?php
2
namespace morphos\Russian;
3
4
use morphos\NumeralCreation;
5
6
/**
7
 * Rules are from http://www.fio.ru/pravila/grammatika/sklonenie-imen-chislitelnykh/
8
 */
9
class CardinalNumeral extends NumeralCreation implements Cases {
10
    use RussianLanguage, CasesHelper;
11
12
    protected $words = array(
13
        1 => 'один',
14
        2 => 'два',
15
        3 => 'три',
16
        4 => 'четыре',
17
        5 => 'пять',
18
        6 => 'шесть',
19
        7 => 'семь',
20
        8 => 'восемь',
21
        9 => 'девять',
22
        10 => 'десять',
23
        11 => 'одиннадцать',
24
        12 => 'двенадцать',
25
        13 => 'тринадцать',
26
        14 => 'четырнадцать',
27
        15 => 'пятнадцать',
28
        16 => 'шестнадцать',
29
        17 => 'семнадцать',
30
        18 => 'восемнадцать',
31
        19 => 'девятнадцать',
32
        20 => 'двадцать',
33
        30 => 'тридцать',
34
        40 => 'сорок',
35
        50 => 'пятьдесят',
36
        60 => 'шестьдесят',
37
        70 => 'семьдесят',
38
        80 => 'восемьдесят',
39
        90 => 'девяносто',
40
        100 => 'сто',
41
        200 => 'двести',
42
        300 => 'триста',
43
        400 => 'четыреста',
44
        500 => 'пятьсот',
45
        600 => 'шестьсот',
46
        700 => 'семьсот',
47
        800 => 'восемьсот',
48
        900 => 'девятьсот',
49
    );
50
51
    protected $exponents = array(
52
        1000 => 'тысяча',
53
        1000000 => 'миллион',
54
        1000000000 => 'миллиард',
55
        1000000000000 => 'триллион',
56
    );
57
58
    protected $declension;
59
    protected $plurality;
60
61
    protected $precalculated = array(
62
        'один' => array(
63
            self::MALE => array(
64
                self::IMENIT => 'один',
65
                self::RODIT => 'одного',
66
                self::DAT => 'одному',
67
                self::VINIT => 'один',
68
                self::TVORIT => 'одним',
69
                self::PREDLOJ => 'об одном',
70
            ),
71
            self::FEMALE => array(
72
                self::IMENIT => 'одна',
73
                self::RODIT => 'одной',
74
                self::DAT => 'одной',
75
                self::VINIT => 'одну',
76
                self::TVORIT => 'одной',
77
                self::PREDLOJ => 'об одной',
78
            ),
79
            self::NEUTER => array(
80
                self::IMENIT => 'одно',
81
                self::RODIT => 'одного',
82
                self::DAT => 'одному',
83
                self::VINIT => 'одно',
84
                self::TVORIT => 'одним',
85
                self::PREDLOJ => 'об одном',
86
            ),
87
        ),
88
        'два' => array(
89
            self::MALE => array(
90
                self::IMENIT => 'два',
91
                self::RODIT => 'двух',
92
                self::DAT => 'двум',
93
                self::VINIT => 'два',
94
                self::TVORIT => 'двумя',
95
                self::PREDLOJ => 'о двух',
96
            ),
97
            self::FEMALE => array(
98
                self::IMENIT => 'две',
99
                self::RODIT => 'двух',
100
                self::DAT => 'двум',
101
                self::VINIT => 'два',
102
                self::TVORIT => 'двумя',
103
                self::PREDLOJ => 'о двух',
104
            ),
105
            self::NEUTER => array(
106
                self::IMENIT => 'два',
107
                self::RODIT => 'двух',
108
                self::DAT => 'двум',
109
                self::VINIT => 'два',
110
                self::TVORIT => 'двумя',
111
                self::PREDLOJ => 'о двух',
112
            ),
113
        ),
114
        'три' => array(
115
            self::IMENIT => 'три',
116
            self::RODIT => 'трех',
117
            self::DAT => 'трем',
118
            self::VINIT => 'три',
119
            self::TVORIT => 'тремя',
120
            self::PREDLOJ => 'о трех',
121
        ),
122
        'четыре' => array(
123
            self::IMENIT => 'четыре',
124
            self::RODIT => 'четырех',
125
            self::DAT => 'четырем',
126
            self::VINIT => 'четыре',
127
            self::TVORIT => 'четырьмя',
128
            self::PREDLOJ => 'о четырех',
129
        ),
130
        'двести' => array(
131
            self::IMENIT => 'двести',
132
            self::RODIT => 'двухсот',
133
            self::DAT => 'двумстам',
134
            self::VINIT => 'двести',
135
            self::TVORIT => 'двумястами',
136
            self::PREDLOJ => 'о двухстах',
137
        ),
138
        'восемьсот' => array(
139
            self::IMENIT => 'восемьсот',
140
            self::RODIT => 'восьмисот',
141
            self::DAT => 'восьмистам',
142
            self::VINIT => 'восемьсот',
143
            self::TVORIT => 'восьмистами',
144
            self::PREDLOJ => 'о восьмистах',
145
        ),
146
        'тысяча' => array(
147
            self::IMENIT => 'тысяча',
148
            self::RODIT => 'тысяч',
149
            self::DAT => 'тысячам',
150
            self::VINIT => 'тысяч',
151
            self::TVORIT => 'тысячей',
152
            self::PREDLOJ => 'о тысячах',
153
        ),
154
    );
155
156
    public function getCases($number, $gender = self::MALE) {
157
        // simple numeral
158
        if (isset($this->words[$number]) || isset($this->exponents[$number])) {
159
            $word = isset($this->words[$number]) ? $this->words[$number] : $this->exponents[$number];
160
            if (isset($this->precalculated[$word])) {
161
                if (isset($this->precalculated[$word][self::MALE])) {
162
                    return $this->precalculated[$word][$gender];
163
                } else {
164
                    return $this->precalculated[$word];
165
                }
166
            } else if (($number >= 5 && $number <= 20) || $number == 30) {
167
                $prefix = slice($word, 0, -1);
168
                return array(
169
                    self::IMENIT => $word,
170
                    self::RODIT => $prefix.'и',
171
                    self::DAT => $prefix.'и',
172
                    self::VINIT => $word,
173
                    self::TVORIT => $prefix.'ью',
174
                    self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'и',
175
                );
176
            } else if (in_array($number, array(40, 90, 100))) {
177
                $prefix = $number == 40 ? $word : slice($word, 0, -1);
178
                return array(
179
                    self::IMENIT => $word,
180
                    self::RODIT => $prefix.'а',
181
                    self::DAT => $prefix.'а',
182
                    self::VINIT => $word,
183
                    self::TVORIT => $prefix.'а',
184
                    self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'а',
185
                );
186
            } else if (($number >= 50 && $number <= 80)) {
187
                $prefix = slice($word, 0, -6);
188
                return array(
189
                    self::IMENIT => $prefix.'ьдесят',
190
                    self::RODIT => $prefix.'идесяти',
191
                    self::DAT => $prefix.'идесяти',
192
                    self::VINIT => $prefix.'ьдесят',
193
                    self::TVORIT => $prefix.'ьюдесятью',
194
                    self::PREDLOJ => $this->choosePrepositionByFirstLetter($word, 'об', 'о').' '.$prefix.'идесяти',
195
                );
196
            } else if (in_array($number, array(300, 400))) {
197
                $prefix = slice($word, 0, -4);
198
                return array(
199
                    self::IMENIT => $word,
200
                    self::RODIT => $prefix.'ехсот',
201
                    self::DAT => $prefix.'емстам',
202
                    self::VINIT => $word,
203
                    self::TVORIT => $prefix.($number == 300 ? 'е' : 'ь').'мястами',
204
                    self::PREDLOJ => $this->choosePrepositionByFirstLetter($word, 'об', 'о').' '.$prefix.'ехстах',
205
                );
206
            } else if ($number >= 500 && $number <= 900) {
207
                $prefix = slice($word, 0, -4);
208
                return array(
209
                    self::IMENIT => $word,
210
                    self::RODIT => $prefix.'исот',
211
                    self::DAT => $prefix.'истам',
212
                    self::VINIT => $word,
213
                    self::TVORIT => $prefix.'ьюстами',
214
                    self::PREDLOJ => $this->choosePrepositionByFirstLetter($word, 'об', 'о').' '.$prefix.'истах',
215
                );
216
            } else if (isset($this->exponents[$number])) {
217
                if (empty($this->declension)) $this->declension = new GeneralDeclension();
218
                return $this->declension->getCases($word, false);
219
            }
220
        }
221
        // compound numeral
222
        else {
223
            $parts = array();
224
            $result = array();
225
226
            foreach (array_reverse($this->exponents, true) as $word_number => $word) {
227
                if ($number >= $word_number) {
228
                    $count = floor($number / $word_number);
229
                    $parts[] = $this->getCases($count, ($word_number == 1000 ? self::FEMALE : self::MALE));
230
231
                    // get forms of word
232
                    if (empty($this->declension)) $this->declension = new GeneralDeclension();
233
                    if (empty($this->plurality)) $this->plurality = new Plurality();
234
235
                    switch (Plurality::getNumeralForm($count)) {
236
                        case Plurality::ONE:
237
                            $parts[] = $this->declension->getCases($word, false);
238
                            break;
239
                        case Plurality::TWO_FOUR:
240
                            $part = $this->plurality->getCases($word);
241
                            if ($word_number != 1000) // get dative case of word for 1000000, 1000000000 and 1000000000000
242
                                $part[Cases::IMENIT] = $part[Cases::VINIT] = $this->declension->getCase($word, Cases::RODIT);
243
                            $parts[] = $part;
244
                            break;
245
                        case Plurality::FIVE_OTHER:
246
                            $part = $this->plurality->getCases($word);
247
                            $part[Cases::IMENIT] = $part[Cases::VINIT] = $part[Cases::RODIT];
248
                            $parts[] = $part;
249
                            break;
250
                    }
251
252
                    $number = $number % ($count * $word_number);
253
                }
254
            }
255
256
            foreach (array_reverse($this->words, true) as $word_number => $word) {
257
                if ($number >= $word_number) {
258
                    $parts[] = $this->getCases($word_number, $gender);
259
                    $number %= $word_number;
260
                }
261
            }
262
263
            // make one array with cases and delete 'o/об' prepositional from all parts except the last one
264 View Code Duplication
            foreach (array(self::IMENIT, self::RODIT, self::DAT, self::VINIT, self::TVORIT, self::PREDLOJ) as $case) {
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...
265
                $result[$case] = array();
266
                foreach ($parts as $partN => $part) {
267
                    if ($case == self::PREDLOJ && $partN > 0) list(, $part[$case]) = explode(' ', $part[$case], 2);
268
                    $result[$case][] = $part[$case];
269
                }
270
                $result[$case] = implode(' ', $result[$case]);
271
            }
272
273
            return $result;
274
        }
275
    }
276
277
    public function getCase($number, $case, $gender = self::MALE) {
278
        $case = self::canonizeCase($case);
279
        $forms = $this->getCases($number, $gender);
280
        return $forms[$case];
281
    }
282
283
    static public function generate($number, $gender = self::MALE) {
284
        static $card;
285
        if ($card === null) $card = new self();
286
287
        return $card->getCase($number, self::IMENIT, $gender);
288
    }
289
}
290