Completed
Push — master ( 2b6ea5...1d86c5 )
by Jonas
04:13
created

Translatable::translatableTexts()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace mindtwo\LaravelMultilingual\Models\Traits;
4
5
use Illuminate\Support\Str;
6
use Illuminate\Database\Eloquent\Model;
7
use mindtwo\LaravelMultilingual\Services\Locale;
8
use Illuminate\Database\Eloquent\Relations\MorphMany;
9
use mindtwo\LaravelMultilingual\Exceptions\Exception;
10
use mindtwo\LaravelMultilingual\Exceptions\TranslatableAttributeNotDefinedException;
11
use mindtwo\LaravelMultilingual\Exceptions\TranslatableAttributeTypeNotDefinedException;
12
13
trait Translatable
14
{
15
    /**
16
     * Translatable key/value storage for relation sync after saving.
17
     *
18
     * @var array
19
     */
20
    private $translationValues = [];
21
22
    /**
23
     * The "booting" method of the trait.
24
     */
25
    public static function bootTranslatable()
26
    {
27
        static::saved(function (Model $model) {
28
            foreach ($model->translationValues as $attributeName=>$values) {
29
                $model->storeAttributeTranslations($attributeName, $values);
30
            }
31
        });
32
33
        static::registerSetMutator('translations', 'setAttributeTranslation');
34
        static::registerGetMutator('translations', 'getAttributeTranslation');
35
    }
36
37
    /**
38
     * Determinate if a translatable attribute is defined.
39
     *
40
     * @param string $attribute
41
     *
42
     * @return bool
43
     */
44
    public function hasTranslatableAttribute(string $attribute): bool
45
    {
46
        return isset($this->translations[$attribute]);
0 ignored issues
show
Bug introduced by
The property translations does not exist on mindtwo\LaravelMultiling...els\Traits\Translatable. Did you mean translationValues?
Loading history...
47
    }
48
49
    /**
50
     * Get the translatable attribute name or throw an exception, if it is not defined.
51
     *
52
     * @param $attribute
53
     *
54
     * @throws TranslatableAttributeNotDefinedException
55
     *
56
     * @return string
57
     */
58
    public function translatableAttributeOrFail($attribute): string
59
    {
60
        if (! $this->hasTranslatableAttribute($attribute)) {
61
            throw new TranslatableAttributeNotDefinedException(sprintf('Translatable attribute "%s" not defined', $attribute));
62
        }
63
64
        return $attribute;
65
    }
66
67
    /**
68
     * Get the normalized translatable type.
69
     *
70
     * @param string $type
71
     *
72
     * @return string
73
     */
74
    public function translatableType(string $type): string
75
    {
76
        return Str::singular(strtolower($type));
77
    }
78
79
    /**
80
     * Determinate if a translatable type exists and throw an exception if not.
81
     *
82
     * @param string $type
83
     *
84
     * @throws TranslatableAttributeTypeNotDefinedException
85
     *
86
     * @return string
87
     */
88
    public function translatableTypeOrFail(string $type): string
89
    {
90
        if (! $this->translatableTypeExists($type)) {
91
            throw new TranslatableAttributeTypeNotDefinedException(sprintf('Attribute type "%s" not defined', $type));
92
        }
93
94
        return $this->translatableType($type);
95
    }
96
97
    /**
98
     * Get the normalized translatable type.
99
     *
100
     * @param string $attribute
101
     *
102
     * @throws TranslatableAttributeNotDefinedException
103
     *
104
     * @return string
105
     */
106
    public function translatableTypeByAttribute(string $attribute): string
107
    {
108
        $attribute = $this->translatableAttributeOrFail($attribute);
109
110
        return $this->translatableType($this->translations[$attribute]);
0 ignored issues
show
Bug introduced by
The property translations does not exist on mindtwo\LaravelMultiling...els\Traits\Translatable. Did you mean translationValues?
Loading history...
111
    }
112
113
    /**
114
     * Determinate if a translatable type exists.
115
     *
116
     * @param string $type
117
     *
118
     * @return bool
119
     */
120
    public function translatableTypeExists(string $type): bool
121
    {
122
        return class_exists(config('laravel-multilingual.model.'.$this->translatableType($type)));
123
    }
124
125
    /**
126
     * Get the translatable relation by attribute name.
127
     *
128
     * @param string $name
129
     *
130
     * @throws Exception
131
     *
132
     * @return MorphMany
133
     */
134
    public function translatableRelationByAttribute(string $name): MorphMany
135
    {
136
        return $this->translatableRelationByType(
137
            $this->translatableTypeByAttribute($name)
138
        );
139
    }
140
141
    /**
142
     * Get the translatable relation by type.
143
     *
144
     * @param string $type
145
     *
146
     * @throws TranslatableAttributeTypeNotDefinedException
147
     *
148
     * @return MorphMany
149
     */
150
    public function translatableRelationByType(string $type): MorphMany
151
    {
152
        $type = $this->translatableTypeOrFail($type);
153
154
        return $this->morphMany(config('laravel-multilingual.model.'.$type), 'linkable');
0 ignored issues
show
Bug introduced by
It seems like morphMany() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

154
        return $this->/** @scrutinizer ignore-call */ morphMany(config('laravel-multilingual.model.'.$type), 'linkable');
Loading history...
155
    }
156
157
    /**
158
     * Set attribute translation.
159
     *
160
     * @param string $name
161
     * @param $value
162
     * @param null $locale
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $locale is correct as it would always require null to be passed?
Loading history...
163
     *
164
     * @throws TranslatableAttributeNotDefinedException
165
     *
166
     * @return $this
167
     */
168
    protected function setAttributeTranslation(string $name, $value, $config = null, $locale = null): self
0 ignored issues
show
Unused Code introduced by
The parameter $config is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

168
    protected function setAttributeTranslation(string $name, $value, /** @scrutinizer ignore-unused */ $config = null, $locale = null): self

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
169
    {
170
        $name = $this->translatableAttributeOrFail($name);
171
172
        if (is_null($locale)) {
0 ignored issues
show
introduced by
The condition is_null($locale) is always true.
Loading history...
173
            $locale = app(Locale::class)->current;
0 ignored issues
show
Bug Best Practice introduced by
The property current does not exist on mindtwo\LaravelMultilingual\Services\Locale. Since you implemented __get, consider adding a @property annotation.
Loading history...
174
        }
175
176
        // Convert scalar values to array
177
        $value = ! is_array($value) ? [$locale => $value] : $value;
178
179
        // Map values to translation attributes
180
        $this->translationValues[$name] = collect($value)->mapWithKeys(function ($value, $locale) {
181
            return [$locale => $value];
182
        })->toArray();
183
184
        return $this;
185
    }
186
187
    /**
188
     * Get attribute translation.
189
     *
190
     * @param string      $name
191
     * @param string|null $locale
192
     *
193
     * @throws Exception
194
     * @throws TranslatableAttributeNotDefinedException
195
     *
196
     * @return string
197
     */
198
    public function getAttributeTranslation(string $name, $config = null, string $locale = null): string
0 ignored issues
show
Unused Code introduced by
The parameter $config is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

198
    public function getAttributeTranslation(string $name, /** @scrutinizer ignore-unused */ $config = null, string $locale = null): string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
199
    {
200
        $name = $this->translatableAttributeOrFail($name);
201
202
        if (is_null($locale)) {
203
            $locale = app(Locale::class)->current;
0 ignored issues
show
Bug Best Practice introduced by
The property current does not exist on mindtwo\LaravelMultilingual\Services\Locale. Since you implemented __get, consider adding a @property annotation.
Loading history...
204
        }
205
206
        // Load translations, if there are no values for the given attribute
207
        if (! array_key_exists($name, $this->translationValues)) {
208
            $this->loadAttributeTranslations($name);
209
        }
210
211
        return $this->translationValues[$name][$locale] ?? $this->translationValues[$name][app(Locale::class)->fallback] ?? '';
0 ignored issues
show
Bug Best Practice introduced by
The property fallback does not exist on mindtwo\LaravelMultilingual\Services\Locale. Since you implemented __get, consider adding a @property annotation.
Loading history...
212
    }
213
214
    /**
215
     * @param string      $name
216
     * @param string|null $locale
217
     *
218
     * @throws Exception
219
     *
220
     * @return string
221
     */
222
    public function translate(string $name, string $locale = null)
223
    {
224
        $config = isset($this->translations[$name]) ? $this->translations[$name] : null;
0 ignored issues
show
Bug introduced by
The property translations does not exist on mindtwo\LaravelMultiling...els\Traits\Translatable. Did you mean translationValues?
Loading history...
225
226
        return $this->getAttributeTranslation($name, $config, $locale);
227
    }
228
229
    /**
230
     * @param string $attributeName
231
     * @param array  $values
232
     *
233
     * @throws Exception
234
     */
235
    public function storeAttributeTranslations(string $attributeName, array $values = [])
236
    {
237
        foreach ($values as $locale => $value) {
238
            $this->translatableRelationByAttribute($attributeName)->updateOrCreate(
239
                [
240
                    'key'    => $attributeName,
241
                    'locale' => $locale,
242
                ],
243
                ['value' => $value]
244
            );
245
        }
246
    }
247
248
    /**
249
     * @param string $attribute
250
     *
251
     * @throws Exception
252
     *
253
     * @return Translatable
254
     */
255
    public function loadAttributeTranslations(string $attribute): self
256
    {
257
        $translations = $this->translatableRelationByAttribute($attribute)->where('key', $attribute)->get();
258
259
        $this->translationValues[$attribute] = collect($translations)->mapWithKeys(function ($item) {
260
            return [$item->locale => $item->value];
261
        })->toArray();
262
263
        return $this;
264
    }
265
266
    /**
267
     * Reload the current model instance with fresh attributes from the database.
268
     *
269
     * @return $this
270
     */
271
    public function refresh()
272
    {
273
        $this->translationValues = [];
274
275
        return parent::refresh();
276
    }
277
278
    /**
279
     * Get translations as array.
280
     *
281
     * @param string|null $locale
282
     *
283
     * @return array
284
     */
285
    public function translationsToArray($locale = null): array
286
    {
287
        if (is_null($locale)) {
288
            $locale = app(Locale::class)->current;
0 ignored issues
show
Bug Best Practice introduced by
The property current does not exist on mindtwo\LaravelMultilingual\Services\Locale. Since you implemented __get, consider adding a @property annotation.
Loading history...
289
        }
290
291
        return collect($this->translations)->map(function ($type, $key) use ($locale) {
0 ignored issues
show
Bug introduced by
The property translations does not exist on mindtwo\LaravelMultiling...els\Traits\Translatable. Did you mean translationValues?
Loading history...
292
            return $this->getAttributeTranslation($key, $locale);
293
        })->toArray();
294
    }
295
296
    /**
297
     * Get the model and translations as array.
298
     *
299
     * @param string|null $locale
300
     *
301
     * @return array
302
     */
303
    public function toArrayWithTranslations($locale = null): array
304
    {
305
        if (is_null($locale)) {
306
            $locale = app(Locale::class)->current;
0 ignored issues
show
Bug Best Practice introduced by
The property current does not exist on mindtwo\LaravelMultilingual\Services\Locale. Since you implemented __get, consider adding a @property annotation.
Loading history...
307
        }
308
309
        return array_merge(
310
            $this->toArray(),
0 ignored issues
show
Bug introduced by
The method toArray() does not exist on mindtwo\LaravelMultiling...els\Traits\Translatable. Did you maybe mean toArrayWithTranslations()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

310
            $this->/** @scrutinizer ignore-call */ 
311
                   toArray(),

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
311
            $this->translationsToArray($locale)
312
        );
313
    }
314
315
    public function translatableTexts() {
316
        return $this->translatableRelationByType('Texts');
317
        
318
    }
319
    public function translatableStrings() {
320
        return $this->translatableRelationByType('Strings');
321
    }
322
}
323