Completed
Pull Request — 2.x (#28)
by Hari
01:57
created

IntlFormatter::throwCannotInstantiateFormatter()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 7
ccs 2
cts 2
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 0
crap 1
1
<?php
2
/**
3
 *
4
 * This file is part of the Aura Project for PHP.
5
 *
6
 * @package Aura.Intl
7
 *
8
 * @license http://opensource.org/licenses/MIT MIT
9
 *
10
 */
11
namespace Aura\Intl;
12
13
use MessageFormatter;
14
use Aura\Intl\Exception;
15
16
/**
17
 *
18
 * Uses php intl extension to format messages
19
 *
20
 * @package Aura.Intl
21
 *
22
 */
23
class IntlFormatter implements FormatterInterface
24
{
25
    /**
26
     *
27
     * Constructor.
28
     *
29
     * @param string $icu_version The current ICU version; mostly used for
30
     * testing.
31
     *
32
     * @throws Exception\IcuVersionTooLow when the Version of ICU installed
33
     * is too low for Aura.Intl to work properly.
34
     *
35
     */
36 12
    public function __construct($icu_version = INTL_ICU_VERSION)
37
    {
38 12
        if (version_compare($icu_version, '4.8') < 0) {
39 1
            throw new Exception\IcuVersionTooLow('ICU Version 4.8 or higher required.');
40
        }
41 11
    }
42
43
    /**
44
     *
45
     * Format the message with the help of php intl extension
46
     *
47
     * @param string $locale
48
     * @param string $string
49
     * @param array $tokens_values
50
     * @return string
51
     * @throws Exception
52
     */
53 11
    public function format($locale, $string, array $tokens_values)
54
    {
55
        // extract tokens and retain sequential positions
56 11
        $tokens = [];
57 11
        $i = 0;
58
59
        // opening brace, followed by the token word characters,
60
        // followed by any non-token word character
61 11
        $regex = '/(\{)([A-Za-z0-9_]+)([\,\}])/m';
62 11
        preg_match_all($regex, $string, $matches, PREG_SET_ORDER);
63
64 11
        foreach ($matches as $match) {
0 ignored issues
show
Bug introduced by
The expression $matches of type null|array<integer,array<integer,string>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
65
66
            // the token name
67 11
            $key = $match[2];
68 11
            if (! isset($tokens[$key])) {
69 11
                $tokens[$key] = $i;
70 11
                $num = $i;
71 11
                $i++;
72
            } else {
73 8
                $num = $tokens[$key];
74
            }
75
76
            // replace just the first occurence;
77
            // other occurrences will get replaced later.
78 11
            $string = preg_replace(
79 11
                "/$match[0]/",
80 11
                '{' . $num . $match[3],
81
                $string,
82 11
                1
83
            );
84
        }
85
86 11
        $values = [];
87 11
        foreach ($tokens as $token => $i) {
88 11
            if (! isset($tokens_values[$token])) {
89 2
                continue;
90
            }
91
92 9
            $value = $tokens_values[$token];
93
94
            // convert an array to a CSV string
95 9
            if (is_array($value)) {
96 1
                $value = '"' . implode('", "', $value) . '"';
97
            }
98
99 9
            $values[$i] = $value;
100
        }
101
102
        try {
103 11
            $formatter = new MessageFormatter($locale, $string);
104 10
            if (! $formatter) {
105 10
                $this->throwCannotInstantiateFormatter();
106
            }
107 1
        } catch (\Exception $e) {
108 1
            $this->throwCannotInstantiateFormatter();
109
        }
110
111 10
        $result = $formatter->format($values);
112 10
        if ($result === false) {
113
            throw new Exception\CannotFormat(
114
                $formatter->getErrorMessage(),
115
                $formatter->getErrorCode()
116
            );
117
        }
118
119 10
        return $result;
120
    }
121
122 1
    protected function throwCannotInstantiateFormatter()
123
    {
124 1
        throw new Exception\CannotInstantiateFormatter(
125
            intl_get_error_message(),
126
            intl_get_error_code()
127
        );
128
    }
129
}
130