MessageSource   A
last analyzed

Complexity

Total Complexity 26

Size/Duplication

Total Lines 132
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 26
eloc 54
c 3
b 0
f 0
dl 0
loc 132
ccs 60
cts 60
cp 1
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A read() 0 16 3
A __construct() 0 2 1
A getMessage() 0 7 2
A generateMessagesFileContent() 0 12 2
A write() 0 8 2
B getFilePath() 0 13 7
A messagesToCode() 0 30 6
A getMessages() 0 13 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Translator\Message\Php;
6
7
use InvalidArgumentException;
8
use RuntimeException;
9
use Yiisoft\Translator\MessageReaderInterface;
10
use Yiisoft\Translator\MessageWriterInterface;
11
12
use function array_key_exists;
13
use function is_array;
14
use function is_string;
15
16
final class MessageSource implements MessageReaderInterface, MessageWriterInterface
17
{
18
    /**
19
     * @psalm-var array<string, array<string, array<string, string>>>
20
     */
21
    private array $messages = [];
22
23 18
    public function __construct(private string $path)
24
    {
25 18
    }
26
27 9
    public function getMessage(string $id, string $category, string $locale, array $parameters = []): ?string
28
    {
29 9
        if (!isset($this->messages[$category][$locale])) {
30 9
            $this->read($category, $locale);
31
        }
32
33 6
        return $this->messages[$category][$locale][$id] ?? null;
34
    }
35
36 3
    public function getMessages(string $category, string $locale): array
37
    {
38 3
        if (!isset($this->messages[$category][$locale])) {
39 3
            $this->read($category, $locale);
40
        }
41
42 3
        $messages = $this->messages[$category][$locale] ?? [];
43 3
        foreach ($messages as &$message) {
44 3
            $message = ['message' => $message];
45
        }
46
        /** @psalm-var array<string, array<string, string>> $messages */
47
48 3
        return $messages;
49
    }
50
51
    /**
52
     * @psalm-param array<string, array<string, string>> $messages
53
     */
54 14
    public function write(string $category, string $locale, array $messages): void
55
    {
56 14
        $content = $this->generateMessagesFileContent($messages);
57
58 11
        $path = $this->getFilePath($category, $locale, true);
59
60 10
        if (file_put_contents($path, $content, LOCK_EX) === false) {
61 1
            throw new RuntimeException('Can not write to ' . $path);
62
        }
63
    }
64
65 15
    private function getFilePath(string $category, string $locale, bool $withCreateDir = false): string
66
    {
67 15
        if ($locale !== '' && !preg_match('/^[a-z0-9_-]+$/i', $locale)) {
68 3
            throw new InvalidArgumentException(sprintf('Invalid locale code: "%s".', $locale));
69
        }
70
71 12
        $filePath = $this->path . DIRECTORY_SEPARATOR . $locale;
72 12
        if ($withCreateDir && !file_exists($filePath) && !mkdir($filePath, 0775, true) && !is_dir($filePath)) {
73 1
            throw new RuntimeException(sprintf('Directory "%s" was not created', $filePath));
74
        }
75 11
        $filePath .= DIRECTORY_SEPARATOR . $category . '.php';
76
77 11
        return $filePath;
78
    }
79
80 12
    private function read(string $category, string $locale): void
81
    {
82 12
        $path = $this->getFilePath($category, $locale);
83
84 9
        if (is_file($path)) {
85 8
            $messages = include $path;
86
87 8
            if (!is_array($messages)) {
88 8
                throw new RuntimeException('Invalid file format: ' . $path);
89
            }
90
            /** @psalm-var array<string, string> $messages */
91
        } else {
92 1
            $messages = [];
93
        }
94
95 9
        $this->messages[$category][$locale] = $messages;
96
    }
97
98
    /**
99
     * @psalm-param array<string, array<string, string>> $messages
100
     */
101 14
    private function generateMessagesFileContent(array $messages): string
102
    {
103 14
        $content = "<?php\nreturn ";
104 14
        if (empty($messages)) {
105 3
            $content .= '[]';
106
        } else {
107 11
            $content .= $this->messagesToCode($messages);
108 8
            $content .= ';';
109
        }
110 11
        $content .= "\n";
111
112 11
        return $content;
113
    }
114
115
    /**
116
     * @psalm-param array<string, array<string, string>> $messages
117
     */
118 11
    private function messagesToCode(array $messages): string
119
    {
120 11
        $code = '[';
121 11
        foreach ($messages as $messageId => $messageData) {
122 11
            if (!array_key_exists('message', $messageData)) {
123 1
                throw new InvalidArgumentException("Message is not valid for ID \"$messageId\". \"message\" key is missing.");
124
            }
125
126
            /** @psalm-suppress DocblockTypeContradiction */
127 10
            if (!is_string($messageData['message'])) {
128 1
                throw new InvalidArgumentException("Message is not a string for ID \"$messageId\".");
129
            }
130
131 9
            if (array_key_exists('comment', $messageData)) {
132
                /** @psalm-suppress DocblockTypeContradiction */
133 5
                if (!is_string($messageData['comment'])) {
134 1
                    throw new InvalidArgumentException("Message comment is not a string for ID \"$messageId\".");
135
                }
136
137 4
                $code .= "\n" . '    /* ' . $messageData['comment'] . ' */';
138
            }
139
140 8
            $code .= "\n" . '    ';
141 8
            $code .= var_export($messageId, true);
142 8
            $code .= ' => ';
143 8
            $code .= var_export($messageData['message'], true);
144 8
            $code .= ',';
145
        }
146 8
        $code .= "\n" . ']';
147 8
        return $code;
148
    }
149
}
150