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

OrdinalNumeral::generate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 2
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
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
 *            and http://school-collection.edu.ru/dlrstore-wrapper/ebbc76cf-46b6-4d51-ad92-d9a84db35cfa/[I-RUS_06-05]_[TE_16-SU]/[I-RUS_06-05]_[TE_16-SU].html
9
 */
10
class OrdinalNumeral extends NumeralCreation implements Cases {
11
    use RussianLanguage, CasesHelper;
12
13
    protected $words = array(
14
        1 => 'первый',
15
        2 => 'второй',
16
        3 => 'третий',
17
        4 => 'четвертый',
18
        5 => 'пятый',
19
        6 => 'шестой',
20
        7 => 'седьмой',
21
        8 => 'восьмой',
22
        9 => 'девятый',
23
        10 => 'десятый',
24
        11 => 'одиннадцатый',
25
        12 => 'двенадцатый',
26
        13 => 'тринадцатый',
27
        14 => 'четырнадцатый',
28
        15 => 'пятнадцатый',
29
        16 => 'шестнадцатый',
30
        17 => 'семнадцатый',
31
        18 => 'восемнадцатый',
32
        19 => 'девятнадцатый',
33
        20 => 'двадцатый',
34
        30 => 'тридцатый',
35
        40 => 'сороковой',
36
        50 => 'пятьдесятый',
37
        60 => 'шестьдесятый',
38
        70 => 'семьдесятый',
39
        80 => 'восемьдесятый',
40
        90 => 'девяностый',
41
        100 => 'сотый',
42
        200 => 'двухсотый',
43
        300 => 'трехсотый',
44
        400 => 'четырехсотый',
45
        500 => 'пятисотый',
46
        600 => 'шестисотый',
47
        700 => 'семисотый',
48
        800 => 'восемисотый',
49
        900 => 'девятисотый',
50
    );
51
52
    protected $exponents = array(
53
        1000 => 'тысячный',
54
        1000000 => 'миллионный',
55
        1000000000 => 'миллиардный',
56
        1000000000000 => 'триллионный',
57
    );
58
59
    protected $multipliers = array(
60
        2 => 'двух',
61
        3 => 'трех',
62
        4 => 'четырех',
63
        5 => 'пяти',
64
        6 => 'шести',
65
        7 => 'седьми',
66
        8 => 'восьми',
67
        9 => 'девяти',
68
        10 => 'десяти',
69
        11 => 'одиннадцати',
70
        12 => 'двенадцати',
71
        13 => 'тринадцати',
72
        14 => 'четырнадцати',
73
        15 => 'пятнадцати',
74
        16 => 'шестнадцати',
75
        17 => 'семнадцати',
76
        18 => 'восемнадцати',
77
        19 => 'девятнадцати',
78
        20 => 'двадцати',
79
        30 => 'тридцати',
80
        40 => 'сорока',
81
        50 => 'пятьдесяти',
82
        60 => 'шестьдесяти',
83
        70 => 'семьдесяти',
84
        80 => 'восемьдесяти',
85
        90 => 'девяности',
86
        100 => 'сто',
87
        200 => 'двухста',
88
        300 => 'трехста',
89
        400 => 'четырехста',
90
        500 => 'пятиста',
91
        600 => 'шестиста',
92
        700 => 'семиста',
93
        800 => 'восемиста',
94
        900 => 'девятиста',
95
    );
96
97
    protected $cardinal;
98
99
    public function getCases($number, $gender = self::MALE) {
100
        // simple numeral
101
        if (isset($this->words[$number]) || isset($this->exponents[$number])) {
102
            $word = isset($this->words[$number]) ? $this->words[$number] : $this->exponents[$number];
103
            // special rules for 3
104
            if ($number == 3) {
105
                $prefix = slice($word, 0, -2);
106
                return array(
107
                    self::IMENIT => $prefix.($gender == self::MALE ? 'ий' : ($gender == self::FEMALE ? 'ья' : 'ье')),
108
                    self::RODIT => $prefix.($gender == self::FEMALE ? 'ьей' : 'ьего'),
109
                    self::DAT => $prefix.($gender == self::FEMALE ? 'ьей' : 'ьему'),
110
                    self::VINIT => $prefix.($gender == self::FEMALE ? 'ью' : 'ьего'),
111
                    self::TVORIT => $prefix.($gender == self::FEMALE ? 'ьей' : 'ьим'),
112
                    self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.($gender == self::FEMALE ? 'ьей' : 'ьем'),
113
                );
114
            } else {
115
                switch ($gender) {
116 View Code Duplication
                    case self::MALE:
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...
117
                        $prefix = slice($word, 0, $number == 40 ? -1 : -2);
118
                        return array(
119
                            self::IMENIT => $word,
120
                            self::RODIT => $prefix.'ого',
121
                            self::DAT => $prefix.'ому',
122
                            self::VINIT => $word,
123
                            self::TVORIT => $prefix.'ым',
124
                            self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'ом',
125
                        );
126
127 View Code Duplication
                    case self::FEMALE:
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...
128
                        $prefix = slice($word, 0, $number == 40 ? -1 : -2);
129
                        return array(
130
                            self::IMENIT => $prefix.'ая',
131
                            self::RODIT => $prefix.'ой',
132
                            self::DAT => $prefix.'ой',
133
                            self::VINIT => $prefix.'ую',
134
                            self::TVORIT => $prefix.'ой',
135
                            self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'ой',
136
                        );
137
138 View Code Duplication
                    case self::NEUTER:
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...
139
                        $prefix = slice($word, 0, $number == 40 ? -1 : -2);
140
                        return array(
141
                            self::IMENIT => $prefix.'ое',
142
                            self::RODIT => $prefix.'го',
143
                            self::DAT => $prefix.'ому',
144
                            self::VINIT => $word,
145
                            self::TVORIT => $prefix.'ым',
146
                            self::PREDLOJ => $this->choosePrepositionByFirstLetter($prefix, 'об', 'о').' '.$prefix.'ом',
147
                        );
148
                }
149
            }
150
        }
151
        // compound numeral
152
        else {
153
            $ordinal_part = null;
154
            $ordinal_prefix = null;
155
            $cardinal_part = array();
0 ignored issues
show
Unused Code introduced by
$cardinal_part is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
156
            $result = array();
157
158
            // test for exponents. If smaller summand of number is an exponent, declinate it
159
            foreach (array_reverse($this->exponents, true) as $word_number => $word) {
160
                if ($number >= $word_number && ($number % $word_number) == 0) {
161
                    $count = floor($number / $word_number) % 1000;
162
                    $number -= ($count * $word_number);
163
                    foreach (array_reverse($this->multipliers, true) as $multiplier => $multipliers_word) {
164
                        if ($count >= $multiplier) {
165
                            $ordinal_prefix .= $multipliers_word;
166
                            $count -= $multiplier;
167
                        }
168
                    }
169
                    $ordinal_part = $this->getCases($word_number, $gender);
170
                    foreach ($ordinal_part as $case => $ordinal_word) {
171 View Code Duplication
                        if ($case == self::PREDLOJ) {
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...
172
                            list(, $ordinal_part[$case]) = explode(' ', $ordinal_part[$case]);
173
                            $ordinal_part[$case] = $this->choosePrepositionByFirstLetter($ordinal_prefix, 'об', 'о').' '.$ordinal_prefix.$ordinal_part[$case];
174
                        } else
175
                            $ordinal_part[$case] = $ordinal_prefix.$ordinal_part[$case];
176
                    }
177
178
                    break;
179
                }
180
            }
181
182
            // otherwise, test if smaller summand is just a number with it's own name
183
            if (empty($ordinal_part)) {
184
                // get the smallest number with it's own name
185
                foreach ($this->words as $word_number => $word) {
186
                    if ($number >= $word_number) {
187
                        if ($word_number <= 9) {
188
                            if ($number % 10 == 0) continue;
189
                            // check for case when word_number smaller than should be used (e.g. 1,2,3 when it can be 4 (number: 344))
190
                            if (($number % 10) > $word_number) {
191
                                continue;
192
                            }
193
                        } else if ($word_number <= 90) {
194
                            // check for case when word_number smaller than should be used (e.g. 10, 11, 12 when it can be 13)
195
                            if (($number % 100) > $word_number) {
196
                                continue;
197
                            }
198
                        }
199
                        $ordinal_part = $this->getCases($word_number, $gender);
200
                        $number -= $word_number;
201
                        break;
202
                    }
203
                }
204
            }
205
206
            // if number has second summand, get cardinal form of it
207
            if ($number > 0) {
208
                if (empty($this->cardinal)) $this->cardinal = new CardinalNumeral();
209
                $cardinal_part = $this->cardinal->getCase($number, self::IMENIT, $gender);
210
211
                // make one array with cases and delete 'o/об' prepositional from all parts except the last one
212
                foreach (array(self::IMENIT, self::RODIT, self::DAT, self::VINIT, self::TVORIT, self::PREDLOJ) as $case) {
213 View Code Duplication
                    if ($case == self::PREDLOJ) {
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...
214
                        list(, $ordinal_part[$case]) = explode(' ', $ordinal_part[$case]);
215
                        $result[$case] = $this->choosePrepositionByFirstLetter($cardinal_part, 'об', 'о').' '.$cardinal_part.' '.$ordinal_part[$case];
216
                    } else
217
                        $result[$case] = $cardinal_part.' '.$ordinal_part[$case];
218
                }
219
            } else {
220
                $result = $ordinal_part;
221
            }
222
223
            return $result;
224
        }
225
    }
226
227
    public function getCase($number, $case, $gender = self::MALE) {
228
        $case = self::canonizeCase($case);
229
        $forms = $this->getCases($number, $gender);
230
        return $forms[$case];
231
    }
232
233
    static public function generate($number, $gender = self::MALE) {
234
        static $card;
235
        if ($card === null) $card = new self();
236
237
        return $card->getCase($number, self::IMENIT, $gender);
238
    }
239
}
240