Completed
Push — master ( 151257...299aae )
by Mārtiņš
02:09
created

MessageStorage::getPluralCount()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 4
nc 2
nop 1
crap 2
1
<?php
2
3
namespace Printful\GettextCms;
4
5
use Gettext\Languages\Language;
6
use Gettext\Translation;
7
use Gettext\Translations;
8
use Printful\GettextCms\Exceptions\InvalidTranslationException;
9
use Printful\GettextCms\Interfaces\MessageRepositoryInterface;
10
use Printful\GettextCms\Structures\MessageItem;
11
12
/**
13
 * Class handles all saving and retrieving logic of translations using the given repository
14
 */
15
class MessageStorage
16
{
17
    /** @var MessageRepositoryInterface */
18
    private $repository;
19
20
    /**
21
     * Cache for plural form counts
22
     * @var array [locale => plural count, ..]
23
     */
24
    private $pluralFormCache = [];
25
26 17
    public function __construct(MessageRepositoryInterface $repository)
27
    {
28 17
        $this->repository = $repository;
29 17
    }
30
31
    /**
32
     * Save translation object for a single domain and locale
33
     *
34
     * @param Translations $translations
35
     * @throws InvalidTranslationException
36
     */
37 6
    public function saveTranslations(Translations $translations)
38
    {
39 6
        $locale = $translations->getLanguage();
40 6
        $domain = (string)$translations->getDomain();
41
42 6
        if (!$locale) {
43 1
            throw new InvalidTranslationException('Locale is missing');
44
        }
45
46 5
        if (!$domain) {
47 1
            throw new InvalidTranslationException('Domain is missing');
48
        }
49
50 4
        foreach ($translations as $v) {
51 4
            $this->saveSingleTranslation($locale, $domain, $v);
52
        }
53 4
    }
54
55
    /**
56
     * Save a translation to database by merging it to a previously saved version.
57
     *
58
     * @param string $locale
59
     * @param string $domain
60
     * @param Translation $translation
61
     */
62 12
    public function saveSingleTranslation(string $locale, string $domain, Translation $translation)
63
    {
64 12
        $key = $this->getKey($locale, $domain, $translation);
65
66 12
        $existingItem = $this->repository->getSingle($key);
67
68 12
        if ($existingItem->exists()) {
69 2
            $existingTranslation = $this->itemToTranslation($existingItem);
70 2
            $existingTranslation->mergeWith($translation);
71 2
            $item = $this->translationToItem($locale, $domain, $existingTranslation);
72
73
            // Override the disabled state of the existing translation
74 2
            $item->isDisabled = $translation->isDisabled();
75
        } else {
76 12
            $item = $this->translationToItem($locale, $domain, $translation);
77
        }
78
79 12
        $item->hasOriginalTranslation = $translation->hasTranslation();
80 12
        $item->requiresTranslating = $this->requiresTranslating($locale, $translation);
81
82 12
        $this->repository->save($item);
83 12
    }
84
85
    /**
86
     * Check if some translations are missing (original or missing plural forms)
87
     *
88
     * @param string $locale
89
     * @param Translation $translation
90
     * @return bool
91
     */
92 12
    private function requiresTranslating(string $locale, Translation $translation): bool
93
    {
94 12
        if (!$translation->hasTranslation()) {
95 7
            return true;
96
        }
97
98 9
        if ($translation->hasPlural()) {
99 5
            $translatedPluralCount = count(array_filter($translation->getPluralTranslations()));
100
            // If there are less plural translations than language requires, this needs translating
101 5
            return $this->getPluralCount($locale) !== $translatedPluralCount;
102
        }
103
104 4
        return false;
105
    }
106
107
    /**
108
     * Get number of plural forms for this locale
109
     *
110
     * @param string $locale
111
     * @return int
112
     * @throws \InvalidArgumentException Thrown in the locale is not correct
113
     */
114 5
    private function getPluralCount(string $locale): int
115
    {
116 5
        if (!array_key_exists($locale, $this->pluralFormCache)) {
117 5
            $info = Language::getById($locale);
118 5
            $this->pluralFormCache[$locale] = count($info->categories);
119
        }
120
121 5
        return $this->pluralFormCache[$locale];
122
    }
123
124
    /**
125
     * Generate a unique key for storage (basically a primary key)
126
     *
127
     * @param string $locale
128
     * @param string $domain
129
     * @param Translation $translation
130
     * @return string
131
     */
132 12
    private function getKey(string $locale, string $domain, Translation $translation): string
133
    {
134 12
        return md5($locale . '|' . $domain . '|' . $translation->getContext() . '|' . $translation->getOriginal());
135
    }
136
137
    /**
138
     * Convert a message item to a translation item
139
     *
140
     * @param MessageItem $item
141
     * @return Translation
142
     */
143 11
    private function itemToTranslation(MessageItem $item): Translation
144
    {
145 11
        $translation = new Translation($item->context, $item->original, $item->originalPlural);
146
147 11
        $translation->setTranslation($item->translation);
148 11
        $translation->setPluralTranslations($item->pluralTranslations);
149 11
        $translation->setDisabled($item->isDisabled);
150
151 11
        foreach ($item->references as $v) {
152 1
            $translation->addReference($v[0], $v[1]);
153
        }
154
155 11
        foreach ($item->comments as $v) {
156 1
            $translation->addComment($v);
157
        }
158
159 11
        foreach ($item->extractedComments as $v) {
160 1
            $translation->addExtractedComment($v);
161
        }
162
163 11
        return $translation;
164
    }
165
166
    /**
167
     * Convert a translation item to a message item
168
     *
169
     * @param string $locale
170
     * @param string $domain
171
     * @param Translation $translation
172
     * @return MessageItem
173
     */
174 12
    private function translationToItem(string $locale, string $domain, Translation $translation): MessageItem
175
    {
176 12
        $item = new MessageItem;
177
178 12
        $item->key = $this->getKey($locale, $domain, $translation);
179 12
        $item->domain = $domain;
180 12
        $item->locale = $locale;
181 12
        $item->context = (string)$translation->getContext();
182 12
        $item->original = $translation->getOriginal();
183 12
        $item->translation = $translation->getTranslation();
184 12
        $item->originalPlural = $translation->getPlural();
185 12
        $item->pluralTranslations = $translation->getPluralTranslations();
186 12
        $item->references = $translation->getReferences();
187 12
        $item->comments = $translation->getComments();
188 12
        $item->extractedComments = $translation->getExtractedComments();
189 12
        $item->isDisabled = $translation->isDisabled();
190
191 12
        return $item;
192
    }
193
194
    /**
195
     * All translations, including disabled, enabled and untranslated
196
     *
197
     * @param string $locale
198
     * @param $domain
199
     * @return Translations
200
     */
201 6
    public function getAll(string $locale, $domain): Translations
202
    {
203 6
        return $this->convertItems(
204 6
            $locale,
205 6
            (string)$domain,
206 6
            $this->repository->getAll($locale, (string)$domain)
207
        );
208
    }
209
210
    /**
211
     * All enabled translations including untranslated
212
     *
213
     * @param string $locale
214
     * @param $domain
215
     * @return Translations
216
     */
217 2
    public function getAllEnabled(string $locale, $domain): Translations
218
    {
219 2
        return $this->convertItems(
220 2
            $locale,
221 2
            (string)$domain,
222 2
            $this->repository->getEnabled($locale, (string)$domain)
223
        );
224
    }
225
226
    /**
227
     * Enabled and translated translations only
228
     *
229
     * @param string $locale
230
     * @param $domain
231
     * @return Translations
232
     */
233 2
    public function getEnabledTranslated(string $locale, $domain): Translations
234
    {
235 2
        return $this->convertItems(
236 2
            $locale,
237 2
            (string)$domain,
238 2
            $this->repository->getEnabledTranslated($locale, (string)$domain)
239
        );
240
    }
241
242
    /**
243
     * Enabled and translated translations only
244
     *
245
     * @param string $locale
246
     * @param $domain
247
     * @return Translations
248
     */
249 6
    public function getRequiresTranslating(string $locale, $domain): Translations
250
    {
251 6
        return $this->convertItems(
252 6
            $locale,
253 6
            (string)$domain,
254 6
            $this->repository->getRequiresTranslating($locale, (string)$domain)
255
        );
256
    }
257
258
    /**
259
     * Converts message items to a translation object
260
     *
261
     * @param string $locale
262
     * @param string|null $domain
263
     * @param MessageItem[] $items
264
     * @return Translations
265
     */
266 14
    private function convertItems(string $locale, $domain, array $items): Translations
267
    {
268 14
        $domain = (string)$domain;
269
270 14
        $translations = new Translations;
271 14
        $translations->setDomain($domain);
272 14
        $translations->setLanguage($locale);
273
274 14
        foreach ($items as $v) {
275 11
            $translation = $this->itemToTranslation($v);
276 11
            $translations[] = $translation;
277
        }
278
279 14
        return $translations;
280
    }
281
282
    /**
283
     * Mark all messages in the given domain and locale as disabled
284
     *
285
     * @param string $locale
286
     * @param string $domain
287
     */
288 2
    public function disableAll(string $locale, string $domain)
289
    {
290 2
        $this->repository->disableAll($locale, $domain);
291
    }
292
}