Passed
Push — master ( 8dca39...7717c8 )
by David
02:04
created

Localizable::getLocaleIdAttribute()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 2
eloc 1
nc 2
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\Models\Locale;
12
13
/**
14
 * Trait Localizable
15
 *
16
 * @since 1.0.0
17
 * @package Locale\Traits
18
 *
19
 * @method BelongsToMany belongsToMany($modelClass, $joiningTable, $modelForeignKey, $localeForeignKey)
20
 *
21
 * @property array localize
22
 * @property Locale locale
23
 * @property Collection locales
24
 */
25
trait Localizable
26
{
27
    /**
28
     * Save the model to the database.
29
     *
30
     * @param  array  $options
31
     * @return bool
32
     */
33
    public function save(array $options = [])
34
    {
35
        $localeForeignKey = "locale_id";
36
        $keys = array_merge($this->localize, [$localeForeignKey]);
37
        $localizeAttributes = array_only($this->attributes, $keys);
38
        $this->attributes = array_except($this->attributes, $keys);
0 ignored issues
show
Bug Best Practice introduced by
The property attributes does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
39
40
        /** @noinspection PhpUndefinedMethodInspection */
41
        $result = parent::save($options);
42
43
        if ($result && !empty($localizeAttributes)) {
44
            if (isset($localizeAttributes[$localeForeignKey])) {
45
                $locale = Locale::find($localizeAttributes[$localeForeignKey]);
46
                unset($localizeAttributes[$localeForeignKey]);
47
            } else {
48
                $locale = Locale::find(app()->getLocale());
1 ignored issue
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

48
                $locale = Locale::find(app()->/** @scrutinizer ignore-call */ getLocale());
Loading history...
49
            }
50
51
            if ($locale) {
52
                $this->locales()->save($locale, $localizeAttributes);
53
            } else {
54
                // TODO - Throw exception?
55
            }
56
        }
57
58
        return $result;
59
    }
60
61
    //////////////
62
    // !Attributes
63
64
    /**
65
     * @since 1.0.0
66
     * @return string
67
     */
68
    public function getLocaleIdAttribute()
69
    {
70
        return $this->locale ? $this->locale->id : null;
71
    }
72
73
    /**
74
     * @since 1.0.0
75
     * @param string $key
76
     * @return bool
77
     */
78
    public function isLocalizableAttribute($key)
79
    {
80
        return array_search($key, $this->localize) !== false;
81
    }
82
83
    /**
84
     * Get an attribute from the model.
85
     *
86
     * @since 1.0.0
87
     * @param string $key
88
     * @return mixed
89
     */
90
    public function getAttribute($key)
91
    {
92
        if ($this->isLocalizableAttribute($key)) {
93
            return $this->getAttributeValue($key);
0 ignored issues
show
Bug introduced by
The method getAttributeValue() does not exist on Locale\Traits\Localizable. Did you maybe mean getAttribute()? ( Ignorable by Annotation )

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

93
            return $this->/** @scrutinizer ignore-call */ getAttributeValue($key);

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...
94
        }
95
96
        /** @noinspection PhpUndefinedMethodInspection */
97
        return parent::getAttribute($key);
98
    }
99
100
    /**
101
     * Get an attribute from the $attributes array.
102
     *
103
     * @param string $key
104
     * @return mixed
105
     */
106
    protected function getAttributeFromArray($key)
107
    {
108
        /** @noinspection PhpUndefinedMethodInspection */
109
        $attribute = parent::getAttributeFromArray($key);
110
111
        if (!$attribute && $this->isLocalizableAttribute($key) && $this->locale) {
112
            return $this->locale->translation->getAttribute($key);
113
        }
114
115
        return $attribute;
116
    }
117
118
    /**
119
     * Determine if the model uses locale timestamps.
120
     *
121
     * @return bool
122
     */
123
    public function usesLocaleTimestamps()
124
    {
125
        return $this->locale_timestamps ?? false;
0 ignored issues
show
Bug introduced by
The property locale_timestamps does not exist on Locale\Traits\Localizable. Did you mean locale?
Loading history...
126
    }
127
128
    /**
129
     * Determine if the model uses fallback locale.
130
     *
131
     * @return bool
132
     */
133
    public function usesFallbackLocale()
134
    {
135
        return $this->fallback_locale ?? false;
0 ignored issues
show
Bug introduced by
The property fallback_locale does not exist on Locale\Traits\Localizable. Did you mean locale?
Loading history...
136
    }
137
138
    /////////////////
139
    // !Relationships
140
141
    /**
142
     * @since 1.0.0
143
     */
144
    public function locale()
145
    {
146
        $locales = $this->locales();
147
        $canBe = [app()->getLocale()];
148
149
        if ($this->usesFallbackLocale()) {
150
            $canBe[] = config("app.fallback_locale");
151
        }
152
153
        /** @noinspection PhpUndefinedMethodInspection */
154
        return $locales->whereIn("id", $canBe);
155
    }
156
157
    /**
158
     * @since 1.0.0
159
     * @return BelongsToMany
160
     */
161
    public function locales()
162
    {
163
        $localeTable = config("locale.model");
164
        $modelTable = isset($this->table) ? $this->table : null;
0 ignored issues
show
Bug Best Practice introduced by
The property table does not exist on Locale\Traits\Localizable. Did you maybe forget to declare it?
Loading history...
165
        $joiningTable = $this->joiningLocaleTable($localeTable, $modelTable);
166
        $modelForeignKey = $this->getModelForeignKey();
167
        $localeForeignKey = $this->getLocaleForeignKey();
168
169
        $locales = $this->belongsToMany($localeTable, $joiningTable, $modelForeignKey, $localeForeignKey)
170
                        ->withPivot($this->localize)
171
                        ->as("translation");
172
173
        if ($this->usesLocaleTimestamps()) {
174
            /** @noinspection PhpUndefinedMethodInspection */
175
            $locales = $locales->withTimestamps();
176
        }
177
178
        return $locales;
179
    }
180
181
    /**
182
     * Get a relationship value from a method.
183
     *
184
     * @param  string  $method
185
     * @return mixed
186
     *
187
     * @throws \LogicException
188
     */
189
    protected function getRelationshipFromMethod($method)
190
    {
191
        /** @noinspection PhpUndefinedMethodInspection */
192
        $results = parent::getRelationshipFromMethod($method);
193
194
        if ($method == "locale") {
195
            /** @noinspection PhpUndefinedMethodInspection */
196
            return $results->first();
197
        }
198
199
        return $results;
200
    }
201
202
    /**
203
     * Set the specific relationship in the model.
204
     *
205
     * @param  string  $relation
206
     * @param  mixed  $value
207
     * @return $this
208
     */
209
    public function setRelation($relation, $value)
210
    {
211
        if ($relation == "locale") {
212
            /** @var Collection $value */
213
            if ($value->count() > 1) {
214
                $value = $value->where("id", app()->getLocale());
215
            }
216
217
            $value = $value->first();
218
219
            /** @var Locale $value */
220
            if (!$value) {
221
                return $this;
222
            } else {
223
                Event::listen(LocaleUpdated::class, function ($event) use ($value) {
224
                    /** @var LocaleUpdated $event */
225
                    if ($this->needsRefreshLocaleRelation($value, $event->locale)) {
226
                        $this->removeLocaleRelation();
227
                    }
228
                });
229
            }
230
        }
231
232
        /** @noinspection PhpUndefinedMethodInspection */
233
        return parent::setRelation($relation, $value);
234
    }
235
236
    /**
237
     * Get the joining locale table name.
238
     *
239
     * @param string $locale
240
     * @param string $modelTable
241
     * @return string
242
     */
243
    public function joiningLocaleTable($locale, $modelTable = null)
244
    {
245
        $models = [
246
            Str::snake(class_basename($locale)),
247
            $modelTable ? Str::singular($modelTable) : Str::snake(class_basename($this)),
248
        ];
249
250
        sort($models);
251
252
        return strtolower(implode('_', $models));
253
    }
254
255
    /**
256
     * Get the foreign key name for the model.
257
     *
258
     * @return string
259
     */
260
    public function getModelForeignKey()
261
    {
262
        if (!isset($this->table)) {
263
            $model = Str::snake(class_basename($this));
264
        } else {
265
            $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

265
            $model = Str::singular($this->/** @scrutinizer ignore-call */ getTable());
Loading history...
266
        }
267
268
        return "{$model}_{$this->primaryKey}";
0 ignored issues
show
Bug Best Practice introduced by
The property primaryKey does not exist on Locale\Traits\Localizable. Did you maybe forget to declare it?
Loading history...
269
    }
270
271
    /**
272
     * Get the foreign key name for the locale model.
273
     *
274
     * @return string
275
     */
276
    public function getLocaleForeignKey()
277
    {
278
        /** @var Model $instance */
279
        $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

279
        /** @scrutinizer ignore-call */ 
280
        $instance = $this->newRelatedInstance(config("locale.model"));
Loading history...
280
        return Str::singular($instance->getTable()) . "_" . $instance->primaryKey;
281
    }
282
283
    /**
284
     * @since 1.0.0
285
     */
286
    public function removeLocaleRelation()
287
    {
288
        $relations = $this->getRelations();
0 ignored issues
show
Bug introduced by
The method getRelations() does not exist on Locale\Traits\Localizable. Did you maybe mean getRelationshipFromMethod()? ( Ignorable by Annotation )

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

288
        /** @scrutinizer ignore-call */ 
289
        $relations = $this->getRelations();

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...
289
        unset($relations["locale"]);
290
        $this->setRelations($relations);
0 ignored issues
show
Bug introduced by
The method setRelations() does not exist on Locale\Traits\Localizable. Did you maybe mean setRelation()? ( Ignorable by Annotation )

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

290
        $this->/** @scrutinizer ignore-call */ 
291
               setRelations($relations);

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...
291
    }
292
293
    /**
294
     * @since 1.0.0
295
     * @param Locale $currentLocale
296
     * @param string $newLocaleId
297
     * @return bool
298
     */
299
    public function needsRefreshLocaleRelation($currentLocale, $newLocaleId)
300
    {
301
        return $currentLocale->id !== $newLocaleId;
302
    }
303
}
304