Passed
Push — master ( 8f0854...fda695 )
by Mārtiņš
02:37
created

MessageStorage::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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