Localizable::getLocaleForeignKey()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Locale\Traits;
4
5
use Illuminate\Database\Eloquent\Collection;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
8
use Illuminate\Foundation\Events\LocaleUpdated;
9
use Illuminate\Support\Facades\Event;
10
use Illuminate\Support\Str;
11
use Locale\Database\LocalizableBuilder;
12
use Locale\Models\Locale;
13
14
/**
15
 * Trait Localizable
16
 *
17
 * @since 1.0.0
18
 * @package Locale\Traits
19
 *
20
 * @method BelongsToMany belongsToMany($modelClass, $joiningTable = null, $modelForeignKey = null, $localeForeignKey = null)
21
 *
22
 * @property array localize
23
 * @property Locale locale
24
 * @property Collection locales
25
 */
26
trait Localizable
27
{
28
    /**
29
     * Create a new Eloquent query builder for the model.
30
     *
31
     * @param  \Illuminate\Database\Query\Builder  $query
32
     * @return \Illuminate\Database\Eloquent\Builder
33
     */
34
    public function newEloquentBuilder($query)
35
    {
36
        return new LocalizableBuilder($query);
37
    }
38
39
    /**
40
     * Get all of the current localizable attributes on the model.
41
     *
42
     * @return array
43
     */
44
    public function getLocalizableAttributes()
45
    {
46
        return array_only($this->locale->translation->getAttributes(), $this->localize);
47
    }
48
49
    /**
50
     * Save the model to the database.
51
     *
52
     * @param  array  $options
53
     * @return bool
54
     */
55
    public function save(array $options = [])
56
    {
57
        /** @var Model $this */
58
        $localeForeignKey = "locale_id";
59
        $keys = array_merge($this->localize, [$localeForeignKey]);
60
        $localizeAttributes = array_only($this->attributes, $keys);
61
        $this->attributes = array_except($this->attributes, $keys);
62
63
        /** @noinspection PhpUndefinedMethodInspection */
64
        /** @noinspection PhpUndefinedClassInspection */
65
        $result = parent::save($options);
66
67
        if ($result && !empty($localizeAttributes)) {
68
            if (isset($localizeAttributes[$localeForeignKey])) {
69
                $locale = Locale::find($localizeAttributes[$localeForeignKey]);
70
                unset($localizeAttributes[$localeForeignKey]);
71
            } else {
72
                $locale = Locale::find(app()->getLocale());
73
            }
74
75
            if ($locale) {
0 ignored issues
show
introduced by
$locale is of type Locale\Models\Locale, thus it always evaluated to true.
Loading history...
76
                if (!$this->locales()->updateExistingPivot($locale->id, $localizeAttributes)) {
77
                    $this->locales()->save($locale, $localizeAttributes);
78
                }
79
            } else {
80
                // TODO - Throw exception?
81
            }
82
        }
83
84
        return $result;
85
    }
86
87
    //////////////
88
    // !Attributes
89
90
    /**
91
     * @since 1.0.0
92
     * @return string
93
     */
94
    public function getLocaleIdAttribute()
95
    {
96
        return $this->locale ? $this->locale->id : null;
97
    }
98
99
    /**
100
     * @since 1.0.0
101
     * @param string $key
102
     * @return bool
103
     */
104
    public function isLocalizableAttribute($key)
105
    {
106
        return array_search($key, $this->localize) !== false;
107
    }
108
109
    /**
110
     * Get an attribute from the model.
111
     *
112
     * @since 1.0.0
113
     * @param string $key
114
     * @return mixed
115
     */
116
    public function getAttribute($key)
117
    {
118
        /** @var Model $this */
119
120
        if ($this->isLocalizableAttribute($key)) {
121
            return $this->getAttributeValue($key);
122
        }
123
124
        /** @noinspection PhpUndefinedMethodInspection */
125
        /** @noinspection PhpUndefinedClassInspection */
126
        return parent::getAttribute($key);
127
    }
128
129
    /**
130
     * Get an attribute from the $attributes array.
131
     *
132
     * @param string $key
133
     * @return mixed
134
     */
135
    protected function getAttributeFromArray($key)
136
    {
137
        /** @noinspection PhpUndefinedMethodInspection */
138
        /** @noinspection PhpUndefinedClassInspection */
139
        $attribute = parent::getAttributeFromArray($key);
140
141
        if (!$attribute && $this->isLocalizableAttribute($key) && $this->locale) {
142
            return $this->locale->translation->getAttribute($key);
143
        }
144
145
        return $attribute;
146
    }
147
148
    /**
149
     * Determine if the model uses locale timestamps.
150
     *
151
     * @return bool
152
     */
153
    public function usesLocaleTimestamps()
154
    {
155
        return isset($this->localeTimestamps) ? $this->localeTimestamps : true;
0 ignored issues
show
Bug introduced by
The property localeTimestamps does not exist on Locale\Traits\Localizable. Did you mean locale?
Loading history...
156
    }
157
158
    /**
159
     * Determine if the model uses fallback locale.
160
     *
161
     * @return bool
162
     */
163
    public function usesFallbackLocale()
164
    {
165
        return isset($this->fallbackLocale) ? $this->fallbackLocale : true;
166
    }
167
168
    /////////////////
169
    // !Relationships
170
171
    /**
172
     * @since 1.0.0
173
     */
174
    public function locale()
175
    {
176
        $locales = $this->locales();
177
        $canBe = [app()->getLocale()];
178
179
        if ($this->usesFallbackLocale()) {
180
            $canBe[] = config("app.fallback_locale");
181
        }
182
183
        $locale = $locales->whereIn("id", $canBe);
184
185
        if ($this->usesFallbackLocale() && $locale->count() === 0) {
186
            $locale = $this->locales()->take(1);
187
        }
188
189
        return $locale;
190
    }
191
192
    /**
193
     * @since 1.0.0
194
     * @return BelongsToMany
195
     */
196
    public function locales()
197
    {
198
        $localeTable = config("locale.model");
199
        $modelTable = isset($this->table) ? $this->table : null;
200
        $joiningTable = $this->joiningLocaleTable($localeTable, $modelTable);
201
        $modelForeignKey = $this->getModelForeignKey();
202
        $localeForeignKey = $this->getLocaleForeignKey();
203
204
        $locales = $this->belongsToMany($localeTable, $joiningTable, $modelForeignKey, $localeForeignKey)
205
                        ->withPivot($this->localize)
206
                        ->as("translation");
207
208
        if ($this->usesLocaleTimestamps()) {
209
            /** @noinspection PhpUndefinedMethodInspection */
210
            $locales = $locales->withTimestamps();
211
        }
212
213
        return $locales;
214
    }
215
216
    /**
217
     * Get a relationship value from a method.
218
     *
219
     * @param  string  $method
220
     * @return mixed
221
     *
222
     * @throws \LogicException
223
     */
224
    protected function getRelationshipFromMethod($method)
225
    {
226
        /** @noinspection PhpUndefinedMethodInspection */
227
        $results = parent::getRelationshipFromMethod($method);
228
229
        if ($method == "locale") {
230
            /** @noinspection PhpUndefinedMethodInspection */
231
            return $results->first();
232
        }
233
234
        return $results;
235
    }
236
237
    /**
238
     * Set the specific relationship in the model.
239
     *
240
     * @param  string  $relation
241
     * @param  mixed  $value
242
     * @return $this
243
     */
244
    public function setRelation($relation, $value)
245
    {
246
        if ($relation == "locale") {
247
            /** @var Collection $value */
248
            if ($value->count() > 1) {
249
                $value = $value->where("id", app()->getLocale());
250
            }
251
252
            $value = $value->first();
253
254
            /** @var Locale $value */
255
            if (!$value) {
0 ignored issues
show
introduced by
$value is of type Locale\Models\Locale, thus it always evaluated to true. If $value can have other possible types, add them to src/Traits/Localizable.php:254
Loading history...
256
                return $this;
257
            } else {
258
                Event::listen(LocaleUpdated::class, function ($event) use ($value) {
259
                    /** @var LocaleUpdated $event */
260
                    if ($this->needsRefreshLocaleRelation($value, $event->locale)) {
261
                        $this->removeLocaleRelation();
262
                    }
263
                });
264
            }
265
        }
266
267
        /** @noinspection PhpUndefinedMethodInspection */
268
        return parent::setRelation($relation, $value);
269
    }
270
271
    /**
272
     * Get the joining locale table name.
273
     *
274
     * @param string $locale
275
     * @param string $modelTable
276
     * @return string
277
     */
278
    public function joiningLocaleTable($locale, $modelTable = null)
279
    {
280
        $models = [
281
            Str::snake(class_basename($locale)),
282
            $modelTable ? Str::singular($modelTable) : Str::snake(class_basename($this)),
283
        ];
284
285
        sort($models);
286
287
        return strtolower(implode('_', $models));
288
    }
289
290
    /**
291
     * Get the foreign key name for the model.
292
     *
293
     * @return string
294
     */
295
    public function getModelForeignKey()
296
    {
297
        if (!isset($this->table)) {
298
            $model = Str::snake(class_basename($this));
299
        } else {
300
            $model = Str::singular($this->getTable());
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

300
            $model = Str::singular($this->/** @scrutinizer ignore-call */ getTable());
Loading history...
301
        }
302
303
        return "{$model}_{$this->primaryKey}";
304
    }
305
306
    /**
307
     * Get the foreign key name for the locale model.
308
     *
309
     * @return string
310
     */
311
    public function getLocaleForeignKey()
312
    {
313
        /** @var Model $instance */
314
        $instance = $this->newRelatedInstance(config("locale.model"));
0 ignored issues
show
Bug introduced by
It seems like newRelatedInstance() 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

314
        /** @scrutinizer ignore-call */ 
315
        $instance = $this->newRelatedInstance(config("locale.model"));
Loading history...
315
        return Str::singular($instance->getTable()) . "_" . $instance->primaryKey;
316
    }
317
318
    /**
319
     * @since 1.0.0
320
     */
321
    public function removeLocaleRelation()
322
    {
323
        /** @var Model $this */
324
        $relations = $this->getRelations();
325
        unset($relations["locale"]);
326
        $this->setRelations($relations);
327
    }
328
329
    /**
330
     * @since 1.0.0
331
     * @param Locale $currentLocale
332
     * @param string $newLocaleId
333
     * @return bool
334
     */
335
    public function needsRefreshLocaleRelation($currentLocale, $newLocaleId)
336
    {
337
        return $currentLocale->id !== $newLocaleId;
338
    }
339
}
340