AdjectiveDeclension::getCase()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 4
dl 0
loc 10
ccs 0
cts 6
cp 0
crap 6
rs 9.9332
c 0
b 0
f 0
1
<?php
2
namespace morphos\Russian;
3
4
use morphos\BaseInflection;
5
use morphos\Gender;
6
use morphos\S;
7
use RuntimeException;
8
9
/**
10
 * Class AdjectiveDeclension.
11
 *
12
 * Склонение прилагательных.
13
 *
14
 * Правила склонения:
15
 * - http://www.fio.ru/pravila/grammatika/sklonenie-prilagatelnykh-v-russkom-yazyke/
16
 *
17
 * @package morphos\Russian
18
 */
19
class AdjectiveDeclension extends BaseInflection implements Cases, Gender
20
{
21
    use RussianLanguage, CasesHelper;
22
23
    const HARD_BASE = 1;
24
    const SOFT_BASE = 2;
25
    const MIXED_BASE = 3;
26
27
    /**
28
     * @param string $adjective
29
     * @return bool|void
30
     */
31
    public static function isMutable($adjective)
32
    {
33
        return false;
34
    }
35
36
    /**
37
     * @param string $adjective
38
     * @param string $case
39
     * @param bool   $animateness
40
     * @param null   $gender
41
     *
42
     * @return string
43
     * @throws \Exception
44
     */
45
    public static function getCase($adjective, $case, $animateness = false, $gender = null)
46
    {
47
        $case = static::canonizeCase($case);
48
49
        if ($gender === null)
50
            $gender = static::detectGender($adjective);
51
52
        $forms = static::getCases($adjective, $animateness, $gender);
53
        return $forms[$case];
54
    }
55
56
    /**
57
     * @param string $adjective
58
     *
59
     * @param bool $isEmphasized
60
     *
61
     * @return string
62
     */
63 24
    public static function detectGender($adjective, &$isEmphasized = false)
64
    {
65 24
        switch (S::lower(S::slice($adjective, -2)))
66
        {
67 24
            case 'ой':
68 4
                $isEmphasized = true;
69 20
            case 'ый':
70 19
            case 'ий':
71 8
                return static::MALE;
72
73 16
            case 'ая':
74 10
            case 'яя':
75 8
                return static::FEMALE;
76
77 8
            case 'ое':
78 2
            case 'ее':
79 8
                return static::NEUTER;
80
        }
81
82
        throw new RuntimeException('Unreachable');
83
    }
84
85
    /**
86
     * @param string $adjective
87
     * @param bool $animateness
88
     * @param null|string $gender
89
     *
90
     * @return string[]
91
     * @phpstan-return array<string, string>
92
     */
93 18
    public static function getCases($adjective, $animateness = false, $gender = null)
94
    {
95 18
        if ($gender === null)
96 18
            $gender = static::detectGender($adjective, $isEmphasized);
97
98 18
        $last_consonant_vowel = S::slice($adjective, -2, -1);
99 18
        $type = static::getAdjectiveBaseType($adjective);
100 18
        $adjective = S::slice($adjective, 0, -2);
101
102
        switch ($type)
103
        {
104 18
            case static::HARD_BASE:
105 6
                return static::declinateHardAdjective($adjective, $animateness, $gender,
106 6
                    $last_consonant_vowel);
107
108 12
            case static::SOFT_BASE:
109 3
                return static::declinateSoftAdjective($adjective, $animateness, $gender,
110 3
                    $last_consonant_vowel);
111
112 9
            case static::MIXED_BASE:
113 9
                return static::declinateMixedAdjective($adjective, $animateness, $gender,
114 9
                    $last_consonant_vowel);
115
        }
116
117
        throw new RuntimeException('Unreachable');
118
    }
119
120
    /**
121
     * @param string $adjective
122
     *
123
     * @return int
124
     */
125 25
    public static function getAdjectiveBaseType($adjective)
126
    {
127 25
        $adjective = S::lower($adjective);
128 25
        $consonants = static::$consonants;
129
130 25
        unset($consonants[array_search('н', $consonants)]);
131 25
        unset($consonants[array_search('й', $consonants)]);
132
133 25
        $substring = S::findLastPositionForOneOfChars($adjective, $consonants);
134 25
        $last_consonant = S::slice($substring, 0, 1);
0 ignored issues
show
Security Bug introduced by
It seems like $substring defined by \morphos\S::findLastPosi...adjective, $consonants) on line 133 can also be of type false; however, morphos\S::slice() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
135
136
        // г, к, х, ударное ш - признак смешанного прилагательно
137 25
        if (in_array($last_consonant, ['г', 'к', 'х'], true) ||
138
            (
139 25
            $last_consonant === 'ш' && in_array(S::slice($substring, 1, 2), ['о', 'а'], true)
0 ignored issues
show
Security Bug introduced by
It seems like $substring defined by \morphos\S::findLastPosi...adjective, $consonants) on line 133 can also be of type false; however, morphos\S::slice() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
140
            )) {
141 12
            return static::MIXED_BASE;
142
        }
143
144 13
        return static::checkBaseLastConsonantSoftness($substring)
0 ignored issues
show
Security Bug introduced by
It seems like $substring defined by \morphos\S::findLastPosi...adjective, $consonants) on line 133 can also be of type false; however, morphos\Russian\RussianL...LastConsonantSoftness() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
145 13
            || (S::slice($substring, 0, 2) === 'шн')
