Completed
Pull Request — master (#100)
by ARCANEDEV
22:26 queued 05:58
created

guardAgainstUntranslatableAttribute()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

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