Completed
Push — master ( 63e4f4...928024 )
by Ryan
07:17
created

EloquentModel::isTranslationDirty()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
c 0
b 0
f 0
rs 9.4285
cc 1
eloc 4
nc 1
nop 1
1
<?php namespace Anomaly\Streams\Platform\Model;
2
3
use Anomaly\Streams\Platform\Collection\CacheCollection;
4
use Anomaly\Streams\Platform\Traits\Hookable;
5
use Illuminate\Contracts\Support\Arrayable;
6
use Illuminate\Database\Eloquent\Builder;
7
use Illuminate\Database\Eloquent\Collection;
8
use Illuminate\Database\Eloquent\Model;
9
use Illuminate\Foundation\Bus\DispatchesJobs;
10
11
/**
12
 * Class EloquentModel
13
 *
14
 * @link    http://anomaly.is/streams-platform
15
 * @author  AnomalyLabs, Inc. <[email protected]>
16
 * @author  Ryan Thompson <[email protected]>
17
 */
18
class EloquentModel extends Model implements Arrayable
19
{
20
    use DispatchesJobs;
21
    use Hookable;
22
23
    /**
24
     * Disable timestamps for this model.
25
     *
26
     * @var bool
27
     */
28
    public $timestamps = false;
29
30
    /**
31
     * Translatable attributes.
32
     *
33
     * @var array
34
     */
35
    protected $translatedAttributes = [];
36
37
    /**
38
     * The number of minutes to cache query results.
39
     *
40
     * @var null|false|int
41
     */
42
    protected $ttl = false;
43
44
    /**
45
     * The attributes that are
46
     * not mass assignable. Let upper
47
     * models handle this themselves.
48
     *
49
     * @var array
50
     */
51
    protected $guarded = [];
52
53
    /**
54
     * The title key.
55
     *
56
     * @var string
57
     */
58
    protected $titleKey = 'id';
59
60
    /**
61
     * Observable model events.
62
     *
63
     * @var array
64
     */
65
    protected $observables = [
66
        'updatingMultiple',
67
        'updatedMultiple',
68
        'deletingMultiple',
69
        'deletedMultiple',
70
    ];
71
72
    /**
73
     * Runtime cache.
74
     *
75
     * @var array
76
     */
77
    protected $cache = [];
78
79
    /**
80
     * Get the ID.
81
     *
82
     * @return integer
83
     */
84
    public function getId()
85
    {
86
        return $this->id;
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<Anomaly\Streams\P...rm\Model\EloquentModel>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
87
    }
88
89
    /**
90
     * Return the object's ETag fingerprint.
91
     *
92
     * @return string
93
     */
94
    public function etag()
95
    {
96
        return md5(get_class($this) . json_encode($this->toArray()));
97
    }
98
99
    /**
100
     * Alias for $this->setTtl($ttl)
101
     *
102
     * @param $ttl
103
     * @return EloquentModel
104
     */
105
    public function cache($ttl)
106
    {
107
        return $this->setTtl($ttl);
108
    }
109
110
    /**
111
     * Fire a model event.
112
     *
113
     * @param $event
114
     * @return mixed
115
     */
116
    public function fireEvent($event)
117
    {
118
        return $this->fireModelEvent($event);
119
    }
120
121
    /**
122
     * Return a new collection class with our models.
123
     *
124
     * @param  array      $items
125
     * @return Collection
126
     */
127 View Code Duplication
    public function newCollection(array $items = [])
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...
128
    {
129
        $collection = substr(get_class($this), 0, -5) . 'Collection';
130
131
        if (class_exists($collection)) {
132
            return new $collection($items);
133
        }
134
135
        return new EloquentCollection($items);
136
    }
137
138
    /**
139
     * Return the translatable flag.
140
     *
141
     * @return bool
142
     */
143
    public function isTranslatable()
144
    {
145
        return isset($this->translationModel);
146
    }
147
148
    /**
149
     * Set the translatable flag.
150
     *
151
     * @param $translatable
152
     * @return $this
153
     */
154
    public function setTranslatable($translatable)
155
    {
156
        $this->translatable = $translatable;
0 ignored issues
show
Documentation introduced by
The property translatable does not exist on object<Anomaly\Streams\P...rm\Model\EloquentModel>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
157
158
        return $this;
159
    }
160
161
    /**
162
     * Set the ttl.
163
     *
164
     * @param  $ttl
165
     * @return $this
166
     */
167
    public function setTtl($ttl)
168
    {
169
        $this->ttl = $ttl;
170
171
        return $this;
172
    }
173
174
    /**
175
     * Get the ttl.
176
     *
177
     * @return int|mixed
178
     */
179
    public function getTtl()
180
    {
181
        return $this->ttl;
182
    }
183
184
    /**
185
     * Get cache collection key.
186
     *
187
     * @return string
188
     */
189
    public function getCacheCollectionKey()
190
    {
191
        return get_called_class();
192
    }
193
194
    /**
195
     * Get the model title.
196
     *
197
     * @return mixed
198
     */
199
    public function getTitle()
200
    {
201
        return $this->{$this->getTitleName()};
202
    }
203
204
    /**
205
     * Get the title key.
206
     *
207
     * @return string
208
     */
209
    public function getTitleName()
210
    {
211
        return $this->titleName ?: 'id';
0 ignored issues
show
Documentation introduced by
The property titleName does not exist on object<Anomaly\Streams\P...rm\Model\EloquentModel>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
212
    }
213
214
    /**
215
     * Return if a row is deletable or not.
216
     *
217
     * @return bool
218
     */
219
    public function isDeletable()
220
    {
221
        return true;
222
    }
223
224
    /**
225
     * Return if the model is restorable or not.
226
     *
227
     * @return bool
228
     */
229
    public function isRestorable()
230
    {
231
        return true;
232
    }
233
234
    /**
235
     * Return whether the model is being
236
     * force deleted or not.
237
     *
238
     * @return bool
239
     */
240
    public function isForceDeleting()
241
    {
242
        return isset($this->forceDeleting) && $this->forceDeleting == true;
0 ignored issues
show
Documentation introduced by
The property forceDeleting does not exist on object<Anomaly\Streams\P...rm\Model\EloquentModel>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
243
    }
244
245
    /**
246
     * Flush the model's cache.
247
     *
248
     * @return $this
249
     */
250
    public function flushCache()
251
    {
252
        (new CacheCollection())->setKey($this->getCacheCollectionKey())->flush();
253
254
        return $this;
255
    }
256
257
    /**
258
     * Get a new query builder for the model's table.
259
     *
260
     * @return \Illuminate\Database\Eloquent\Builder
261
     */
262 View Code Duplication
    public function newQuery()
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...
263
    {
264
        $builder = new EloquentQueryBuilder($this->newBaseQueryBuilder());
265
266
        // Once we have the query builders, we will set the model instances so the
267
        // builder can easily access any information it may need from the model
268
        // while it is constructing and executing various queries against it.
269
        $builder->setModel($this)->with($this->with);
270
271
        return $this->applyGlobalScopes($builder);
272
    }
273
274
    /*
275
     * Alias for getTranslation()
276
     */
277
    public function translate($locale = null, $withFallback = false)
278
    {
279
        return $this->getTranslation($locale, $withFallback);
280
    }
281
282
    /*
283
     * Alias for getTranslation()
284
     */
285
    public function translateOrDefault($locale)
286
    {
287
        return $this->getTranslation($locale, true) ?: $this;
288
    }
289
290
    /*
291
     * Alias for getTranslationOrNew()
292
     */
293
    public function translateOrNew($locale)
294
    {
295
        return $this->getTranslationOrNew($locale);
296
    }
297
298
    /**
299
     * Get related translations.
300
     *
301
     * @return EloquentCollection
302
     */
303
    public function getTranslations()
304
    {
305
        foreach ($translations = $this->translations()->get() as $translation) {
306
            $translation->setRelation('parent', $this);
307
        }
308
309
        return $translations;
310
    }
311
312
    /**
313
     * @param  null       $locale
314
     * @param  bool|null  $withFallback
315
     * @return Model|null
316
     */
317
    public function getTranslation($locale = null, $withFallback = false)
318
    {
319
        $locale = $locale ?: $this->getFallbackLocale();
320
321
        if ($translation = $this->getTranslationByLocaleKey($locale)) {
322
            return $translation;
323
        } elseif ($withFallback
324
            && $this->getFallbackLocale()
325
            && $this->getTranslationByLocaleKey($this->getFallbackLocale())
326
        ) {
327
            return $this->getTranslationByLocaleKey($this->getFallbackLocale());
328
        }
329
330
        return null;
331
    }
332
333
    public function hasTranslation($locale = null)
334
    {
335
        $locale = $locale ?: $this->getFallbackLocale();
336
337 View Code Duplication
        foreach ($this->translations as $translation) {
0 ignored issues
show
Documentation introduced by
The property translations does not exist on object<Anomaly\Streams\P...rm\Model\EloquentModel>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Duplication introduced by
This code seems to be duplicated across 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...
338
            $translation->setRelation('parent', $this);
339
340
            if ($translation->getAttribute($this->getLocaleKey()) == $locale) {
341
                return true;
342
            }
343
        }
344
345
        return false;
346
    }
347
348
    /**
349
     * Get the translation model.
350
     *
351
     * @return EloquentModel
352
     */
353
    public function getTranslationModel()
354
    {
355
        return new $this->translationModel;
0 ignored issues
show
Documentation introduced by
The property translationModel does not exist on object<Anomaly\Streams\P...rm\Model\EloquentModel>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
356
    }
357
358
    /**
359
     * Get the translation model name.
360
     *
361
     * @return string
362
     */
363
    public function getTranslationModelName()
364
    {
365
        return $this->translationModel;
0 ignored issues
show
Documentation introduced by
The property translationModel does not exist on object<Anomaly\Streams\P...rm\Model\EloquentModel>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
366
    }
367
368
    /**
369
     * Get the translation table name.
370
     *
371
     * @return string
372
     */
373
    public function getTranslationTableName()
374
    {
375
        $model = $this->getTranslationModel();
376
377
        return $model->getTableName();
378
    }
379
380
    public function getTranslationModelNameDefault()
381
    {
382
        return get_class($this) . 'Translation';
383
    }
384
385
    public function getRelationKey()
386
    {
387
        return $this->translationForeignKey ?: $this->getForeignKey();
0 ignored issues
show
Documentation introduced by
The property translationForeignKey does not exist on object<Anomaly\Streams\P...rm\Model\EloquentModel>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
388
    }
389
390
    public function getLocaleKey()
391
    {
392
        return $this->localeKey ?: 'locale';
0 ignored issues
show
Documentation introduced by
The property localeKey does not exist on object<Anomaly\Streams\P...rm\Model\EloquentModel>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
393
    }
394
395
    public function translations()
396
    {
397
        return $this->hasMany($this->getTranslationModelName(), $this->getRelationKey());
398
    }
399
400
    public function getAttribute($key)
401
    {
402
        if ($this->isTranslatedAttribute($key)) {
403
            if ($this->getTranslation() === null) {
404
                return null;
405
            }
406
407
            $translation = $this->getTranslation();
408
409
            $translation->setRelation('parent', $this);
410
411
            return $translation->$key;
412
        }
413
414
        return parent::getAttribute($key);
415
    }
416
417
    /**
418
     * Set an attribute.
419
     *
420
     * @param  string $key
421
     * @param  mixed  $value
422
     * @return $this
423
     */
424
    public function setAttribute($key, $value)
425
    {
426
        if (in_array($key, $this->translatedAttributes)) {
427
            $this->getTranslationOrNew(config('app.locale'))->$key = $value;
428
        } else {
429
            parent::setAttribute($key, $value);
430
        }
431
432
        return $this;
433
    }
434
435
    /**
436
     * Save the model.
437
     *
438
     * We have some customization here to
439
     * accommodate translations. First sa
440
     * then save translations is translatable.
441
     *
442
     * @param  array $options
443
     * @return bool
444
     */
445
    public function save(array $options = [])
446
    {
447
        if (!$this->getTranslationModelName()) {
448
            return $this->saveModel($options);
449
        }
450
451
        if ($this->exists) {
452
            if (count($this->getDirty()) > 0) {
453
454
                // If $this->exists and dirty, $this->saveModel() has to return true. If not,
0 ignored issues
show
Unused Code Comprehensibility introduced by
42% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
455
                // an error has occurred. Therefore we shouldn't save the translations.
456
                if ($this->saveModel($options)) {
457
                    return $this->saveTranslations();
458
                }
459
460
                return false;
461
            } else {
462
463
                // If $this->exists and not dirty, $this->saveModel() skips saving and returns
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
464
                // false. So we have to save the translations
465
                return $this->saveTranslations();
466
            }
467
        } elseif ($this->saveModel($options)) {
468
469
            // We save the translations only if the instance is saved in the database.
470
            return $this->saveTranslations();
471
        }
472
473
        return false;
474
    }
475
476
    /**
477
     * Save the model to the database.
478
     *
479
     * This is a direct port from Eloquent
480
     * with the only exception being that if
481
     * the model is translatable it will NOT
482
     * fire the saved event. The saveTranslations
483
     * method will do that instead.
484
     *
485
     * @param  array $options
486
     * @return bool
487
     */
488
    public function saveModel(array $options = [])
489
    {
490
        $query = $this->newQueryWithoutScopes();
491
492
        // If the "saving" event returns false we'll bail out of the save and return
493
        // false, indicating that the save failed. This provides a chance for any
494
        // listeners to cancel save operations if validations fail or whatever.
495
        if ($this->fireModelEvent('saving') === false) {
496
            return false;
497
        }
498
499
        // If the model already exists in the database we can just update our record
500
        // that is already in this database using the current IDs in this "where"
501
        // clause to only update this model. Otherwise, we'll just insert them.
502
        if ($this->exists) {
503
            $saved = $this->performUpdate($query, $options);
0 ignored issues
show
Bug introduced by
It seems like $query defined by $this->newQueryWithoutScopes() on line 490 can also be of type object<Illuminate\Database\Eloquent\Model>; however, Illuminate\Database\Eloq...\Model::performUpdate() does only seem to accept object<Illuminate\Database\Eloquent\Builder>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
504
        }
505
506
        // If the model is brand new, we'll insert it into our database and set the
507
        // ID attribute on the model to the value of the newly inserted row's ID
508
        // which is typically an auto-increment value managed by the database.
509
        else {
510
            $saved = $this->performInsert($query, $options);
0 ignored issues
show
Bug introduced by
It seems like $query defined by $this->newQueryWithoutScopes() on line 490 can also be of type object<Illuminate\Database\Eloquent\Model>; however, Illuminate\Database\Eloq...\Model::performInsert() does only seem to accept object<Illuminate\Database\Eloquent\Builder>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
511
        }
512
513
        if ($saved && !$this->isTranslatable()) {
514
            $this->finishSave($options);
515
        }
516
517
        return $saved;
518
    }
519
520
    /**
521
     * Save translations to the database.
522
     *
523
     * @return bool
524
     */
525
    protected function saveTranslations()
526
    {
527
        $saved = true;
528
529
        foreach ($this->translations as $translation) {
0 ignored issues
show
Documentation introduced by
The property translations does not exist on object<Anomaly\Streams\P...rm\Model\EloquentModel>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
530
            $translation->setRelation('parent', $this);
531
532
            /* @var EloquentModel $translation */
533
            if ($saved && $this->isTranslationDirty($translation)) {
534
                $translation->setAttribute($this->getRelationKey(), $this->getKey());
535
536
                $saved = $translation->save();
537
            }
538
        }
539
540
        if ($this->translations->isEmpty()) {
0 ignored issues
show
Documentation introduced by
The property translations does not exist on object<Anomaly\Streams\P...rm\Model\EloquentModel>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
541
            $translation = $this->translateOrNew(config('streams::locales.default'));
542
543
            $translation->save();
544
        }
545
546
        $this->finishSave([]);
547
548
        return $saved;
549
    }
550
551
    protected function getTranslationOrNew($locale)
552
    {
553
        if (($translation = $this->getTranslation($locale, false)) === null) {
554
            $translation = $this->getNewTranslation($locale);
555
        }
556
557
        return $translation;
558
    }
559
560
    public function fill(array $attributes)
561
    {
562
        foreach ($attributes as $key => $values) {
563
            if (is_array($values) && $this->isKeyALocale($key)) {
564
                foreach ($values as $translationAttribute => $translationValue) {
565
                    if ($this->alwaysFillable() || $this->isFillable($translationAttribute)) {
566
                        $this->getTranslationOrNew($key)->$translationAttribute = $translationValue;
567
                    }
568
                }
569
                unset($attributes[$key]);
570
            }
571
        }
572
573
        return parent::fill($attributes);
574
    }
575
576
    private function getTranslationByLocaleKey($key)
577
    {
578 View Code Duplication
        foreach ($this->translations as $translation) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
Documentation introduced by
The property translations does not exist on object<Anomaly\Streams\P...rm\Model\EloquentModel>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
579
            $translation->setRelation('parent', $this);
580
581
            if ($translation->getAttribute($this->getLocaleKey()) == $key) {
582
                return $translation;
583
            }
584
        }
585
586
        return null;
587
    }