0 ignored issues
show
Security Bug introduced by
It seems like $substring defined by \morphos\S::findLastPosi...adjective, $consonants) on line 133 can also be of type false; however, morphos\S::slice() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
146 4
            ? static::SOFT_BASE
147 13
            : static::HARD_BASE;
148
    }
149
150
    /**
151
     * @param string $adjective
152
     * @param bool   $animateness
153
     * @param string $gender
154
     * @param string $afterConsonantVowel
155
     *
156
     * @return string[]
157
     * @phpstan-return array<string, string>
158
     */
159 6 View Code Duplication
    protected static function declinateHardAdjective($adjective, $animateness, $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...
160
        $afterConsonantVowel)
161
    {
162
        switch ($gender)
163
        {
164 6
            case static::MALE:
165 2
                $postfix = $afterConsonantVowel.'й';
166 2
                break;
167
168 4
            case static::FEMALE:
169 2
                $postfix = $afterConsonantVowel.'я';
170 2
                break;
171
172 2
            case static::NEUTER:
173 2
                $postfix = $afterConsonantVowel.'е';
174 2
                break;
175
176
            default: throw new RuntimeException('Unreachable');
177
        }
178
179
        $cases = [
180 6
            static::IMENIT => $adjective.$postfix,
181 6
            static::RODIT => $adjective.'о'.($gender !== static::FEMALE ? 'го' : 'й'),
182 6
            static::DAT => $adjective.'о'.($gender !== static::FEMALE ? 'му' : 'й'),
183
        ];
184
185 6
        if ($gender !== static::FEMALE)
186 4
            $cases[static::VINIT] = static::getVinitCaseByAnimateness($cases, $animateness);
187
        else
188 2
            $cases[static::VINIT] = $adjective.'ую';
189
190 6
        $cases[static::TVORIT] = $adjective.($gender !== static::FEMALE ? 'ым' : 'ой');
191 6
        $cases[static::PREDLOJ] = $adjective.($gender !== static::FEMALE ? 'ом' : 'ой');
192
193 6
        return $cases;
194
    }
195
196
    /**
197
     * @param string $adjective
198
     * @param bool   $animateness
199
     * @param string $gender
200
     * @param string $afterConsonantVowel
201
     *
202
     * @return string[]
203
     * @phpstan-return array<string, string>
204
     */
205 3 View Code Duplication
    protected static function declinateSoftAdjective($adjective, $animateness, $gender, $afterConsonantVowel)
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...
206
    {
207
        switch ($gender)
208
        {
209 3
            case static::MALE:
210 1
                $postfix = $afterConsonantVowel.'й';
211 1
                break;
212
213 2
            case static::FEMALE:
214 1
                $postfix = $afterConsonantVowel.'я';
215 1
                break;
216
217 1
            case static::NEUTER:
218 1
                $postfix = $afterConsonantVowel.'е';
219 1
                break;
220
221
            default: throw new RuntimeException('Unreachable');
222
        }
223
224
        $cases = [
225 3
            static::IMENIT => $adjective.$postfix,
226 3
            static::RODIT => $adjective.'е'.($gender !== static::FEMALE ? 'го' : 'й'),
227 3
            static::DAT => $adjective.'е'.($gender !== static::FEMALE ? 'му' : 'й'),
228
        ];
229
230 3
        if ($gender !== static::FEMALE)
231 2
            $cases[static::VINIT] = static::getVinitCaseByAnimateness($cases, $animateness);
232
        else
233 1
            $cases[static::VINIT] = $adjective.'юю';
234
235 3
        $cases[static::TVORIT] = $adjective.($gender !== static::FEMALE ? 'им' : 'ей');
236 3
        $cases[static::PREDLOJ] = $adjective.($gender !== static::FEMALE ? 'ем' : 'ей');
237
238 3
        return $cases;
239
    }
240
241
    /**
242
     * @param string $adjective
243
     * @param bool   $animateness
244
     * @param string $gender
245
     * @param string $afterConsonantVowel
246
     *
247
     * @return string[]
248
     * @phpstan-return array<string, string>
249
     */
250 9
    protected static function declinateMixedAdjective($adjective, $animateness, $gender, $afterConsonantVowel)
251
    {
252
        switch ($gender)
253
        {
254 9
            case static::MALE:
255 3
                $postfix = $afterConsonantVowel.'й';
256 3
                break;
257
258 6
            case static::FEMALE:
259 3
                $postfix = $afterConsonantVowel.'я';
260 3
                break;
261
262 3
            case static::NEUTER:
263 3
                $postfix = $afterConsonantVowel.'е';
264 3
                break;
265
266
            default: throw new RuntimeException('Unreachable');
267
        }
268
269
        $cases = [
270 9
            static::IMENIT => $adjective.$postfix,
271 9
            static::RODIT => $adjective.'о'.($gender !== static::FEMALE ? 'го' : 'й'),
272 9
            static::DAT => $adjective.'о'.($gender !== static::FEMALE ? 'му' : 'й'),
273
        ];
274
275 9
        if ($gender === static::MALE)
276 3
            $cases[static::VINIT] = static::getVinitCaseByAnimateness($cases, $animateness);
277 6
        else if ($gender === static::NEUTER)
278 3
            $cases[static::VINIT] = $adjective.'ое';
279
        else
280 3
            $cases[static::VINIT] = $adjective.'ую';
281
282 9
        $cases[static::TVORIT] = $adjective.($gender !== static::FEMALE ? 'им' : 'ой');
283 9
        $cases[static::PREDLOJ] = $adjective.($gender !== static::FEMALE ? 'ом' : 'ой');
284
285 9
        return $cases;
286
    }
287
}