1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Dimsav\Translatable; |
4
|
|
|
|
5
|
|
|
use App; |
6
|
|
|
use Dimsav\Translatable\Exception\LocalesNotDefinedException; |
7
|
|
|
use Illuminate\Database\Eloquent\Builder; |
8
|
|
|
use Illuminate\Database\Eloquent\MassAssignmentException; |
9
|
|
|
use Illuminate\Database\Eloquent\Model; |
10
|
|
|
use Illuminate\Database\Eloquent\Relations\Relation; |
11
|
|
|
use Illuminate\Database\Query\Builder as QueryBuilder; |
12
|
|
|
|
13
|
|
|
trait Translatable |
14
|
|
|
{ |
15
|
|
|
/** |
16
|
|
|
* Alias for getTranslation(). |
17
|
|
|
* |
18
|
|
|
* @param string|null $locale |
19
|
|
|
* @param bool $withFallback |
20
|
|
|
* |
21
|
|
|
* @return \Illuminate\Database\Eloquent\Model|null |
22
|
|
|
*/ |
23
|
|
|
public function translate($locale = null, $withFallback = false) |
24
|
|
|
{ |
25
|
|
|
return $this->getTranslation($locale, $withFallback); |
26
|
|
|
} |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* Alias for getTranslation(). |
30
|
|
|
* |
31
|
|
|
* @param string $locale |
32
|
|
|
* |
33
|
|
|
* @return \Illuminate\Database\Eloquent\Model|null |
34
|
|
|
*/ |
35
|
|
|
public function translateOrDefault($locale) |
36
|
|
|
{ |
37
|
|
|
return $this->getTranslation($locale, true); |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Alias for getTranslationOrNew(). |
42
|
|
|
* |
43
|
|
|
* @param string $locale |
44
|
|
|
* |
45
|
|
|
* @return \Illuminate\Database\Eloquent\Model|null |
46
|
|
|
*/ |
47
|
|
|
public function translateOrNew($locale) |
48
|
|
|
{ |
49
|
|
|
return $this->getTranslationOrNew($locale); |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @param string|null $locale |
54
|
|
|
* @param bool $withFallback |
55
|
|
|
* |
56
|
|
|
* @return \Illuminate\Database\Eloquent\Model|null |
57
|
|
|
*/ |
58
|
|
|
public function getTranslation($locale = null, $withFallback = null) |
59
|
|
|
{ |
60
|
|
|
$configFallbackLocale = $this->getFallbackLocale($locale); |
|
|
|
|
61
|
|
|
$locale = $locale ?: $this->locale(); |
62
|
|
|
$withFallback = $withFallback === null ? $this->useFallback() : $withFallback; |
63
|
|
|
$fallbackLocale = $this->getFallbackLocale($locale); |
64
|
|
|
|
65
|
|
|
if ($translation = $this->getTranslationByLocaleKey($locale)) { |
66
|
|
|
return $translation; |
67
|
|
|
} |
68
|
|
|
if ($withFallback && $fallbackLocale) { |
69
|
|
|
if ($translation = $this->getTranslationByLocaleKey($fallbackLocale)) { |
70
|
|
|
return $translation; |
71
|
|
|
} |
72
|
|
|
if ($translation = $this->getTranslationByLocaleKey($configFallbackLocale)) { |
73
|
|
|
return $translation; |
74
|
|
|
} |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
return null; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @param string|null $locale |
82
|
|
|
* |
83
|
|
|
* @return bool |
84
|
|
|
*/ |
85
|
|
|
public function hasTranslation($locale = null) |
86
|
|
|
{ |
87
|
|
|
$locale = $locale ?: $this->locale(); |
88
|
|
|
|
89
|
|
|
foreach ($this->translations as $translation) { |
|
|
|
|
90
|
|
|
if ($translation->getAttribute($this->getLocaleKey()) == $locale) { |
91
|
|
|
return true; |
92
|
|
|
} |
93
|
|
|
} |
94
|
|
|
|
95
|
|
|
return false; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* @return string |
100
|
|
|
*/ |
101
|
|
|
public function getTranslationModelName() |
102
|
|
|
{ |
103
|
|
|
return $this->translationModel ?: $this->getTranslationModelNameDefault(); |
|
|
|
|
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* @return string |
108
|
|
|
*/ |
109
|
|
|
public function getTranslationModelNameDefault() |
110
|
|
|
{ |
111
|
|
|
$config = app()->make('config'); |
112
|
|
|
|
113
|
|
|
return get_class($this).$config->get('translatable.translation_suffix', 'Translation'); |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
/** |
117
|
|
|
* @return string |
118
|
|
|
*/ |
119
|
|
|
public function getRelationKey() |
120
|
|
|
{ |
121
|
|
|
if ($this->translationForeignKey) { |
122
|
|
|
$key = $this->translationForeignKey; |
|
|
|
|
123
|
|
|
} elseif ($this->primaryKey !== 'id') { |
|
|
|
|
124
|
|
|
$key = $this->primaryKey; |
125
|
|
|
} else { |
126
|
|
|
$key = $this->getForeignKey(); |
|
|
|
|
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
return $key; |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* @return string |
134
|
|
|
*/ |
135
|
|
|
public function getLocaleKey() |
136
|
|
|
{ |
137
|
|
|
$config = app()->make('config'); |
138
|
|
|
|
139
|
|
|
return $this->localeKey ?: $config->get('translatable.locale_key', 'locale'); |
|
|
|
|
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* @return \Illuminate\Database\Eloquent\Relations\HasMany |
144
|
|
|
*/ |
145
|
|
|
public function translations() |
146
|
|
|
{ |
147
|
|
|
return $this->hasMany($this->getTranslationModelName(), $this->getRelationKey()); |
|
|
|
|
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* @param string $key |
152
|
|
|
* |
153
|
|
|
* @return mixed |
154
|
|
|
*/ |
155
|
|
|
public function getAttribute($key) |
156
|
|
|
{ |
157
|
|
View Code Duplication |
if (str_contains($key, ':')) { |
|
|
|
|
158
|
|
|
list($key, $locale) = explode(':', $key); |
159
|
|
|
} else { |
160
|
|
|
$locale = $this->locale(); |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
if ($this->isTranslationAttribute($key)) { |
164
|
|
|
if ($this->getTranslation($locale) === null) { |
165
|
|
|
return null; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
// If the given $key has a mutator, we push it to $attributes and then call getAttributeValue |
169
|
|
|
// on it. This way, we can use Eloquent's checking for Mutation, type casting, and |
170
|
|
|
// Date fields. |
171
|
|
|
if ($this->hasGetMutator($key)) { |
|
|
|
|
172
|
|
|
$this->attributes[$key] = $this->getTranslation($locale)->$key; |
|
|
|
|
173
|
|
|
|
174
|
|
|
return $this->getAttributeValue($key); |
|
|
|
|
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
return $this->getTranslation($locale)->$key; |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
return parent::getAttribute($key); |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* @param string $key |
185
|
|
|
* @param mixed $value |
186
|
|
|
*/ |
187
|
|
|
public function setAttribute($key, $value) |
188
|
|
|
{ |
189
|
|
View Code Duplication |
if (str_contains($key, ':')) { |
|
|
|
|
190
|
|
|
list($key, $locale) = explode(':', $key); |
191
|
|
|
} else { |
192
|
|
|
$locale = $this->locale(); |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
if ($this->isTranslationAttribute($key)) { |
196
|
|
|
$this->getTranslationOrNew($locale)->$key = $value; |
197
|
|
|
} else { |
198
|
|
|
return parent::setAttribute($key, $value); |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
return $this; |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* @param array $options |
206
|
|
|
* |
207
|
|
|
* @return bool |
208
|
|
|
*/ |
209
|
|
|
public function save(array $options = []) |
210
|
|
|
{ |
211
|
|
|
if ($this->exists) { |
|
|
|
|
212
|
|
|
if (count($this->getDirty()) > 0) { |
|
|
|
|
213
|
|
|
// If $this->exists and dirty, parent::save() has to return true. If not, |
|
|
|
|
214
|
|
|
// an error has occurred. Therefore we shouldn't save the translations. |
215
|
|
|
if (parent::save($options)) { |
216
|
|
|
return $this->saveTranslations(); |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
return false; |
220
|
|
|
} else { |
221
|
|
|
// If $this->exists and not dirty, parent::save() skips saving and returns |
|
|
|
|
222
|
|
|
// false. So we have to save the translations |
223
|
|
|
if ($saved = $this->saveTranslations()) { |
224
|
|
|
$this->fireModelEvent('saved', false); |
|
|
|
|
225
|
|
|
$this->fireModelEvent('updated', false); |
|
|
|
|
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
return $saved; |
229
|
|
|
} |
230
|
|
|
} elseif (parent::save($options)) { |
231
|
|
|
// We save the translations only if the instance is saved in the database. |
232
|
|
|
return $this->saveTranslations(); |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
return false; |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
/** |
239
|
|
|
* @param string $locale |
240
|
|
|
* |
241
|
|
|
* @return \Illuminate\Database\Eloquent\Model|null |
242
|
|
|
*/ |
243
|
|
|
protected function getTranslationOrNew($locale) |
244
|
|
|
{ |
245
|
|
|
if (($translation = $this->getTranslation($locale, false)) === null) { |
246
|
|
|
$translation = $this->getNewTranslation($locale); |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
return $translation; |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* @param array $attributes |
254
|
|
|
* |
255
|
|
|
* @throws \Illuminate\Database\Eloquent\MassAssignmentException |
256
|
|
|
* |
257
|
|
|
* @return $this |
258
|
|
|
*/ |
259
|
|
|
public function fill(array $attributes) |
260
|
|
|
{ |
261
|
|
|
$totallyGuarded = $this->totallyGuarded(); |
|
|
|
|
262
|
|
|
|
263
|
|
|
foreach ($attributes as $key => $values) { |
264
|
|
|
if ($this->isKeyALocale($key)) { |
265
|
|
|
foreach ($values as $translationAttribute => $translationValue) { |
266
|
|
|
if ($this->alwaysFillable() || $this->isFillable($translationAttribute)) { |
|
|
|
|
267
|
|
|
$this->getTranslationOrNew($key)->$translationAttribute = $translationValue; |
268
|
|
|
} elseif ($totallyGuarded) { |
269
|
|
|
throw new MassAssignmentException($key); |
270
|
|
|
} |
271
|
|
|
} |
272
|
|
|
unset($attributes[$key]); |
273
|
|
|
} |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
return parent::fill($attributes); |
277
|
|
|
} |
278
|
|
|
|
279
|
|
|
/** |
280
|
|
|
* @param string $key |
281
|
|
|
*/ |
282
|
|
|
private function getTranslationByLocaleKey($key) |
283
|
|
|
{ |
284
|
|
|
foreach ($this->translations as $translation) { |
285
|
|
|
if ($translation->getAttribute($this->getLocaleKey()) == $key) { |
286
|
|
|
return $translation; |
287
|
|
|
} |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
return null; |
291
|
|
|
} |
292
|
|
|
|
293
|
|
|
/** |
294
|
|
|
* @param null $locale |
295
|
|
|
* |
296
|
|
|
* @return string |
297
|
|
|
*/ |
298
|
|
|
private function getFallbackLocale($locale = null) |
299
|
|
|
{ |
300
|
|
|
if ($locale && $this->isLocaleCountryBased($locale)) { |
301
|
|
|
if ($fallback = $this->getLanguageFromCountryBasedLocale($locale)) { |
302
|
|
|
return $fallback; |
303
|
|
|
} |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
return app()->make('config')->get('translatable.fallback_locale'); |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
/** |
310
|
|
|
* @param $locale |
311
|
|
|
* |
312
|
|
|
* @return bool |
313
|
|
|
*/ |
314
|
|
|
private function isLocaleCountryBased($locale) |
315
|
|
|
{ |
316
|
|
|
return strpos($locale, $this->getLocaleSeparator()) !== false; |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
/** |
320
|
|
|
* @param $locale |
321
|
|
|
* |
322
|
|
|
* @return string |
323
|
|
|
*/ |
324
|
|
|
private function getLanguageFromCountryBasedLocale($locale) |
325
|
|
|
{ |
326
|
|
|
$parts = explode($this->getLocaleSeparator(), $locale); |
327
|
|
|
|
328
|
|
|
return array_get($parts, 0); |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
/** |
332
|
|
|
* @return bool|null |
333
|
|
|
*/ |
334
|
|
|
private function useFallback() |
335
|
|
|
{ |
336
|
|
|
if (isset($this->useTranslationFallback) && $this->useTranslationFallback !== null) { |
337
|
|
|
return $this->useTranslationFallback; |
|
|
|
|
338
|
|
|
} |
339
|
|
|
|
340
|
|
|
return app()->make('config')->get('translatable.use_fallback'); |
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
/** |
344
|
|
|
* @param string $key |
345
|
|
|
* |
346
|
|
|
* @return bool |
347
|
|
|
*/ |
348
|
|
|
public function isTranslationAttribute($key) |
349
|
|
|
{ |
350
|
|
|
return in_array($key, $this->translatedAttributes); |
|
|
|
|
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
/** |
354
|
|
|
* @param string $key |
355
|
|
|
* |
356
|
|
|
* @throws \Dimsav\Translatable\Exception\LocalesNotDefinedException |
357
|
|
|
* |
358
|
|
|
* @return bool |
359
|
|
|
*/ |
360
|
|
|
protected function isKeyALocale($key) |
361
|
|
|
{ |
362
|
|
|
$locales = $this->getLocales(); |
363
|
|
|
|
364
|
|
|
return in_array($key, $locales); |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
/** |
368
|
|
|
* @throws \Dimsav\Translatable\Exception\LocalesNotDefinedException |
369
|
|
|
* |
370
|
|
|
* @return array |
371
|
|
|
*/ |
372
|
|
|
protected function getLocales() |
373
|
|
|
{ |
374
|
|
|
$localesConfig = (array) app()->make('config')->get('translatable.locales'); |
375
|
|
|
|
376
|
|
|
if (empty($localesConfig)) { |
377
|
|
|
throw new LocalesNotDefinedException('Please make sure you have run "php artisan config:publish dimsav/laravel-translatable" '. |
378
|
|
|
' and that the locales configuration is defined.'); |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
$locales = []; |
382
|
|
|
foreach ($localesConfig as $key => $locale) { |
383
|
|
|
if (is_array($locale)) { |
384
|
|
|
$locales[] = $key; |
385
|
|
|
foreach ($locale as $countryLocale) { |
386
|
|
|
$locales[] = $key.$this->getLocaleSeparator().$countryLocale; |
387
|
|
|
} |
388
|
|
|
} else { |
389
|
|
|
$locales[] = $locale; |
390
|
|
|
} |
391
|
|
|
} |
392
|
|
|
|
393
|
|
|
return $locales; |
394
|
|
|
} |
395
|
|
|
|
396
|
|
|
/** |
397
|
|
|
* @return string |
398
|
|
|
*/ |
399
|
|
|
protected function getLocaleSeparator() |
400
|
|
|
{ |
401
|
|
|
return app()->make('config')->get('translatable.locale_separator', '-'); |
402
|
|
|
} |
403
|
|
|
|
404
|
|
|
/** |
405
|
|
|
* @return bool |
406
|
|
|
*/ |
407
|
|
|
protected function saveTranslations() |
408
|
|
|
{ |
409
|
|
|
$saved = true; |
410
|
|
|
foreach ($this->translations as $translation) { |
411
|
|
|
if ($saved && $this->isTranslationDirty($translation)) { |
412
|
|
|
$translation->setAttribute($this->getRelationKey(), $this->getKey()); |
|
|
|
|
413
|
|
|
$saved = $translation->save(); |
414
|
|
|
} |
415
|
|
|
} |
416
|
|
|
|
417
|
|
|
return $saved; |
418
|
|
|
} |
419
|
|
|
|
420
|
|
|
/** |
421
|
|
|
* @param \Illuminate\Database\Eloquent\Model $translation |
422
|
|
|
* |
423
|
|
|
* @return bool |
424
|
|
|
*/ |
425
|
|
|
protected function isTranslationDirty(Model $translation) |
426
|
|
|
{ |
427
|
|
|
$dirtyAttributes = $translation->getDirty(); |
428
|
|
|
unset($dirtyAttributes[$this->getLocaleKey()]); |
429
|
|
|
|
430
|
|
|
return count($dirtyAttributes) > 0; |
431
|
|
|
} |
432
|
|
|
|
433
|
|
|
/** |
434
|
|
|
* @param string $locale |
435
|
|
|
* |
436
|
|
|
* @return \Illuminate\Database\Eloquent\Model |
437
|
|
|
*/ |
438
|
|
|
public function getNewTranslation($locale) |
439
|
|
|
{ |
440
|
|
|
$modelName = $this->getTranslationModelName(); |
441
|
|
|
$translation = new $modelName(); |
442
|
|
|
$translation->setAttribute($this->getLocaleKey(), $locale); |
443
|
|
|
$this->translations->add($translation); |
444
|
|
|
|
445
|
|
|
return $translation; |
446
|
|
|
} |
447
|
|
|
|
448
|
|
|
/** |
449
|
|
|
* @param $key |
450
|
|
|
* |
451
|
|
|
* @return bool |
452
|
|
|
*/ |
453
|
|
|
public function __isset($key) |
454
|
|
|
{ |
455
|
|
|
return $this->isTranslationAttribute($key) || parent::__isset($key); |
456
|
|
|
} |
457
|
|
|
|
458
|
|
|
/** |
459
|
|
|
* @param \Illuminate\Database\Eloquent\Builder $query |
460
|
|
|
* @param string $locale |
461
|
|
|
* |
462
|
|
|
* @return \Illuminate\Database\Eloquent\Builder|static |
463
|
|
|
*/ |
464
|
|
View Code Duplication |
public function scopeTranslatedIn(Builder $query, $locale = null) |
|
|
|
|
465
|
|
|
{ |
466
|
|
|
$locale = $locale ?: $this->locale(); |
467
|
|
|
|
468
|
|
|
return $query->whereHas('translations', function (Builder $q) use ($locale) { |
469
|
|
|
$q->where($this->getLocaleKey(), '=', $locale); |
470
|
|
|
}); |
471
|
|
|
} |
472
|
|
|
|
473
|
|
|
/** |
474
|
|
|
* @param \Illuminate\Database\Eloquent\Builder $query |
475
|
|
|
* @param string $locale |
476
|
|
|
* |
477
|
|
|
* @return \Illuminate\Database\Eloquent\Builder|static |
478
|
|
|
*/ |
479
|
|
View Code Duplication |
public function scopeNotTranslatedIn(Builder $query, $locale = null) |
|
|
|
|
480
|
|
|
{ |
481
|
|
|
$locale = $locale ?: $this->locale(); |
482
|
|
|
|
483
|
|
|
return $query->whereDoesntHave('translations', function (Builder $q) use ($locale) { |
484
|
|
|
$q->where($this->getLocaleKey(), '=', $locale); |
485
|
|
|
}); |
486
|
|
|
} |
487
|
|
|
|
488
|
|
|
/** |
489
|
|
|
* @param \Illuminate\Database\Eloquent\Builder $query |
490
|
|
|
* |
491
|
|
|
* @return \Illuminate\Database\Eloquent\Builder|static |
492
|
|
|
*/ |
493
|
|
|
public function scopeTranslated(Builder $query) |
494
|
|
|
{ |
495
|
|
|
return $query->has('translations'); |
496
|
|
|
} |
497
|
|
|
|
498
|
|
|
/** |
499
|
|
|
* Adds scope to get a list of translated attributes, using the current locale. |
500
|
|
|
* |
501
|
|
|
* Example usage: Country::listsTranslations('name')->get()->toArray() |
502
|
|
|
* Will return an array with items: |
503
|
|
|
* [ |
504
|
|
|
* 'id' => '1', // The id of country |
505
|
|
|
* 'name' => 'Griechenland' // The translated name |
506
|
|
|
* ] |
507
|
|
|
* |
508
|
|
|
* @param \Illuminate\Database\Eloquent\Builder $query |
509
|
|
|
* @param string $translationField |
510
|
|
|
*/ |
511
|
|
|
public function scopeListsTranslations(Builder $query, $translationField) |
512
|
|
|
{ |
513
|
|
|
$withFallback = $this->useFallback(); |
514
|
|
|
$translationTable = $this->getTranslationsTable(); |
515
|
|
|
$localeKey = $this->getLocaleKey(); |
516
|
|
|
|
517
|
|
|
$query |
518
|
|
|
->select($this->getTable().'.'.$this->getKeyName(), $translationTable.'.'.$translationField) |
|
|
|
|
519
|
|
|
->leftJoin($translationTable, $translationTable.'.'.$this->getRelationKey(), '=', $this->getTable().'.'.$this->getKeyName()) |
|
|
|
|
520
|
|
|
->where($translationTable.'.'.$localeKey, $this->locale()); |
521
|
|
|
if ($withFallback) { |
522
|
|
|
$query->orWhere(function (Builder $q) use ($translationTable, $localeKey) { |
|
|
|
|
523
|
|
|
$q->where($translationTable.'.'.$localeKey, $this->getFallbackLocale()) |
524
|
|
|
->whereNotIn($translationTable.'.'.$this->getRelationKey(), function (QueryBuilder $q) use ($translationTable, $localeKey) { |
525
|
|
|
$q->select($translationTable.'.'.$this->getRelationKey()) |
526
|
|
|
->from($translationTable) |
527
|
|
|
->where($translationTable.'.'.$localeKey, $this->locale()); |
528
|
|
|
}); |
529
|
|
|
}); |
530
|
|
|
} |
531
|
|
|
} |
532
|
|
|
|
533
|
|
|
/** |
534
|
|
|
* This scope eager loads the translations for the default and the fallback locale only. |
535
|
|
|
* We can use this as a shortcut to improve performance in our application. |
536
|
|
|
* |
537
|
|
|
* @param Builder $query |
538
|
|
|
*/ |
539
|
|
|
public function scopeWithTranslation(Builder $query) |
540
|
|
|
{ |
541
|
|
|
$query->with(['translations' => function (Relation $query) { |
542
|
|
|
$query->where($this->getTranslationsTable().'.'.$this->getLocaleKey(), $this->locale()); |
543
|
|
|
|
544
|
|
|
if ($this->useFallback()) { |
545
|
|
|
return $query->orWhere($this->getTranslationsTable().'.'.$this->getLocaleKey(), $this->getFallbackLocale()); |
546
|
|
|
} |
547
|
|
|
}]); |
548
|
|
|
} |
549
|
|
|
|
550
|
|
|
/** |
551
|
|
|
* This scope filters results by checking the translation fields. |
552
|
|
|
* |
553
|
|
|
* @param \Illuminate\Database\Eloquent\Builder $query |
554
|
|
|
* @param string $key |
555
|
|
|
* @param string $value |
556
|
|
|
* @param string $locale |
557
|
|
|
* |
558
|
|
|
* @return \Illuminate\Database\Eloquent\Builder|static |
559
|
|
|
*/ |
560
|
|
View Code Duplication |
public function scopeWhereTranslation(Builder $query, $key, $value, $locale = null) |
|
|
|
|
561
|
|
|
{ |
562
|
|
|
return $query->whereHas('translations', function (Builder $query) use ($key, $value, $locale) { |
563
|
|
|
$query->where($this->getTranslationsTable().'.'.$key, $value); |
564
|
|
|
if ($locale) { |
|
|
|
|
565
|
|
|
$query->where($this->getTranslationsTable().'.'.$this->getLocaleKey(), $locale); |
566
|
|
|
} |
567
|
|
|
}); |
568
|
|
|
} |
569
|
|
|
|
570
|
|
|
/** |
571
|
|
|
* This scope filters results by checking the translation fields. |
572
|
|
|
* |
573
|
|
|
* @param \Illuminate\Database\Eloquent\Builder $query |
574
|
|
|
* @param string $key |
575
|
|
|
* @param string $value |
576
|
|
|
* @param string $locale |
577
|
|
|
* |
578
|
|
|
* @return \Illuminate\Database\Eloquent\Builder|static |
579
|
|
|
*/ |
580
|
|
View Code Duplication |
public function scopeWhereTranslationLike(Builder $query, $key, $value, $locale = null) |
|
|
|
|
581
|
|
|
{ |
582
|
|
|
return $query->whereHas('translations', function (Builder $query) use ($key, $value, $locale) { |
583
|
|
|
$query->where($this->getTranslationsTable().'.'.$key, 'LIKE', $value); |
584
|
|
|
if ($locale) { |
|
|
|
|
585
|
|
|
$query->where($this->getTranslationsTable().'.'.$this->getLocaleKey(), 'LIKE', $locale); |
586
|
|
|
} |
587
|
|
|
}); |
588
|
|
|
} |
589
|
|
|
|
590
|
|
|
/** |
591
|
|
|
* @return array |
592
|
|
|
*/ |
593
|
|
|
public function toArray() |
594
|
|
|
{ |
595
|
|
|
$attributes = parent::toArray(); |
596
|
|
|
|
597
|
|
|
$hiddenAttributes = $this->getHidden(); |
|
|
|
|
598
|
|
|
|
599
|
|
|
foreach ($this->translatedAttributes as $field) { |
|
|
|
|
600
|
|
|
if (in_array($field, $hiddenAttributes)) { |
601
|
|
|
continue; |
602
|
|
|
} |
603
|
|
|
|
604
|
|
|
if ($translations = $this->getTranslation()) { |
|
|
|
|
605
|
|
|
$attributes[$field] = $translations->$field; |
606
|
|
|
} |
607
|
|
|
} |
608
|
|
|
|
609
|
|
|
return $attributes; |
610
|
|
|
} |
611
|
|
|
|
612
|
|
|
/** |
613
|
|
|
* @return bool |
614
|
|
|
*/ |
615
|
|
|
private function alwaysFillable() |
616
|
|
|
{ |
617
|
|
|
return app()->make('config')->get('translatable.always_fillable', false); |
618
|
|
|
} |
619
|
|
|
|
620
|
|
|
/** |
621
|
|
|
* @return string |
622
|
|
|
*/ |
623
|
|
|
private function getTranslationsTable() |
624
|
|
|
{ |
625
|
|
|
return app()->make($this->getTranslationModelName())->getTable(); |
626
|
|
|
} |
627
|
|
|
|
628
|
|
|
/** |
629
|
|
|
* @return string |
630
|
|
|
*/ |
631
|
|
|
protected function locale() |
632
|
|
|
{ |
633
|
|
|
return app()->make('config')->get('translatable.locale') |
634
|
|
|
?: app()->make('translator')->getLocale(); |
635
|
|
|
} |
636
|
|
|
|
637
|
|
|
/** |
638
|
|
|
* Deletes all translations for this model. |
639
|
|
|
* |
640
|
|
|
* @param string|array|null $locales The locales to be deleted (array or single string) |
641
|
|
|
* (e.g., ["en", "de"] would remove these translations). |
642
|
|
|
*/ |
643
|
|
|
public function deleteTranslations($locales = null) |
644
|
|
|
{ |
645
|
|
|
if ($locales === null) { |
646
|
|
|
$this->translations()->delete(); |
647
|
|
|
} else { |
648
|
|
|
$locales = (array) $locales; |
649
|
|
|
$this->translations()->whereIn($this->getLocaleKey(), $locales)->delete(); |
650
|
|
|
} |
651
|
|
|
|
652
|
|
|
// we need to manually "reload" the collection built from the relationship |
653
|
|
|
// otherwise $this->translations()->get() would NOT be the same as $this->translations |
|
|
|
|
654
|
|
|
$this->load('translations'); |
|
|
|
|
655
|
|
|
} |
656
|
|
|
|
657
|
|
|
/** |
658
|
|
|
* Deletes the translations for this model, which are not listed in $locales. |
659
|
|
|
* |
660
|
|
|
* @param mixed $locales The locales to be left untouched (array or single string) |
661
|
|
|
* (e.g., ["en", "de"] would remove all locales but these). |
662
|
|
|
*/ |
663
|
|
|
public function syncTranslations($locales) |
664
|
|
|
{ |
665
|
|
|
if (!is_array($locales)) { |
666
|
|
|
$locales = [$locales]; |
667
|
|
|
} |
668
|
|
|
|
669
|
|
|
$modelTranslation = $this->getTranslationModelName(); |
670
|
|
|
$modelTranslation::where($this->getRelationKey(), '=', $this->id)->whereNotIn($this->getLocaleKey(), $locales)->delete(); |
|
|
|
|
671
|
|
|
|
672
|
|
|
// we need to manually "reload" the collection built from the relationship |
673
|
|
|
// otherwise $this->translations()->get() would NOT be the same as $this->translations |
|
|
|
|
674
|
|
|
$this->load('translations'); |
|
|
|
|
675
|
|
|
} |
676
|
|
|
} |
677
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.