588
589
    public function isTranslatedAttribute($key)
590
    {
591
        return in_array($key, $this->translatedAttributes);
592
    }
593
594
    protected function isTranslationAttribute($key)
595
    {
596
        return in_array($key, $this->translatedAttributes);
597
    }
598
599
    protected function isKeyALocale($key)
600
    {
601
        return config('streams::locales.supported.' . $key) !== null;
602
    }
603
604
    protected function isTranslationDirty(Model $translation)
605
    {
606
        $dirtyAttributes = $translation->getDirty();
607
        unset($dirtyAttributes[$this->getLocaleKey()]);
608
609
        return count($dirtyAttributes) > 0;
610
    }
611
612
    public function getNewTranslation($locale)
613
    {
614
        $modelName = $this->getTranslationModelName();
615
616
        /* @var EloquentModel $translation */
617
        $translation = new $modelName;
618
619
        $translation->setRelation('parent', $this);
620
621
        $translation->setAttribute($this->getLocaleKey(), $locale);
622
        $translation->setAttribute($this->getRelationKey(), $this->getKey());
623
624
        $this->translations->add($translation);
0 ignored issues
show
Documentation introduced by
The property translations does not exist on object<Anomaly\Streams\P...rm\Model\EloquentModel>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
625
626
        return $translation;
627
    }
