Completed
Pull Request — master (#140)
by ARCANEDEV
17:13
created

HasTranslations::getTranslationsAttribute()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 8
ccs 5
cts 5
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php namespace Arcanedev\Localization\Traits;
2
3
use Arcanedev\Localization\Events\TranslationHasBeenSet;
4
use Arcanedev\Localization\Exceptions\UntranslatableAttributeException;
5
use Illuminate\Support\Str;
6
7
/**
8
 * Trait     HasTranslations
9
 *
10
 * @package  Arcanedev\Localization\Traits
11
 * @author   ARCANEDEV <[email protected]>
12
 *
13
 * @property       array  attributes
14
 * @property-read  array  translations
15
 */
16
trait HasTranslations
17
{
18
    /* -----------------------------------------------------------------
19
     |  Getters
20
     | -----------------------------------------------------------------
21
     */
22
23
    /**
24
     * Get the translations.
25
     *
26
     * @return array
27
     */
28 4
    public function getTranslationsAttribute(): array
29
    {
30 4
        return collect($this->getTranslatableAttributes())
31
            ->mapWithKeys(function (string $key) {
32 4
                return [$key => $this->getTranslations($key)];
33 4
            })
34 4
            ->toArray();
35
    }
36
37
    /* -----------------------------------------------------------------
38
     |  Main Methods
39
     | -----------------------------------------------------------------
40
     */
41
42
    /**
43
     * Get the translatable attributes.
44
     *
45
     * @return array
46
     */
47
    abstract public function getTranslatableAttributes();
48
49
    /**
50
     * Get the translated attribute value.
51
     *
52
     * @param  string  $key
53
     *
54
     * @return mixed
55
     */
56 32
    public function getAttributeValue($key)
57
    {
58 32
        return $this->isTranslatableAttribute($key)
59 28
            ? $this->getTranslation($key, $this->getLocale())
60 32
            : parent::getAttributeValue($key);
61
    }
62
63
    /**
64
     * Set a given attribute on the model.
65
     *
66
     * @param  string  $key
67
     * @param  mixed   $value
68
     *
69
     * @return self
70
     */
71 80
    public function setAttribute($key, $value)
72
    {
73 80
        return ( ! $this->isTranslatableAttribute($key) || is_array($value))
74 80
            ? parent::setAttribute($key, $value)
75 80
            : $this->setTranslation($key, $this->getLocale(), $value);
76
    }
77
78
    /**
79
     * Get the translated attribute (alias).
80
     *
81
     * @param  string  $key
82
     * @param  string  $locale
83
     *
84
     * @return mixed
85
     */
86 8
    public function trans($key, $locale = '')
87
    {
88 8
        return $this->getTranslation($key, $locale);
89
    }
90
91
    /***
92
     * Get the translated attribute.
93
     *
94
     * @param  string  $key
95
     * @param  string  $locale
96
     * @param  bool    $useFallbackLocale
97
     *
98
     * @return mixed
99
     */
100 64
    public function getTranslation($key, $locale, $useFallbackLocale = true)
101
    {
102 64
        $locale       = $this->normalizeLocale($key, $locale, $useFallbackLocale);
103 64
        $translations = $this->getTranslations($key);
104 64
        $translation  = $translations[$locale] ?? '';
105
106 64
        return $this->hasGetMutator($key)
107 60
            ? $this->mutateAttribute($key, $translation)
108 64
            : $translation;
109
    }
110
111
    /**
112
     * Get the translations for the given key.
113
     *
114
     * @param  string|null  $key
115
     *
116
     * @return array
117
     */
118 96
    public function getTranslations($key = null)
119
    {
120 96
        if ($key !== null) {
121 96
            $this->guardAgainstNonTranslatableAttribute($key);
122
123
            return array_filter(json_decode($this->getAttributeFromArray($key) ?? '' ?: '{}', true) ?: [], function ($value) {
124 92
                return $value !== null && $value !== false && $value !== '';
125 96
            });
126
        }
127
128
        return array_reduce($this->getTranslatableAttributes(), function ($result, $item) {
129 4
            $result[$item] = $this->getTranslations($item);
130
131 4
            return $result;
132 4
        });
133
    }
134
135
    /**
136
     * Set a translation.
137
     *
138
     * @param  string  $key
139
     * @param  string  $locale
140
     * @param  string  $value
141
     *
142
     * @return self
143
     */
144 92
    public function setTranslation($key, $locale, $value)
145
    {
146 92
        $this->guardAgainstNonTranslatableAttribute($key);
147
148 88
        $translations = $this->getTranslations($key);
149 88
        $oldValue     = $translations[$locale] ?? '';
150
151 88
        if ($this->hasSetMutator($key)) {
152 16
            $this->{'set'.Str::studly($key).'Attribute'}($value);
153 16
            $value = $this->attributes[$key];
154
        }
155
156 88
        $translations[$locale]  = $value;
157 88
        $this->attributes[$key] = $this->asJson($translations);
158
159 88
        event(new TranslationHasBeenSet($this, $key, $locale, $oldValue, $value));
160
161 88
        return $this;
162
    }
163
164
    /**
165
     * Set the translations.
166
     *
167
     * @param  string  $key
168
     * @param  array   $translations
169
     *
170
     * @return self
171
     */
172 8
    public function setTranslations($key, array $translations)
173
    {
174 8
        $this->guardAgainstNonTranslatableAttribute($key);
175
176 8
        foreach ($translations as $locale => $translation) {
177 8
            $this->setTranslation($key, $locale, $translation);
178
        }
179
180 8
        return $this;
181
    }
182
183
    /**
184
     * Forget a translation.
185
     *
186
     * @param  string  $key
187
     * @param  string  $locale
188
     *
189
     * @return self
190
     */
191 8
    public function forgetTranslation($key, $locale)
192
    {
193 8
        $translations = $this->getTranslations($key);
194 8
        unset($translations[$locale]);
195
196 8
        if ($this->hasSetMutator($key))
197 4
            $this->attributes[$key] = $this->asJson($translations);
198
        else
199 8
            $this->setAttribute($key, $translations);
200
201 8
        return $this;
202
    }
203
204
    /**
205
     * Forget all the translations by the given locale.
206
     *
207
     * @param  string  $locale
208
     *
209
     * @return self
210
     */
211 4
    public function flushTranslations($locale)
212
    {
213
        collect($this->getTranslatableAttributes())->each(function (string $attribute) use ($locale) {
214 4
            $this->forgetTranslation($attribute, $locale);
215 4
        });
216
217 4
        return $this;
218
    }
219
220
    /**
221
     * Get the translated attribute's locales
222
     *
223
     * @param  string  $key
224
     *
225
     * @return array
226
     */
227 68
    public function getTranslatedLocales($key): array
228
    {
229 68
        return array_keys($this->getTranslations($key));
230
    }
231
232
    /**
233
     * Check if has a translation.
234
     *
235
     * @param  string       $key
236
     * @param  string|null  $locale
237
     *
238
     * @return bool
239
     */
240 4
    public function hasTranslation(string $key, string $locale = null): bool
241
    {
242 4
        $locale = $locale ?: $this->getLocale();
243
244 4
        return isset($this->getTranslations($key)[$locale]);
245
    }
246
247
    /**
248
     * Check if the attribute is translatable.
249
     *
250
     * @param  string  $key
251
     *
252
     * @return bool
253
     */
254 104
    public function isTranslatableAttribute($key)
255
    {
256 104
        return in_array($key, $this->getTranslatableAttributes());
257
    }
258
259
    /* -----------------------------------------------------------------
260
     |  Other Methods
261
     | -----------------------------------------------------------------
262
     */
263
264
    /**
265
     * Get the locale.
266
     *
267
     * @return string
268
     */
269 28
    protected function getLocale(): string
270
    {
271 28
        return config('app.locale');
272
    }
273
274
    /**
275
     * Guard against untranslatable attribute.
276
     *
277
     * @param  string  $key
278
     */
279 100
    protected function guardAgainstNonTranslatableAttribute($key)
280
    {
281 100
        if ( ! $this->isTranslatableAttribute($key)) {
282 4
            throw UntranslatableAttributeException::make($key, $this->getTranslatableAttributes());
283
        }
284 96
    }
285
286
    /**
287
     * Normalize the locale.
288
     *
289
     * @param  string  $key
290
     * @param  string  $locale
291
     * @param  bool    $useFallback
292
     *
293
     * @return string
294
     */
295 64
    protected function normalizeLocale($key, $locale, $useFallback)
296
    {
297 64
        if (in_array($locale, $this->getTranslatedLocales($key)) || ! $useFallback)
298 48
            return $locale;
299
300 20
        return config('app.fallback_locale') ?: $locale;
301
    }
302
303
    /* -----------------------------------------------------------------
304
     |  Eloquent Methods
305
     | -----------------------------------------------------------------
306
     */
307
308
    /**
309
     * Get the casts array.
310
     *
311
     * @return array
312
     */
313 84
    public function getCasts()
314
    {
315 84
        return array_merge(
316 84
            parent::getCasts(),
317 84
            array_fill_keys($this->getTranslatableAttributes(), 'array')
318
        );
319
    }
320
321
    /**
322
     * Determine if a get mutator exists for an attribute.
323
     *
324
     * @param  string  $key
325
     *
326
     * @return bool
327
     */
328
    abstract public function hasGetMutator($key);
329
330
    /**
331
     * Get the value of an attribute using its mutator.
332
     *
333
     * @param  string  $key
334
     * @param  mixed   $value
335
     *
336
     * @return mixed
337
     */
338
    abstract protected function mutateAttribute($key, $value);
339
340
    /**
341
     * Get an attribute from the $attributes array.
342
     *
343
     * @param  string  $key
344
     *
345
     * @return mixed
346
     */
347
    abstract protected function getAttributeFromArray($key);
348
349
    /**
350
     * Determine if a set mutator exists for an attribute.
351
     *
352
     * @param  string  $key
353
     *
354
     * @return bool
355
     */
356
    abstract public function hasSetMutator($key);
357
358
    /**
359
     * Encode the given value as JSON.
360
     *
361
     * @param  mixed  $value
362
     *
363
     * @return string
364
     */
365
    abstract protected function asJson($value);
366
}
367