Passed
Push — master ( 214870...d63ff9 )
by Koen
02:32 queued 15s
created

HasTranslations::getRouteKeyName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace KoenHoeijmakers\LaravelTranslatable;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Support\Arr;
7
use KoenHoeijmakers\LaravelTranslatable\Exceptions\MissingTranslationsException;
8
use KoenHoeijmakers\LaravelTranslatable\Scopes\JoinTranslationScope;
9
use KoenHoeijmakers\LaravelTranslatable\Services\TranslationSavingService;
10
11
/**
12
 * Trait HasTranslations
13
 *
14
 * @mixin \Illuminate\Database\Eloquent\Model
15
 */
16
trait HasTranslations
17
{
18
    /**
19
     * The current locale, used to handle internal states.
20
     *
21
     * @var string|null
22
     */
23
    protected $currentLocale = null;
24
25
    /**
26
     * Boot the translatable trait.
27
     *
28
     * @return void
29
     */
30
    public static function bootHasTranslations()
31
    {
32
        if (config('translatable.use_saving_service', true)) {
33
            static::saving(function (self $model) {
34
                app(TranslationSavingService::class)->rememberTranslationForModel($model);
0 ignored issues
show
Bug introduced by
$model of type KoenHoeijmakers\LaravelT...latable\HasTranslations is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $model of KoenHoeijmakers\LaravelT...erTranslationForModel(). ( Ignorable by Annotation )

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

34
                app(TranslationSavingService::class)->rememberTranslationForModel(/** @scrutinizer ignore-type */ $model);
Loading history...
35
            });
36
37
            static::saved(function (self $model) {
38
                app(TranslationSavingService::class)->storeTranslationOnModel($model);
0 ignored issues
show
Bug introduced by
$model of type KoenHoeijmakers\LaravelT...latable\HasTranslations is incompatible with the type Illuminate\Database\Eloquent\Model expected by parameter $model of KoenHoeijmakers\LaravelT...oreTranslationOnModel(). ( Ignorable by Annotation )

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

38
                app(TranslationSavingService::class)->storeTranslationOnModel(/** @scrutinizer ignore-type */ $model);
Loading history...
39
40
                $model->refreshTranslation();
41
            });
42
        }
43
44
        static::addGlobalScope(new JoinTranslationScope());
45
    }
46
47
    /**
48
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
49
     */
50
    public function translations()
51
    {
52
        return $this->hasMany($this->getTranslationModel(), $this->getTranslationForeignKey());
0 ignored issues
show
Bug introduced by
It seems like hasMany() 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

52
        return $this->/** @scrutinizer ignore-call */ hasMany($this->getTranslationModel(), $this->getTranslationForeignKey());
Loading history...
53
    }
54
55
    /**
56
     * Check if the translation by the given locale exists.
57
     *
58
     * @param string $locale
59
     * @return bool
60
     */
61
    public function translationExists(string $locale): bool
62
    {
63
        return $this->translations()->where($this->getLocaleKeyName(), $locale)->exists();
64
    }
65
66
    /**
67
     * Get the translation model.
68
     *
69
     * @return string
70
     */
71
    public function getTranslationModel(): string
72
    {
73
        if (isset($this->translationModel)) {
74
            return $this->translationModel;
75
        }
76
77
        return get_class($this) . $this->getTranslationModelSuffix();
78
    }
79
80
    /**
81
     * Get the translation model suffix.
82
     *
83
     * @return string
84
     */
85
    protected function getTranslationModelSuffix(): string
86
    {
87
        return 'Translation';
88
    }
89
90
    /**
91
     * Get the translation table.
92
     *
93
     * @return string
94
     */
95
    public function getTranslationTable(): string
96
    {
97
        $model = $this->getTranslationModel();
98
99
        return (new $model())->getTable();
100
    }
101
102
    /**
103
     * Get the translation foreign key.
104
     *
105
     * @return string
106
     */
107
    public function getTranslationForeignKey()
108
    {
109
        if (isset($this->translationForeignKey)) {
110
            return $this->translationForeignKey;
111
        }
112
113
        return $this->getForeignKey();
0 ignored issues
show
Bug introduced by
It seems like getForeignKey() 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

113
        return $this->/** @scrutinizer ignore-call */ getForeignKey();
Loading history...
114
    }
115
116
    /**
117
     * Get the translatable.
118
     *
119
     * @return array
120
     * @throws \KoenHoeijmakers\LaravelTranslatable\Exceptions\MissingTranslationsException
121
     */
122
    public function getTranslatable(): array
123
    {
124
        if (!isset($this->translatable)) {
125
            throw new MissingTranslationsException('Model "' . static::class . '" is missing translations');
126
        }
127
128
        return $this->translatable;
129
    }
130
131
    /**
132
     * Get the translatable attributes.
133
     *
134
     * @return array
135
     */
136
    public function getTranslatableAttributes(): array
137
    {
138
        return Arr::only($this->getAttributes(), $this->translatable);
0 ignored issues
show
Bug introduced by
It seems like getAttributes() 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

138
        return Arr::only($this->/** @scrutinizer ignore-call */ getAttributes(), $this->translatable);
Loading history...
139
    }
140
141
    /**
142
     * @param string $locale
143
     * @param array<string, mixed> $attributes
144
     * @return \Illuminate\Database\Eloquent\Model
145
     */
146
    public function storeTranslation(string $locale, array $attributes = [])
147
    {
148
        if (!is_null($model = $this->translations()->where($this->getLocaleKeyName(), $locale)->first())) {
149
            $model->update($attributes);
150
151
            return $model;
152
        }
153
154
        $model = $this->translations()->make($attributes);
155
        $model->setAttribute($this->getLocaleKeyName(), $locale);
156
        $model->save();
157
158
        return $model;
159
    }
160
161
    /**
162
     * Store many translations at once.
163
     *
164
     * @param array<string, array> $translations
165
     * @return $this
166
     */
167
    public function storeTranslations(array $translations)
168
    {
169
        foreach ($translations as $locale => $translation) {
170
            $this->storeTranslation($locale, $translation);
171
        }
172
173
        return $this;
174
    }
175
176
    /**
177
     * @param string $locale
178
     * @return \Illuminate\Database\Eloquent\Model|self
179
     */
180
    public function getTranslation(string $locale)
181
    {
182
        return $this->translations()->where($this->getLocaleKeyName(), $locale)->first();
183
    }
184
185
    /**
186
     * The locale key name.
187
     *
188
     * @return string
189
     */
190
    public function getLocaleKeyName(): string
191
    {
192
        return $this->localeKeyName ?? config('translatable.locale_key_name', 'locale');
193
    }
194
195
    /**
196
     * Get the locale.
197
     *
198
     * @return string
199
     */
200
    public function getLocale(): string
201
    {
202
        return $this->currentLocale ?? app()->getLocale();
0 ignored issues
show
introduced by
The method getLocale() does not exist on Illuminate\Container\Container. Are you sure you never get this type here, but always one of the subclasses? ( Ignorable by Annotation )

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

202
        return $this->currentLocale ?? app()->/** @scrutinizer ignore-call */ getLocale();
Loading history...
203
    }
204
205
    /**
206
     * Refresh the translation (in the current locale).
207
     *
208
     * @return \Illuminate\Database\Eloquent\Model|null
209
     */
210
    public function refreshTranslation()
211
    {
212
        if (!$this->exists) {
213
            return null;
214
        }
215
216
        $attributes = Arr::only(
217
            static::findOrFail($this->getKey())->attributes, $this->getTranslatable()
0 ignored issues
show
Bug introduced by
It seems like getKey() 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

217
            static::findOrFail($this->/** @scrutinizer ignore-call */ getKey())->attributes, $this->getTranslatable()
Loading history...
218
        );
219
220
        foreach ($attributes as $key => $value) {
221
            $this->setAttribute($key, $value);
0 ignored issues
show
Bug introduced by
It seems like setAttribute() 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

221
            $this->/** @scrutinizer ignore-call */ 
222
                   setAttribute($key, $value);
Loading history...
222
        }
223
224
        $this->syncOriginal();
0 ignored issues
show
Bug introduced by
It seems like syncOriginal() 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

224
        $this->/** @scrutinizer ignore-call */ 
225
               syncOriginal();
Loading history...
225
226
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type KoenHoeijmakers\LaravelT...latable\HasTranslations which is incompatible with the documented return type null|Illuminate\Database\Eloquent\Model.
Loading history...
227
    }
228
229
    /**
230
     * Translate the model to the given locale.
231
     *
232
     * @param string $locale
233
     * @return \Illuminate\Database\Eloquent\Model|null
234
     */
235
    public function translate(string $locale)
236
    {
237
        if (!$this->exists) {
238
            return null;
239
        }
240
241
        $this->currentLocale = $locale;
242
243
        return $this->refreshTranslation();
244
    }
245
246
    /**
247
     * Get a new query builder that doesn't have any global scopes (except the JoinTranslationScope).
248
     *
249
     * @return \Illuminate\Database\Eloquent\Builder
250
     */
251
    public function newQueryWithoutScopes(): Builder
252
    {
253
        return parent::newQueryWithoutScopes()
254
            ->withGlobalScope(JoinTranslationScope::class, new JoinTranslationScope());
255
    }
256
257
    /**
258
     * Get the route key for the model.
259
     *
260
     * @return string
261
     */
262
    public function getRouteKeyName()
263
    {
264
        return $this->getTable() . '.' . $this->getKeyName();
0 ignored issues
show
Bug introduced by
It seems like getTable() 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

264
        return $this->/** @scrutinizer ignore-call */ getTable() . '.' . $this->getKeyName();
Loading history...
Bug introduced by
It seems like getKeyName() 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

264
        return $this->getTable() . '.' . $this->/** @scrutinizer ignore-call */ getKeyName();
Loading history...
265
    }
266
}
267