628
629
    public function scopeTranslatedIn(Builder $query, $locale)
630
    {
631
        return $query->whereHas(
632
            'translations',
633
            function (Builder $q) use ($locale) {
634
                $q->where($this->getLocaleKey(), '=', $locale);
635
            }
636
        );
637
    }
638
639
    public function scopeTranslated(Builder $query)
640
    {
641
        return $query->has('translations');
642
    }
643
644
    /**
645
     * Return unguarded attributes.
646
     *
647
     * @return array
648
     */
649
    public function getUnguardedAttributes()
650
    {
651
        foreach ($attributes = $this->getAttributes() as $attribute => $value) {
652
            $attributes[$attribute] = $this->{$attribute};
653
        }
654
655
        return array_diff_key($attributes, array_flip($this->getGuarded()));
656
    }
657
658
    /**
659
     * Get the fallback locale.
660
     *
661
     * @return string
662
     */
663
    protected function getFallbackLocale()
664
    {
665
        if (isset($this->cache['fallback_locale'])) {
666
            return $this->cache['fallback_locale'];
667
        }
668
669
        return $this->cache['fallback_locale'] = config('app.fallback_locale');
670
    }
671
672
    /**
673
     * This is to keep consistency with the
674
     * entry interface above us.
675
     *
676
     * @return string
677
     */
