Passed
Push — master ( bc43cb...6e7af2 )
by David
05:10
created

Localizable::removeLocaleRelation()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 3
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\Models\Locale;
12
13
/**
14
 * Trait Localizable
15
 *
16
 * @since 1.0.0
17
 * @package Locale\Traits
18
 *
19
 * @method BelongsToMany belongsToMany($modelClass, $joiningTable = null, $modelForeignKey = null, $localeForeignKey = null)
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());
49
            }
50
51
            if ($locale) {
52
                if (!$this->locales()->updateExistingPivot($locale->id, $localizeAttributes)) {
53
                    $this->locales()->save($locale, $localizeAttributes);
54
                }
55
            } else {
56
                // TODO - Throw exception?
57
            }
58
        }
59
60
        return $result;
61
    }
62
63
    //////////////
64
    // !Attributes
65
66
    /**
67
     * @since 1.0.0
68
     * @return string
69
     */
70
    public function getLocaleIdAttribute()
71
    {
72
        return $this->locale ? $this->locale->id : null;
73
    }
74
75
    /**
76
     * @since 1.0.0
77
     * @param string $key
78
     * @return bool
79
     */
80
    public function isLocalizableAttribute($key)
81
    {
82
        return array_search($key, $this->localize) !== false;
83
    }
84
85
    /**
86
     * Get an attribute from the model.
87
     *
88
     * @since 1.0.0
89
     * @param string $key
90
     * @return mixed
91
     */
92
    public function getAttribute($key)
93
    {
94
        if ($this->isLocalizableAttribute($key)) {
95
            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

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

267
            $model = Str::singular($this->/** @scrutinizer ignore-call */ getTable());
Loading history...
268
        }
269
270
        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...
271
    }
272
273
    /**
274
     * Get the foreign key name for the locale model.
275
     *
276
     * @return string
277
     */
278
    public function getLocaleForeignKey()
279
    {
280
        /** @var Model $instance */
281
        $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

281
        /** @scrutinizer ignore-call */ 
282
        $instance = $this->newRelatedInstance(config("locale.model"));
Loading history...
282
        return Str::singular($instance->getTable()) . "_" . $instance->primaryKey;
283
    }
284
285
    /**
286
     * @since 1.0.0
287
     */
288
    public function removeLocaleRelation()
289
    {
290
        $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

290
        /** @scrutinizer ignore-call */ 
291
        $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...
291
        unset($relations["locale"]);
292
        $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

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