Passed
Push — master ( f50dcb...17d4c3 )
by
unknown
02:12
created

SimpleMessageFormatter::pluralize()   B

Complexity

Conditions 7
Paths 9

Size

Total Lines 29
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 7

Importance

Changes 0
Metric Value
cc 7
eloc 15
nc 9
nop 2
dl 0
loc 29
ccs 16
cts 16
cp 1
crap 7
rs 8.8333
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Translator;
6
7
use InvalidArgumentException;
8
9
class SimpleMessageFormatter implements MessageFormatterInterface
10
{
11
    private const PLURAL_ONE = 'one';
12
    private const PLURAL_OTHER = 'other';
13
    private const PLURAL_KEYS = [self::PLURAL_ONE, self::PLURAL_OTHER];
14
15 14
    public function format(string $message, array $parameters, string $locale = 'en_US'): string
16
    {
17 14
        preg_match_all('/{((?>[^{}]+)|(?R))*}/', $message, $matches);
18 14
        $replacements = [];
19
20 14
        foreach ($matches[0] as $match) {
21 14
            $parts = explode(',', $match);
22 14
            $parameter = trim($parts[0], '{}');
23
24 14
            if (!isset($parameters[$parameter])) {
25 1
                throw new InvalidArgumentException("\"$parameter\" parameter's value is missing.");
26
            }
27
28 13
            $value = $parameters[$parameter];
29
30 13
            if (!is_scalar($value)) {
31 1
                continue;
32
            }
33
34 12
            if (count($parts) === 1) {
35 3
                $replacements[$match] = $value;
36
37 3
                continue;
38
            }
39
40 10
            $format = ltrim($parts[1]);
41 10
            $format = rtrim($format, '}');
42
43 10
            switch ($format) {
44 10
                case 'plural':
45 9
                    $options = $parts[2] ?? '';
46 9
                    $replacements[$match] = self::pluralize($value, $options);
47
48 5
                    break;
49
                default:
50 2
                    $replacements[$match] = $value;
51
            }
52
        }
53
54 9
        return strtr($message, $replacements);
55
    }
56
57
    /**
58
     * @param mixed $value
59
     * @param string $options
60
     *
61
     * @return string
62
     */
63 9
    private static function pluralize($value, string $options): string
64
    {
65 9
        if (!$options) {
66 1
            throw new InvalidArgumentException('Missing plural keys: ' . self::formatList(self::PLURAL_KEYS) . '.');
67
        }
68
69 8
        if (!is_int($value)) {
70 1
            throw new InvalidArgumentException('Only integer numbers are supported with plural format.');
71
        }
72
73 7
        preg_match_all('/([^{}\s]+)({(.*?)})/', $options, $pluralMatches);
74
75 7
        $map = [];
76 7
        foreach ($pluralMatches[1] as $index => $match) {
77 7
            if (!in_array($match, self::PLURAL_KEYS, true)) {
78 1
                $keysStr = self::formatList(self::PLURAL_KEYS);
79
80 1
                throw new InvalidArgumentException("Invalid plural key - \"$match\". The valid keys are $keysStr.");
81
            }
82
83 7
            $map[$match] = $pluralMatches[3][$index];
84
        }
85
86 6
        $diff = array_diff(self::PLURAL_KEYS, $pluralMatches[1]);
87 6
        if ($diff !== []) {
88 1
            throw new InvalidArgumentException('Missing plural keys: ' . self::formatList($diff) . '.');
89
        }
90
91 5
        return $value === 1 ? $map[self::PLURAL_ONE] : $map[self::PLURAL_OTHER];
92
    }
93
94
    /**
95
     * @param string[] $items
96
     *
97
     * @return string
98
     */
99 3
    private static function formatList(array $items): string
100
    {
101 3
        return implode(', ', array_map(fn (string $value): string => '"' . $value . '"', $items));
102
    }
103
}
104