678
    public function getTableName()
679
    {
680
        return $this->getTable();
681
    }
682
683
    /**
684
     * Return if the entry is trashed or not.
685
     *
686
     * @return bool
687
     */
688
    public function trashed()
689
    {
690
        return parent::trashed();
691
    }
692
693
    public function toArray()
694
    {
695
        $attributes = $this->attributesToArray();
696
697
        foreach ($this->translatedAttributes as $field) {
698
            if ($translation = $this->getTranslation()) {
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $translation is correct as $this->getTranslation() (which targets Anomaly\Streams\Platform...Model::getTranslation()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
699
                $attributes[$field] = $translation->$field;
700
            }
701
        }
702
703
        return $attributes;
704
    }
705
706
    /**
707
     * Return the routable array information.
708
     *
709
     * @return array
710
     */
711
    public function toRoutableArray()
712
    {
713
        return $this->toArray();
714
    }
715
716
    private function alwaysFillable()
717
    {
718
        return false;
719
    }
720
721
    /**
722
     * Determine if the given attribute exists.
723
     * Make sure to skip where there could be an
724
     * issue with relational "looking" properties.
725
     *
726
     * @param  mixed $offset
727
     * @return bool
728
     */
729
    public function offsetExists($offset)
730
    {
731
        return !method_exists($this, $offset) && isset($this->$offset);
732
    }
733
734
    /**
735
     * Get the criteria class.
736
     *
737
     * @return string
738
     */
739
    public function getCriteriaName()
740
    {
741
        $criteria = substr(get_class($this), 0, -5) . 'Criteria';
742
743
        return class_exists($criteria) ? $criteria : EloquentCriteria::class;
744
    }
745
746
    public function __get($key)
747
    {
748
        if ($this->hasHook($key)) {
749
            return $this->call($key, []);
750
        }
751
752
        return parent::__get($key); // TODO: Change the autogenerated stub
753
    }
754
755
    public function __call($method, $parameters)
756
    {
757
        if ($this->hasHook($hook = snake_case($method))) {
758
            return $this->call($hook, $parameters);
759
        }
760
761
        return parent::__call($method, $parameters);
762
    }
763
764
    /**
765
     * Check if an attribute exists.
766
     *
767
     * @param  string $key
768
     * @return bool
769
     */
770
    public function __isset($key)
771
    {
772
        return (in_array($key, $this->translatedAttributes) || parent::__isset($key));
773
    }
774
775
    /**
776
     * Return the string form of the model.
777
     *
778
     * @return string
779
     */
780
    public function __toString()
781
    {
782
        return json_encode($this->toArray());
783
    }
784
}
785