Completed
Pull Request — master (#140)
by ARCANEDEV
08:35
created

HasTranslations::hasTranslation()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 2
dl 0
loc 6
ccs 3
cts 3
cp 1
crap 2
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-read  array  translations
14
 */
15
trait HasTranslations
16
{
17
    /* -----------------------------------------------------------------
18
     |  Getters
19
     | -----------------------------------------------------------------
20
     */
21
22
    /**
23
     * Get the translations.
24
     *
25
     * @return array
26
     */
27 4
    public function getTranslationsAttribute(): array
28
    {
29 4
        return collect($this->getTranslatableAttributes())
30
            ->mapWithKeys(function (string $key) {
31 4
                return [$key => $this->getTranslations($key)];
32 4
            })
33 4
            ->toArray();
34
    }
35
36
    /* -----------------------------------------------------------------
37
     |  Main Methods
38
     | -----------------------------------------------------------------
39
     */
40
41
    /**
42
     * Get the translatable attributes.
43
     *
44
     * @return array
45
     */
46
    abstract public function getTranslatableAttributes();
47
48
    /**
49
     * Get the translated attribute value.
50
     *
51
     * @param  string  $key
52
     *
53
     * @return mixed
54
     */
55 32
    public function getAttributeValue($key)
56
    {
57 32
        return $this->isTranslatableAttribute($key)
58 28
            ? $this->getTranslation($key, $this->getLocale())
59 32
            : parent::getAttributeValue($key);
60
    }
61
62
    /**
63
     * Set a given attribute on the model.
64
     *
65
     * @param  string  $key
66
     * @param  mixed   $value
67
     *
68
     * @return self
69
     */
70 80
    public function setAttribute($key, $value)
71
    {
72 80
        return ( ! $this->isTranslatableAttribute($key) || is_array($value))
73 80
            ? parent::setAttribute($key, $value)
74 80
            : $this->setTranslation($key, $this->getLocale(), $value);
75
    }
76
77
    /**
78
     * Get the translated attribute (alias).
79
     *
80
     * @param  string  $key
81
     * @param  string  $locale
82
     *
83
     * @return mixed
84
     */
85 8
    public function trans($key, $locale = '')
86
    {
87 8
        return $this->getTranslation($key, $locale);
88
    }
89
90
    /***
91
     * Get the translated attribute.
92
     *
93
     * @param  string  $key
94
     * @param  string  $locale
95
     * @param  bool    $useFallbackLocale
96
     *
97
     * @return mixed
98
     */
99 64
    public function getTranslation($key, $locale, $useFallbackLocale = true)
100
    {
101 64
        $locale       = $this->normalizeLocale($key, $locale, $useFallbackLocale);
102 64
        $translations = $this->getTranslations($key);
103 64
        $translation  = $translations[$locale] ?? '';
104
105 64
        return $this->hasGetMutator($key)
106 60
            ? $this->mutateAttribute($key, $translation)
107 64
            : $translation;
108
    }
109
110
    /**
111
     * Get the translations for the given key.
112
     *
113
     * @param  string|null  $key
114
     *
115
     * @return array
116
     */
117 96
    public function getTranslations($key = null)
118
    {
119 96
        if ($key !== null) {
120 96
            $this->guardAgainstNonTranslatableAttribute($key);
121
122
            return array_filter(json_decode($this->getAttributeFromArray($key) ?? '' ?: '{}', true) ?: [], function ($value) {
123 92
                return $value !== null && $value !== false && $value !== '';
124 96
            });
125
        }
126
127
        return array_reduce($this->getTranslatableAttributes(), function ($result, $item) {
128 4
            $result[$item] = $this->getTranslations($item);
129
130 4
            return $result;
131 4
        });
132
    }
133
134
    /**
135
     * Set a translation.
136
     *
137
     * @param  string  $key
138
     * @param  string  $locale
139
     * @param  string  $value
140
     *
141
     * @return self
142
     */
143 92
    public function setTranslation($key, $locale, $value)
144
    {
145 92
        $this->guardAgainstNonTranslatableAttribute($key);
146
147 88
        $translations = $this->getTranslations($key);
148 88
        $oldValue     = $translations[$locale] ?? '';
149
150 88
        if ($this->hasSetMutator($key)) {
151 16
            $this->{'set'.Str::studly($key).'Attribute'}($value);
152 16
            $value = $this->attributes[$key];
0 ignored issues
show
Bug introduced by
The property attributes does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
153
        }
154
155 88
        $translations[$locale]  = $value;
156 88
        $this->attributes[$key] = $this->asJson($translations);
157
158 88
        event(new TranslationHasBeenSet($this, $key, $locale, $oldValue, $value));
159
160 88
        return $this;
161
    }
162
163
    /**
164
     * Set the translations.
165
     *
166
     * @param  string  $key
167
     * @param  array   $translations
168
     *
169
     * @return self
170
     */
171 8
    public function setTranslations($key, array $translations)
172
    {
173 8
        $this->guardAgainstNonTranslatableAttribute($key);
174
175 8
        foreach ($translations as $locale => $translation) {
176 8
            $this->setTranslation($key, $locale, $translation);
177
        }
178
179 8
        return $this;
180
    }
181
182
    /**
183
     * Forget a translation.
184
     *
185
     * @param  string  $key
186
     * @param  string  $locale
187
     *
188
     * @return self
189
     */
190 8
    public function forgetTranslation($key, $locale)
191
    {
192 8
        $translations = $this->getTranslations($key);
193 8
        unset($translations[$locale]);
194
195 8
        if ($this->hasSetMutator($key))
196 4
            $this->attributes[$key] = $this->asJson($translations);
197
        else
198 8
            $this->setAttribute($key, $translations);
199
200 8
        return $this;
201
    }
202
203
    /**
204
     * Forget all the translations by the given locale.
205
     *
206
     * @param  string  $locale
207
     *
208
     * @return self
209
     */
210 4
    public function flushTranslations($locale)
211
    {
212
        collect($this->getTranslatableAttributes())->each(function (string $attribute) use ($locale) {
213 4
            $this->forgetTranslation($attribute, $locale);
214 4
        });
215
216 4
        return $this;
217
    }
218
219
    /**
220
     * Get the translated attribute's locales
221
     *
222
     * @param  string  $key
223
     *
224
     * @return array
225
     */
226 68
    public function getTranslatedLocales($key): array
227
    {
228 68
        return array_keys($this->getTranslations($key));
229
    }
230
231
    /**
232
     * Check if has a translation.
233
     *
234
     * @param  string       $key
235
     * @param  string|null  $locale
236
     *
237
     * @return bool
238
     */
239 4
    public function hasTranslation(string $key, string $locale = null): bool
240
    {
241 4
        $locale = $locale ?: $this->getLocale();
242
243 4
        return isset($this->getTranslations($key)[$locale]);
244
    }
245
246
    /**
247
     * Check if the attribute is translatable.
248
     *
249
     * @param  string  $key
250
     *
251
     * @return bool
252
     */
253 104
    public function isTranslatableAttribute($key)
254
    {
255 104
        return in_array($key, $this->getTranslatableAttributes());
256
    }
257
258
    /* -----------------------------------------------------------------
259
     |  Other Methods
260
     | -----------------------------------------------------------------
261
     */
262
263
    /**
264
     * Get the locale.
265
     *
266
     * @return string
267
     */
268 28
    protected function getLocale(): string
269
    {
270 28
        return config('app.locale');
271
    }
272
273
    /**
274
     * Guard against untranslatable attribute.
275
     *
276
     * @param  string  $key
277
     */
278 100
    protected function guardAgainstNonTranslatableAttribute($key)
279
    {
280 100
        if ( ! $this->isTranslatableAttribute($key)) {
281 4
            throw UntranslatableAttributeException::make($key, $this->getTranslatableAttributes());
282
        }
283 96
    }
284
285
    /**
286
     * Normalize the locale.
287
     *
288
     * @param  string  $key
289
     * @param  string  $locale
290
     * @param  bool    $useFallback
291
     *
292
     * @return string
293
     */
294 64
    protected function normalizeLocale($key, $locale, $useFallback)
295
    {
296 64
        if (in_array($locale, $this->getTranslatedLocales($key)) || ! $useFallback)
297 48
            return $locale;
298
299 20
        return config('app.fallback_locale') ?: $locale;
300
    }
301
302
    /* -----------------------------------------------------------------
303
     |  Eloquent Methods
304
     | -----------------------------------------------------------------
305
     */
306
307
    /**
308
     * Get the casts array.
309
     *
310
     * @return array
311
     */
312 84
    public function getCasts()
313
    {
314 84
        return array_merge(
315 84
            parent::getCasts(),
316 84
            array_fill_keys($this->getTranslatableAttributes(), 'array')
317
        );
318
    }
319
320
    /**
321
     * Determine if a get mutator exists for an attribute.
322
     *
323
     * @param  string  $key
324
     *
325
     * @return bool
326
     */
327
    abstract public function hasGetMutator($key);
328
329
    /**
330
     * Get the value of an attribute using its mutator.
331
     *
332
     * @param  string  $key
333
     * @param  mixed   $value
334
     *
335
     * @return mixed
336
     */
337
    abstract protected function mutateAttribute($key, $value);
338
339
    /**
340
     * Get an attribute from the $attributes array.
341
     *
342
     * @param  string  $key
343
     *
344
     * @return mixed
345
     */
346
    abstract protected function getAttributeFromArray($key);
347
348
    /**
349
     * Determine if a set mutator exists for an attribute.
350
     *
351
     * @param  string  $key
352
     *
353
     * @return bool
354
     */
355
    abstract public function hasSetMutator($key);
356
357
    /**
358
     * Encode the given value as JSON.
359
     *
360
     * @param  mixed  $value
361
     *
362
     * @return string
363
     */
364
    abstract protected function asJson($value);
365
}
366