Test Setup Failed
Pull Request — master (#559)
by
unknown
02:01
created

Translatable::scopeWhereTranslationLike()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 9

Duplication

Lines 9
Ratio 100 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 9
loc 9
ccs 5
cts 5
cp 1
rs 9.9666
c 0
b 0
f 0
cc 2
nc 1
nop 4
crap 2
1
<?php
2
3
namespace Dimsav\Translatable;
4
5
use Illuminate\Database\Eloquent\Model;
6
use Illuminate\Database\Eloquent\Builder;
7
use Illuminate\Database\Query\JoinClause;
8
use Illuminate\Database\Eloquent\Relations\Relation;
9
use Illuminate\Database\Query\Builder as QueryBuilder;
10
use Dimsav\Translatable\Exception\LocalesNotDefinedException;
11
use Illuminate\Database\Eloquent\Relations\HasOne;
12
13
trait Translatable
14
{
15
    protected static $autoloadTranslations = null;
16
17
    protected $defaultLocale;
18
19
    /**
20
     * Alias for getTranslation().
21
     *
22
     * @param string|null $locale
23
     * @param bool        $withFallback
24
     *
25
     * @return \Illuminate\Database\Eloquent\Model|null
26
     */
27 52
    public function translate($locale = null, $withFallback = false)
28
    {
29 52
        return $this->getTranslation($locale, $withFallback);
30
    }
31
32
    /**
33
     * Alias for getTranslation().
34
     *
35
     * @param string $locale
36
     *
37
     * @return \Illuminate\Database\Eloquent\Model|null
38
     */
39 4
    public function translateOrDefault($locale = null)
40
    {
41 4
        return $this->getTranslation($locale, true);
42
    }
43
44
    /**
45
     * Alias for getTranslationOrNew().
46
     *
47
     * @param string $locale
48
     *
49
     * @return \Illuminate\Database\Eloquent\Model|null
50
     */
51 4
    public function translateOrNew($locale = null)
52
    {
53 4
        return $this->getTranslationOrNew($locale);
54
    }
55
56
    /**
57
     * @param string|null $locale
58
     * @param bool        $withFallback
59
     *
60
     * @return \Illuminate\Database\Eloquent\Model|null
61
     */
62 248
    public function getTranslation($locale = null, $withFallback = null)
63
    {
64 248
        $configFallbackLocale = $this->getFallbackLocale();
65 248
        $locale = $locale ?: $this->locale();
66 248
        $withFallback = $withFallback === null ? $this->useFallback() : $withFallback;
67 248
        $fallbackLocale = $this->getFallbackLocale($locale);
68
69 248
        if ($translation = $this->getTranslationByLocaleKey($locale)) {
70 140
            return $translation;
71
        }
72 168
        if ($withFallback && $fallbackLocale) {
73 28
            if ($translation = $this->getTranslationByLocaleKey($fallbackLocale)) {
74 16
                return $translation;
75
            }
76 12
            if ($fallbackLocale !== $configFallbackLocale && $translation = $this->getTranslationByLocaleKey($configFallbackLocale)) {
77 8
                return $translation;
78
            }
79
        }
80
81 164
        return null;
82
    }
83
84
    /**
85
     * @param string|null $locale
86
     *
87
     * @return bool
88
     */
89 12
    public function hasTranslation($locale = null)
90
    {
91 12
        $locale = $locale ?: $this->locale();
92
93 12
        foreach ($this->translations as $translation) {
0 ignored issues
show
Bug introduced by
The property translations does not seem to exist. Did you mean autoloadTranslations?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
94 4
            if ($translation->getAttribute($this->getLocaleKey()) == $locale) {
95 4
                return true;
96
            }
97
        }
98
99 12
        return false;
100
    }
101
102
    /**
103
     * @return string
104
     */
105 312
    public function getTranslationModelName()
106
    {
107 312
        return $this->translationModel ?: $this->getTranslationModelNameDefault();
0 ignored issues
show
Bug introduced by
The property translationModel does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
108
    }
109
110
    /**
111
     * @return string
112
     */
113 304
    public function getTranslationModelNameDefault()
114
    {
115 304
        $modelName = get_class($this);
116
117 304
        if ($namespace = $this->getTranslationModelNamespace()) {
118 4
            $modelName = $namespace.'\\'.class_basename(get_class($this));
119
        }
120
121 304
        return $modelName.config('translatable.translation_suffix', 'Translation');
122
    }
123
124
    /**
125
     * @return string|null
126
     */
127 304
    public function getTranslationModelNamespace()
128
    {
129 304
        return config('translatable.translation_model_namespace');
130
    }
131
132
    /**
133
     * @return string
134
     */
135 312
    public function getRelationKey()
136
    {
137 312
        if ($this->translationForeignKey) {
138 24
            $key = $this->translationForeignKey;
0 ignored issues
show
Bug introduced by
The property translationForeignKey does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
139 292
        } elseif ($this->primaryKey !== 'id') {
0 ignored issues
show
Bug introduced by
The property primaryKey does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
140
            $key = $this->primaryKey;
141
        } else {
142 292
            $key = $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?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
143
        }
144
145 312
        return $key;
146
    }
147
148
    /**
149
     * @return string
150
     */
151 292
    public function getLocaleKey()
152
    {
153 292
        return $this->localeKey ?: config('translatable.locale_key', 'locale');
0 ignored issues
show
Bug introduced by
The property localeKey does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
154
    }
155
156
    /**
157
     * @return HasOne
158
     */
159
    public function translation($locale = null)
160
    {
161
        if (!$locale) {
162
            $locale = $this->locale();
163
        }
164
165
        return $this->hasOne($this->getTranslationModelName(), $this->getRelationKey())
0 ignored issues
show
Bug introduced by
It seems like hasOne() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
166
            ->where($this->getLocaleKey(), $locale);
167
    }
168
    
169
    /**
170
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
171
     */
172 292
    public function translations()
173
    {
174 292
        return $this->hasMany($this->getTranslationModelName(), $this->getRelationKey());
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?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
175
    }
176
177
    /**
178
     * @return bool
179
     */
180 12
    private function usePropertyFallback()
181
    {
182 12
        return $this->useFallback() && config('translatable.use_property_fallback', false);
183
    }
184
185
    /**
186
     * Returns the attribute value from fallback translation if value of attribute
187
     * is empty and the property fallback is enabled in the configuration.
188
     * in model.
189
     * @param $locale
190
     * @param $attribute
191
     * @return mixed
192
     */
193 92
    private function getAttributeOrFallback($locale, $attribute)
194
    {
195 92
        $translation = $this->getTranslation($locale);
196
197
        if (
198
            (
199 92
                ! $translation instanceof Model ||
200 92
                empty($translation->$attribute)
201
            ) &&
202 92
            $this->usePropertyFallback()
203
        ) {
204 8
            $translation = $this->getTranslation($this->getFallbackLocale(), false);
205
        }
206
207 92
        if ($translation instanceof Model) {
208 88
            return $translation->$attribute;
209
        }
210
211 8
        return null;
212
    }
213
214
    /**
215
     * @param string $key
216
     *
217
     * @return mixed
218
     */
219 388
    public function getAttribute($key)
220
    {
221 388
        list($attribute, $locale) = $this->getAttributeAndLocale($key);
222
223 388
        if ($this->isTranslationAttribute($attribute)) {
224 72
            if ($this->getTranslation($locale) === null) {
225 12
                return $this->getAttributeValue($attribute);
0 ignored issues
show
Bug introduced by
The method getAttributeValue() does not exist on Dimsav\Translatable\Translatable. Did you maybe mean getAttribute()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
226
            }
227
228
            // If the given $attribute has a mutator, we push it to $attributes and then call getAttributeValue
229
            // on it. This way, we can use Eloquent's checking for Mutation, type casting, and
230
            // Date fields.
231 60
            if ($this->hasGetMutator($attribute)) {
0 ignored issues
show
Bug introduced by
It seems like hasGetMutator() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
232 4
                $this->attributes[$attribute] = $this->getAttributeOrFallback($locale, $attribute);
0 ignored issues
show
Bug introduced by
The property attributes does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
233
234 4
                return $this->getAttributeValue($attribute);
0 ignored issues
show
Bug introduced by
The method getAttributeValue() does not exist on Dimsav\Translatable\Translatable. Did you maybe mean getAttribute()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
235
            }
236
237 56
            return $this->getAttributeOrFallback($locale, $attribute);
238
        }
239
240 388
        return parent::getAttribute($key);
241
    }
242
243
    /**
244
     * @param string $key
245
     * @param mixed  $value
246
     *
247
     * @return $this
248
     */
249 388
    public function setAttribute($key, $value)
250
    {
251 388
        list($attribute, $locale) = $this->getAttributeAndLocale($key);
252
253 388
        if ($this->isTranslationAttribute($attribute)) {
254 40
            $this->getTranslationOrNew($locale)->$attribute = $value;
255
        } else {
256 388
            return parent::setAttribute($key, $value);
257
        }
258
259 40
        return $this;
260
    }
261
262
    /**
263
     * @param array $options
264
     *
265
     * @return bool
266
     */
267 388
    public function save(array $options = [])
268
    {
269 388
        if ($this->exists && ! $this->isDirty()) {
0 ignored issues
show
Bug introduced by
The property exists does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Bug introduced by
It seems like isDirty() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
270
            // If $this->exists and not dirty, parent::save() skips saving and returns
271
            // false. So we have to save the translations
272 24
            if ($this->fireModelEvent('saving') === false) {
0 ignored issues
show
Bug introduced by
It seems like fireModelEvent() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
273
                return false;
274
            }
275
276 24
            if ($saved = $this->saveTranslations()) {
277 24
                $this->fireModelEvent('saved', false);
0 ignored issues
show
Bug introduced by
It seems like fireModelEvent() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
278 24
                $this->fireModelEvent('updated', false);
0 ignored issues
show
Bug introduced by
It seems like fireModelEvent() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
279
            }
280
281 24
            return $saved;
282
        }
283
284
        // We save the translations only if the instance is saved in the database.
285 388
        if (parent::save($options)) {
286 388
            return $this->saveTranslations();
287
        }
288
289 8
        return false;
290
    }
291
292
    /**
293
     * @param string $locale
294
     *
295
     * @return \Illuminate\Database\Eloquent\Model
296
     */
297 140
    protected function getTranslationOrNew($locale = null)
298
    {
299 140
        $locale = $locale ?: $this->locale();
300
301 140
        if (($translation = $this->getTranslation($locale, false)) === null) {
302 124
            $translation = $this->getNewTranslation($locale);
303
        }
304
305 140
        return $translation;
306
    }
307
308
    /**
309
     * @param array $attributes
310
     *
311
     * @throws \Illuminate\Database\Eloquent\MassAssignmentException
312
     * @return $this
313
     */
314 388
    public function fill(array $attributes)
315
    {
316 388
        foreach ($attributes as $key => $values) {
317 112
            if ($this->isKeyALocale($key)) {
318 48
                $this->getTranslationOrNew($key)->fill($values);
319 40
                unset($attributes[$key]);
320
            } else {
321 100
                list($attribute, $locale) = $this->getAttributeAndLocale($key);
322 100
                if ($this->isTranslationAttribute($attribute) and $this->isKeyALocale($locale)) {
323 48
                    $this->getTranslationOrNew($locale)->fill([$attribute => $values]);
324 48
                    unset($attributes[$key]);
325
                }
326
            }
327
        }
328
329 388
        return parent::fill($attributes);
330
    }
331
332
    /**
333
     * @param string $key
334
     */
335 248
    private function getTranslationByLocaleKey($key)
336
    {
337 248
        foreach ($this->translations as $translation) {
0 ignored issues
show
Bug introduced by
The property translations does not seem to exist. Did you mean autoloadTranslations?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
338 196
            if ($translation->getAttribute($this->getLocaleKey()) == $key) {
339 164
                return $translation;
340
            }
341
        }
342
343 168
        return null;
344
    }
345
346
    /**
347
     * @param null $locale
348
     *
349
     * @return string
350
     */
351 252
    private function getFallbackLocale($locale = null)
352
    {
353 252
        if ($locale && $this->isLocaleCountryBased($locale)) {
354 28
            if ($fallback = $this->getLanguageFromCountryBasedLocale($locale)) {
355 28
                return $fallback;
356
            }
357
        }
358
359 252
        return config('translatable.fallback_locale');
360
    }
361
362
    /**
363
     * @param $locale
364
     *
365
     * @return bool
366
     */
367 248
    private function isLocaleCountryBased($locale)
368
    {
369 248
        return strpos($locale, $this->getLocaleSeparator()) !== false;
370
    }
371
372
    /**
373
     * @param $locale
374
     *
375
     * @return string
376
     */
377 28
    private function getLanguageFromCountryBasedLocale($locale)
378
    {
379 28
        $parts = explode($this->getLocaleSeparator(), $locale);
380
381 28
        return array_get($parts, 0);
0 ignored issues
show
Deprecated Code introduced by
The function array_get() has been deprecated with message: Arr::get() should be used directly instead. Will be removed in Laravel 5.9.

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
382
    }
383
384
    /**
385
     * @return bool|null
386
     */
387 144
    private function useFallback()
388
    {
389 144
        if (isset($this->useTranslationFallback) && $this->useTranslationFallback !== null) {
390 12
            return $this->useTranslationFallback;
0 ignored issues
show
Bug introduced by
The property useTranslationFallback does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
391
        }
392
393 132
        return config('translatable.use_fallback');
394
    }
395
396
    /**
397
     * @param string $key
398
     *
399
     * @return bool
400
     */
401 388
    public function isTranslationAttribute($key)
402
    {
403 388
        return in_array($key, $this->translatedAttributes);
0 ignored issues
show
Bug introduced by
The property translatedAttributes does not seem to exist. Did you mean attributes?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
404
    }
405
406
    /**
407
     * @param string $key
408
     *
409
     * @throws \Dimsav\Translatable\Exception\LocalesNotDefinedException
410
     * @return bool
411
     */
412 112
    protected function isKeyALocale($key)
413
    {
414 112
        $locales = $this->getLocales();
415
416 108
        return in_array($key, $locales);
417
    }
418
419
    /**
420
     * @throws \Dimsav\Translatable\Exception\LocalesNotDefinedException
421
     * @return array
422
     */
423 112
    protected function getLocales()
424
    {
425 112
        $localesConfig = (array) config('translatable.locales');
426
427 112
        if (empty($localesConfig)) {
428 4
            throw new LocalesNotDefinedException('Please make sure you have run "php artisan config:publish dimsav/laravel-translatable" '.
429 4
                ' and that the locales configuration is defined.');
430
        }
431
432 108
        $locales = [];
433 108
        foreach ($localesConfig as $key => $locale) {
434 108
            if (is_array($locale)) {
435 20
                $locales[] = $key;
436 20
                foreach ($locale as $countryLocale) {
437 20
                    $locales[] = $key.$this->getLocaleSeparator().$countryLocale;
438
                }
439
            } else {
440 100
                $locales[] = $locale;
441
            }
442
        }
443
444 108
        return $locales;
445
    }
446
447
    /**
448
     * @return string
449
     */
450 248
    protected function getLocaleSeparator()
451
    {
452 248
        return config('translatable.locale_separator', '-');
453
    }
454
455
    /**
456
     * @return bool
457
     */
458 388
    protected function saveTranslations()
459
    {
460 388
        $saved = true;
461
462 388
        if (! $this->relationLoaded('translations')) {
0 ignored issues
show
Bug introduced by
It seems like relationLoaded() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
463 388
            return $saved;
464
        }
465
466 100
        foreach ($this->translations as $translation) {
0 ignored issues
show
Bug introduced by
The property translations does not seem to exist. Did you mean autoloadTranslations?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
467 100
            if ($saved && $this->isTranslationDirty($translation)) {
468 100
                if (! empty($connectionName = $this->getConnectionName())) {
0 ignored issues
show
Bug introduced by
It seems like getConnectionName() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
469 100
                    $translation->setConnection($connectionName);
470
                }
471
472 100
                $translation->setAttribute($this->getRelationKey(), $this->getKey());
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?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
473 100
                $saved = $translation->save();
474
            }
475
        }
476
477 96
        return $saved;
478
    }
479
480
    /**
481
     * @param array
482
     *
483
     * @return \Illuminate\Database\Eloquent\Model
484
     */
485 4
    public function replicateWithTranslations(array $except = null)
486
    {
487 4
        $newInstance = parent::replicate($except);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (replicate() instead of replicateWithTranslations()). Are you sure this is correct? If so, you might want to change this to $this->replicate().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
488
489 4
        unset($newInstance->translations);
490 4
        foreach ($this->translations as $translation) {
0 ignored issues
show
Bug introduced by
The property translations does not seem to exist. Did you mean autoloadTranslations?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
491 4
            $newTranslation = $translation->replicate();
492 4
            $newInstance->translations->add($newTranslation);
493
        }
494
495 4
        return  $newInstance;
496
    }
497
498
    /**
499
     * @param \Illuminate\Database\Eloquent\Model $translation
500
     *
501
     * @return bool
502
     */
503 100
    protected function isTranslationDirty(Model $translation)
504
    {
505 100
        $dirtyAttributes = $translation->getDirty();
506 100
        unset($dirtyAttributes[$this->getLocaleKey()]);
507
508 100
        return count($dirtyAttributes) > 0;
509
    }
510
511
    /**
512
     * @param string $locale
513
     *
514
     * @return \Illuminate\Database\Eloquent\Model
515
     */
516 128
    public function getNewTranslation($locale)
517
    {
518 128
        $modelName = $this->getTranslationModelName();
519 128
        $translation = new $modelName();
520 128
        $translation->setAttribute($this->getLocaleKey(), $locale);
521 128
        $this->translations->add($translation);
0 ignored issues
show
Bug introduced by
The property translations does not seem to exist. Did you mean autoloadTranslations?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
522
523 128
        return $translation;
524
    }
525
526
    /**
527
     * @param $key
528
     *
529
     * @return bool
530
     */
531 148
    public function __isset($key)
532
    {
533 148
        return $this->isTranslationAttribute($key) || parent::__isset($key);
534
    }
535
536
    /**
537
     * @param \Illuminate\Database\Eloquent\Builder $query
538
     * @param string                                $locale
539
     *
540
     * @return \Illuminate\Database\Eloquent\Builder|static
541
     */
542 8 View Code Duplication
    public function scopeTranslatedIn(Builder $query, $locale = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
543
    {
544 8
        $locale = $locale ?: $this->locale();
545
546
        return $query->whereHas('translations', function (Builder $q) use ($locale) {
547 8
            $q->where($this->getLocaleKey(), '=', $locale);
548 8
        });
549
    }
550
551
    /**
552
     * @param \Illuminate\Database\Eloquent\Builder $query
553
     * @param string                                $locale
554
     *
555
     * @return \Illuminate\Database\Eloquent\Builder|static
556
     */
557 8 View Code Duplication
    public function scopeNotTranslatedIn(Builder $query, $locale = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
558
    {
559 8
        $locale = $locale ?: $this->locale();
560
561
        return $query->whereDoesntHave('translations', function (Builder $q) use ($locale) {
562 8
            $q->where($this->getLocaleKey(), '=', $locale);
563 8
        });
564
    }
565
566
    /**
567
     * @param \Illuminate\Database\Eloquent\Builder $query
568
     *
569
     * @return \Illuminate\Database\Eloquent\Builder|static
570
     */
571 4
    public function scopeTranslated(Builder $query)
572
    {
573 4
        return $query->has('translations');
574
    }
575
576
    /**
577
     * Adds scope to get a list of translated attributes, using the current locale.
578
     * Example usage: Country::listsTranslations('name')->get()->toArray()
579
     * Will return an array with items:
580
     *  [
581
     *      'id' => '1',                // The id of country
582
     *      'name' => 'Griechenland'    // The translated name
583
     *  ].
584
     *
585
     * @param \Illuminate\Database\Eloquent\Builder $query
586
     * @param string                                $translationField
587
     */
588 12
    public function scopeListsTranslations(Builder $query, $translationField)
589
    {
590 12
        $withFallback = $this->useFallback();
591 12
        $translationTable = $this->getTranslationsTable();
592 12
        $localeKey = $this->getLocaleKey();
593
594
        $query
0 ignored issues
show
Bug introduced by
The method select() does not exist on Illuminate\Database\Eloquent\Builder. Did you maybe mean createSelectWithConstraint()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
595 12
            ->select($this->getTable().'.'.$this->getKeyName(), $translationTable.'.'.$translationField)
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?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

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?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
596 12
            ->leftJoin($translationTable, $translationTable.'.'.$this->getRelationKey(), '=', $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?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

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?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
597 12
            ->where($translationTable.'.'.$localeKey, $this->locale());
598 12
        if ($withFallback) {
599
            $query->orWhere(function (Builder $q) use ($translationTable, $localeKey) {
600 4
                $q->where($translationTable.'.'.$localeKey, $this->getFallbackLocale())
601
                  ->whereNotIn($translationTable.'.'.$this->getRelationKey(), function (QueryBuilder $q) use (
602 4
                      $translationTable,
603 4
                      $localeKey
604
                  ) {
605 4
                      $q->select($translationTable.'.'.$this->getRelationKey())
606 4
                        ->from($translationTable)
607 4
                        ->where($translationTable.'.'.$localeKey, $this->locale());
608 4
                  });
609 4
            });
610
        }
611 12
    }
612
613
    /**
614
     * This scope eager loads the translations for the default and the fallback locale only.
615
     * We can use this as a shortcut to improve performance in our application.
616
     *
617
     * @param Builder $query
618
     */
619 12
    public function scopeWithTranslation(Builder $query)
620
    {
621 12
        $query->with([
622
            'translations' => function (Relation $query) {
623 12
                if ($this->useFallback()) {
624 8
                    $locale = $this->locale();
625 8
                    $countryFallbackLocale = $this->getFallbackLocale($locale); // e.g. de-DE => de
626 8
                    $locales = array_unique([$locale, $countryFallbackLocale, $this->getFallbackLocale()]);
627
628 8
                    return $query->whereIn($this->getTranslationsTable().'.'.$this->getLocaleKey(), $locales);
0 ignored issues
show
Bug introduced by
The method whereIn() does not exist on Illuminate\Database\Eloquent\Relations\Relation. Did you maybe mean whereInMethod()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
629
                }
630
631 4
                return $query->where($this->getTranslationsTable().'.'.$this->getLocaleKey(), $this->locale());
632 12
            },
633
        ]);
634 12
    }
635
636
    /**
637
     * This scope filters results by checking the translation fields.
638
     *
639
     * @param \Illuminate\Database\Eloquent\Builder $query
640
     * @param string                                $key
641
     * @param string                                $value
642
     * @param string                                $locale
643
     *
644
     * @return \Illuminate\Database\Eloquent\Builder|static
645
     */
646 12 View Code Duplication
    public function scopeWhereTranslation(Builder $query, $key, $value, $locale = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
647
    {
648
        return $query->whereHas('translations', function (Builder $query) use ($key, $value, $locale) {
649 12
            $query->where($this->getTranslationsTable().'.'.$key, $value);
650 12
            if ($locale) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $locale of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
651 4
                $query->where($this->getTranslationsTable().'.'.$this->getLocaleKey(), $locale);
652
            }
653 12
        });
654
    }
655
656
    /**
657
     * This scope filters results by checking the translation fields.
658
     *
659
     * @param \Illuminate\Database\Eloquent\Builder $query
660
     * @param string                                $key
661
     * @param string                                $value
662
     * @param string                                $locale
663
     *
664
     * @return \Illuminate\Database\Eloquent\Builder|static
665
     */
666 4 View Code Duplication
    public function scopeOrWhereTranslation(Builder $query, $key, $value, $locale = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
667
    {
668
        return $query->orWhereHas('translations', function (Builder $query) use ($key, $value, $locale) {
669 4
            $query->where($this->getTranslationsTable().'.'.$key, $value);
670 4
            if ($locale) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $locale of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
671
                $query->where($this->getTranslationsTable().'.'.$this->getLocaleKey(), $locale);
672
            }
673 4
        });
674
    }
675
676
    /**
677
     * This scope filters results by checking the translation fields.
678
     *
679
     * @param \Illuminate\Database\Eloquent\Builder $query
680
     * @param string                                $key
681
     * @param string                                $value
682
     * @param string                                $locale
683
     *
684
     * @return \Illuminate\Database\Eloquent\Builder|static
685
     */
686 12 View Code Duplication
    public function scopeWhereTranslationLike(Builder $query, $key, $value, $locale = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
687
    {
688
        return $query->whereHas('translations', function (Builder $query) use ($key, $value, $locale) {
689 12
            $query->where($this->getTranslationsTable().'.'.$key, 'LIKE', $value);
690 12
            if ($locale) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $locale of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
691 4
                $query->where($this->getTranslationsTable().'.'.$this->getLocaleKey(), 'LIKE', $locale);
692
            }
693 12
        });
694
    }
695
696
    /**
697
     * This scope filters results by checking the translation fields.
698
     *
699
     * @param \Illuminate\Database\Eloquent\Builder $query
700
     * @param string                                $key
701
     * @param string                                $value
702
     * @param string                                $locale
703
     *
704
     * @return \Illuminate\Database\Eloquent\Builder|static
705
     */
706 4 View Code Duplication
    public function scopeOrWhereTranslationLike(Builder $query, $key, $value, $locale = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
707
    {
708
        return $query->orWhereHas('translations', function (Builder $query) use ($key, $value, $locale) {
709 4
            $query->where($this->getTranslationsTable().'.'.$key, 'LIKE', $value);
710 4
            if ($locale) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $locale of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
711
                $query->where($this->getTranslationsTable().'.'.$this->getLocaleKey(), 'LIKE', $locale);
712
            }
713 4
        });
714
    }
715
716
    /**
717
     * This scope sorts results by the given translation field.
718
     *
719
     * @param \Illuminate\Database\Eloquent\Builder $query
720
     * @param string                                $key
721
     * @param string                                $sortmethod
722
     *
723
     * @return \Illuminate\Database\Eloquent\Builder|static
724
     */
725 8
    public function scopeOrderByTranslation(Builder $query, $key, $sortmethod = 'asc')
726
    {
727 8
        $translationTable = $this->getTranslationsTable();
728 8
        $localeKey = $this->getLocaleKey();
729 8
        $table = $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?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
730 8
        $keyName = $this->getKeyName();
0 ignored issues
show
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?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
731
732
        return $query
733
            ->join($translationTable, function (JoinClause $join) use ($translationTable, $localeKey, $table, $keyName) {
734
                $join
735 8
                    ->on($translationTable.'.'.$this->getRelationKey(), '=', $table.'.'.$keyName)
736 8
                    ->where($translationTable.'.'.$localeKey, $this->locale());
737 8
            })
738 8
            ->orderBy($translationTable.'.'.$key, $sortmethod)
739 8
            ->select($table.'.*')
740 8
            ->with('translations');
741
    }
742
743
    /**
744
     * @return array
745
     */
746 48
    public function attributesToArray()
747
    {
748 48
        if (config('translatable.to_array_always_loads_translation', false)) {
749
            return $this->attributesToArrayForCurrentTranslation();
750
        }
751
        
752 48
        $attributes = parent::attributesToArray();
753
754
        if (
755 48
            (! $this->relationLoaded('translations') && ! $this->toArrayAlwaysLoadsTranslations() && is_null(self::$autoloadTranslations))
0 ignored issues
show
Bug introduced by
It seems like relationLoaded() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
756 48
            || self::$autoloadTranslations === false
757
        ) {
758 16
            return $attributes;
759
        }
760
761 32
        $hiddenAttributes = $this->getHidden();
0 ignored issues
show
Bug introduced by
It seems like getHidden() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
762
763 32
        foreach ($this->translatedAttributes as $field) {
0 ignored issues
show
Bug introduced by
The property translatedAttributes does not seem to exist. Did you mean attributes?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
764 32
            if (in_array($field, $hiddenAttributes)) {
765 4
                continue;
766
            }
767
768 32
            $attributes[$field] = $this->getAttributeOrFallback(null, $field);
769
        }
770
771 32
        return $attributes;
772
    }
773
774
    /**
775
     * @return array
776
     */
777 4
    public function getTranslationsArray()
778
    {
779 4
        $translations = [];
780
781 4
        foreach ($this->translations as $translation) {
0 ignored issues
show
Bug introduced by
The property translations does not seem to exist. Did you mean autoloadTranslations?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
782 4
            foreach ($this->translatedAttributes as $attr) {
0 ignored issues
show
Bug introduced by
The property translatedAttributes does not seem to exist. Did you mean attributes?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
783 4
                $translations[$translation->{$this->getLocaleKey()}][$attr] = $translation->{$attr};
784
            }
785
        }
786
787 4
        return $translations;
788
    }
789
790
    /**
791
     * @return string
792
     */
793 56
    private function getTranslationsTable()
794
    {
795 56
        return app()->make($this->getTranslationModelName())->getTable();
796
    }
797
798
    /**
799
     * @return string
800
     */
801 388
    protected function locale()
802
    {
803 388
        if ($this->defaultLocale) {
804 4
            return $this->defaultLocale;
805
        }
806
807 388
        return config('translatable.locale')
808 388
            ?: app()->make('translator')->getLocale();
809
    }
810
811
    /**
812
     * Set the default locale on the model.
813
     *
814
     * @param $locale
815
     *
816
     * @return $this
817
     */
818 4
    public function setDefaultLocale($locale)
819
    {
820 4
        $this->defaultLocale = $locale;
821
822 4
        return $this;
823
    }
824
825
    /**
826
     * Get the default locale on the model.
827
     *
828
     * @return mixed
829
     */
830
    public function getDefaultLocale()
831
    {
832
        return $this->defaultLocale;
833
    }
834
835
    /**
836
     * Deletes all translations for this model.
837
     *
838
     * @param string|array|null $locales The locales to be deleted (array or single string)
839
     *                                   (e.g., ["en", "de"] would remove these translations).
840
     */
841 12
    public function deleteTranslations($locales = null)
842
    {
843 12
        if ($locales === null) {
844 4
            $translations = $this->translations()->get();
845
        } else {
846 8
            $locales = (array) $locales;
847 8
            $translations = $this->translations()->whereIn($this->getLocaleKey(), $locales)->get();
0 ignored issues
show
Bug introduced by
The method whereIn() does not exist on Illuminate\Database\Eloquent\Relations\HasMany. Did you maybe mean whereInMethod()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
848
        }
849 12
        foreach ($translations as $translation) {
850 8
            $translation->delete();
851
        }
852
853
        // we need to manually "reload" the collection built from the relationship
854
        // otherwise $this->translations()->get() would NOT be the same as $this->translations
855 12
        $this->load('translations');
0 ignored issues
show
Bug introduced by
It seems like load() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
856 12
    }
857
858
    /**
859
     * @param $key
860
     *
861
     * @return array
862
     */
863 388
    private function getAttributeAndLocale($key)
864
    {
865 388
        if (str_contains($key, ':')) {
0 ignored issues
show
Deprecated Code introduced by
The function str_contains() has been deprecated with message: Str::contains() should be used directly instead. Will be removed in Laravel 5.9.

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
866 44
            return explode(':', $key);
867
        }
868
869 388
        return [$key, $this->locale()];
870
    }
871
872
    /**
873
     * @return bool
874
     */
875 32
    private function toArrayAlwaysLoadsTranslations()
876
    {
877 32
        return config('translatable.to_array_always_loads_translations', true);
878
    }
879
880
    public static function enableAutoloadTranslations()
881
    {
882
        self::$autoloadTranslations = true;
883
    }
884
885 4
    public static function defaultAutoloadTranslations()
886
    {
887 4
        self::$autoloadTranslations = null;
888 4
    }
889
890 4
    public static function disableAutoloadTranslations()
891
    {
892 4
        self::$autoloadTranslations = false;
893 4
    }
894
    
895
    private function attributesToArrayForCurrentTranslation()
896
    {
897
        $attributes = parent::attributesToArray();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (attributesToArray() instead of attributesToArrayForCurrentTranslation()). Are you sure this is correct? If so, you might want to change this to $this->attributesToArray().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
898
        $this->addHidden(['translation']); // we don't need this
0 ignored issues
show
Bug introduced by
It seems like addHidden() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
899
        foreach ($this->translatedAttributes as $field) {
0 ignored issues
show
Bug introduced by
The property translatedAttributes does not seem to exist. Did you mean attributes?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
900
            if (in_array($field, $this->getHidden())) {
0 ignored issues
show
Bug introduced by
It seems like getHidden() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
901
                continue;
902
            }
903
904
            $attributes[$field] = $this->translation->$field;
0 ignored issues
show
Bug introduced by
The property translation does not seem to exist. Did you mean autoloadTranslations?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
905
        }
906
907
        return $attributes;
908
    }
909
}
910