EloquentModel::isKeyALocale()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
c 0
b 0
f 0
rs 10
cc 1
eloc 2
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
use Robbo\Presenter\PresentableInterface;
11
12
/**
13
 * Class EloquentModel
14
 *
15
 * @link   http://pyrocms.com/
16
 * @author PyroCMS, Inc. <[email protected]>
17
 * @author Ryan Thompson <[email protected]>
18
 */
19
class EloquentModel extends Model implements Arrayable, PresentableInterface
20
{
21
22
    use Hookable;
23
    use DispatchesJobs;
24
25
    /**
26
     * Disable timestamps for this model.
27
     *
28
     * @var bool
29
     */
30
    public $timestamps = false;
31
32
    /**
33
     * Translatable attributes.
34
     *
35
     * @var array
36
     */
37
    protected $translatedAttributes = [];
38
39
    /**
40
     * The number of minutes to cache query results.
41
     *
42
     * @var null|false|int
43
     */
44
    protected $ttl = false;
45
46
    /**
47
     * The attributes that are
48
     * not mass assignable. Let upper
49
     * models handle this themselves.
50
     *
51
     * @var array
52
     */
53
    protected $guarded = [];
54
55
    /**
56
     * The title key.
57
     *
58
     * @var string
59
     */
60
    protected $titleKey = 'id';
61
62
    /**
63
     * Observable model events.
64
     *
65
     * @var array
66
     */
67
    protected $observables = [
68
        'updatingMultiple',
69
        'updatedMultiple',
70
        'deletingMultiple',
71
        'deletedMultiple',
72
    ];
73
74
    /**
75
     * The cascading delete-able relations.
76
     *
77
     * @var array
78
     */
79
    protected $cascades = [];
80
81
    /**
82
     * Runtime cache.
83
     *
84
     * @var array
85
     */
86
    protected $cache = [];
87
88
    /**
89
     * Get the ID.
90
     *
91
     * @return integer
92
     */
93
    public function getId()
94
    {
95
        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...
96
    }
97
98
    /**
99
     * Return the object's ETag fingerprint.
100
     *
101
     * @return string
102
     */
103
    public function etag()
104
    {
105
        return md5(get_class($this) . json_encode($this->toArray()));
106
    }
107
108
    /**
109
     * Cache a value in the
110
     * model's cache collection.
111
     *
112
     * @param $key
113
     * @param $ttl
114
     * @param $value
115
     * @return mixed
116
     */
117
    public function cache($key, $ttl, $value)
118
    {
119
        (new CacheCollection())
120
            ->make([$key])
121
            ->setKey($this->getCacheCollectionKey())
122
            ->index();
123
124
        return app('cache')->remember(
125
            $key,
126
            $ttl ?: $this->getTtl(),
127
            $value
128
        );
129
    }
130
131
    /**
132
     * Fire a model event.
133
     *
134
     * @param $event
135
     * @return mixed
136
     */
137
    public function fireEvent($event)
138
    {
139
        return $this->fireModelEvent($event);
140
    }
141
142
    /**
143
     * Return the entry presenter.
144
     *
145
     * This is against standards but required
146
     * by the presentable interface.
147
     *
148
     * @return EloquentPresenter
149
     */
150 View Code Duplication
    public function getPresenter()
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...
151
    {
152
        $presenter = substr(get_class($this), 0, -5) . 'Presenter';
153
154
        if (class_exists($presenter)) {
155
            return app()->make($presenter, ['object' => $this]);
156
        }
157
158
        return new EloquentPresenter($this);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Anomaly\Stre...oquentPresenter($this); (Anomaly\Streams\Platform\Model\EloquentPresenter) is incompatible with the return type declared by the interface Robbo\Presenter\PresentableInterface::getPresenter of type Robbo\Presenter\Robbo\Presenter\Presenter.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
159
    }
160
161
    /**
162
     * Return a new collection class with our models.
163
     *
164
     * @param  array $items
165
     * @return Collection
166
     */
167 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...
168
    {
169
        $collection = substr(get_class($this), 0, -5) . 'Collection';
170
171
        if (class_exists($collection)) {
172
            return new $collection($items);
173
        }
174
175
        return new EloquentCollection($items);
176
    }
177
178
    /**
179
     * Return the translatable flag.
180
     *
181
     * @return bool
182
     */
183
    public function isTranslatable()
184
    {
185
        return isset($this->translationModel);
186
    }
187
188
    /**
189
     * Set the translatable flag.
190
     *
191
     * @param $translatable
192
     * @return $this
193
     */
194
    public function setTranslatable($translatable)
195
    {
196
        $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...
197
198
        return $this;
199
    }
200
201
    /**
202
     * Set the ttl.
203
     *
204
     * @param  $ttl
205
     * @return $this
206
     */
207
    public function setTtl($ttl)
208
    {
209
        $this->ttl = $ttl;
210
211
        return $this;
212
    }
213
214
    /**
215
     * Get the ttl.
216
     *
217
     * @return int|mixed
218
     */
219
    public function getTtl()
220
    {
221
        return $this->ttl;
222
    }
223
224
    /**
225
     * Get cache collection key.
226
     *
227
     * @return string
228
     */
229
    public function getCacheCollectionKey()
230
    {
231
        return get_called_class();
232
    }
233
234
    /**
235
     * Get the model title.
236
     *
237
     * @return mixed
238
     */
239
    public function getTitle()
240
    {
241
        return $this->{$this->getTitleName()};
242
    }
243
244
    /**
245
     * Get the title key.
246
     *
247
     * @return string
248
     */
249
    public function getTitleName()
250
    {
251
        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...
252
    }
253
254
    /**
255
     * Return if a row is deletable or not.
256
     *
257
     * @return bool
258
     */
259
    public function isDeletable()
260
    {
261
        return true;
262
    }
263
264
    /**
265
     * Return if the model is restorable or not.
266
     *
267
     * @return bool
268
     */
269
    public function isRestorable()
270
    {
271
        return true;
272
    }
273
274
    /**
275
     * Return whether the model is being
276
     * force deleted or not.
277
     *
278
     * @return bool
279
     */
280
    public function isForceDeleting()
281
    {
282
        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...
283
    }
284
285
    /**
286
     * Flush the model's cache.
287
     *
288
     * @return $this
289
     */
290
    public function flushCache()
291
    {
292
        (new CacheCollection())->setKey($key = $this->getCacheCollectionKey())->flush();
293
294
        EloquentQueryBuilder::dropRuntimeCache($key);
295
296
        return $this;
297
    }
298
299
    /**
300
     * Create a new Eloquent query builder for the model.
301
     *
302
     * @param  \Illuminate\Database\Query\Builder $query
303
     * @return \Illuminate\Database\Eloquent\Builder
304
     */
305 View Code Duplication
    public function newEloquentBuilder($query)
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...
306
    {
307
        $builder = substr(get_class($this), 0, -5) . 'QueryBuilder';
308
309
        if (class_exists($builder)) {
310
            return new $builder($query);
311
        }
312
313
        return new EloquentQueryBuilder($query);
314
    }
315
316
    /*
317
     * Alias for getTranslation()
318
     */
319
    public function translate($locale = null, $withFallback = false)
320
    {
321
        return $this->getTranslation($locale, $withFallback);
322
    }
323
324
    /*
325
     * Alias for getTranslation()
326
     */
327
    public function translateOrDefault($locale)
328
    {
329
        return $this->getTranslation($locale, true) ?: $this;
330
    }
331
332
    /*
333
     * Alias for getTranslationOrNew()
334
     */
335
    public function translateOrNew($locale)
336
    {
337
        return $this->getTranslationOrNew($locale);
338
    }
339
340
    /**
341
     * Get related translations.
342
     *
343
     * @return EloquentCollection
344
     */
345
    public function getTranslations()
346
    {
347
        foreach ($translations = $this->translations()->get() as $translation) {
348
            $translation->setRelation('parent', $this);
349
        }
350
351
        return $translations;
352
    }
353
354
    /**
355
     * @param  null      $locale
356
     * @param  bool|null $withFallback
357
     * @return Model|null
358
     */
359
    public function getTranslation($locale = null, $withFallback = true)
360
    {
361
362
        /**
363
         * If we have a desired locale and
364
         * it exists then just use that locale.
365
         */
366
        if ($locale && $translation = $this->getTranslationByLocaleKey($locale)) {
367
            return $translation;
368
        }
369
370
        /**
371
         * If we don't have a locale or it doesn't exist
372
         * then go ahead and try using a fallback in using
373
         * the system's designated DEFAULT (not active) locale.
374
         */
375
        if ($withFallback
376
            && $translation = $this->getTranslationByLocaleKey($this->getDefaultLocale())
377
        ) {
378
            return $translation;
379
        }
380
381
        /**
382
         * If we still don't have a translation then
383
         * try looking up the FALLBACK translation.
384
         */
385
        if ($withFallback
386
            && $this->getFallbackLocale()
387
            && $this->getTranslationByLocaleKey($this->getFallbackLocale())
388
            && $translation = $this->getTranslationByLocaleKey($this->getFallbackLocale())
389
        ) {
390
            return $translation;
391
        }
392
393
        return null;
394
    }
395
396
    public function hasTranslation($locale = null)
397
    {
398
        $locale = $locale ?: $this->getFallbackLocale();
399
400 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...
401
            $translation->setRelation('parent', $this);
402
403
            if ($translation->getAttribute($this->getLocaleKey()) == $locale) {
404
                return true;
405
            }
406
        }
407
408
        return false;
409
    }
410
411
    /**
412
     * Get the translation model.
413
     *
414
     * @return EloquentModel
415
     */
416
    public function getTranslationModel()
417
    {
418
        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...
419
    }
420
421
    /**
422
     * Get the translation model name.
423
     *
424
     * @return string
425
     */
426
    public function getTranslationModelName()
427
    {
428
        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...
429
    }
430
431
    /**
432
     * Get the translation table name.
433
     *
434
     * @return string
435
     */
436
    public function getTranslationTableName()
437
    {
438
        $model = $this->getTranslationModel();
439
440
        return $model->getTableName();
441
    }
442
443
    public function getTranslationModelNameDefault()
444
    {
445
        return get_class($this) . 'Translation';
446
    }
447
448
    /**
449
     * Return translated attributes.
450
     *
451
     * @return array
452
     */
453
    public function getTranslatedAttributes()
454
    {
455
        return $this->translatedAttributes;
456
    }
457
458
    public function getRelationKey()
459
    {
460
        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...
461
    }
462
463
    public function getLocaleKey()
464
    {
465
        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...
466
    }
467
468
    public function translations()
469
    {
470
        return $this->hasMany($this->getTranslationModelName(), $this->getRelationKey());
471
    }
472
473
    public function getAttribute($key)
474
    {
475
        if ($this->isTranslatedAttribute($key)) {
476
477
            if (($translation = $this->getTranslation()) === null) {
478
                return null;
479
            }
480
481
            $translation->setRelation('parent', $this);
482
483
            return $translation->$key;
484
        }
485
486
        return parent::getAttribute($key);
487
    }
488
489
    /**
490
     * Set an attribute.
491
     *
492
     * @param  string $key
493
     * @param  mixed  $value
494
     * @return $this
495
     */
496
    public function setAttribute($key, $value)
497
    {
498
        if (in_array($key, $this->translatedAttributes)) {
499
            $this->getTranslationOrNew(config('app.locale'))->$key = $value;
500
        } else {
501
            parent::setAttribute($key, $value);
502
        }
503
504
        return $this;
505
    }
506
507
    /**
508
     * Save the model.
509
     *
510
     * We have some customization here to
511
     * accommodate translations. First sa
512
     * then save translations is translatable.
513
     *
514
     * @param  array $options
515
     * @return bool
516
     */
517
    public function save(array $options = [])
518
    {
519
        if (!$this->getTranslationModelName()) {
520
            return $this->saveModel($options);
521
        }
522
523
        if ($this->exists) {
524
            if (count($this->getDirty()) > 0) {
525
526
                // 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...
527
                // an error has occurred. Therefore we shouldn't save the translations.
528
                if ($this->saveModel($options)) {
529
                    return $this->saveTranslations();
530
                }
531
532
                return false;
533
            } else {
534
535
                // 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...
536
                // false. So we have to save the translations
537
                return $this->saveTranslations();
538
            }
539
        } elseif ($this->saveModel($options)) {
540
541
            // We save the translations only if the instance is saved in the database.
542
            return $this->saveTranslations();
543
        }
544
545
        return false;
546
    }
547
548
    /**
549
     * Save the model to the database.
550
     *
551
     * This is a direct port from Eloquent
552
     * with the only exception being that if
553
     * the model is translatable it will NOT
554
     * fire the saved event. The saveTranslations
555
     * method will do that instead.
556
     *
557
     * @param  array $options
558
     * @return bool
559
     */
560
    public function saveModel(array $options = [])
561
    {
562
        $query = $this->newQueryWithoutScopes();
563
564
        // If the "saving" event returns false we'll bail out of the save and return
565
        // false, indicating that the save failed. This provides a chance for any
566
        // listeners to cancel save operations if validations fail or whatever.
567
        if ($this->fireModelEvent('saving') === false) {
568
            return false;
569
        }
570
571
        // If the model already exists in the database we can just update our record
572
        // that is already in this database using the current IDs in this "where"
573
        // clause to only update this model. Otherwise, we'll just insert them.
574
        if ($this->exists) {
575
            $saved = $this->performUpdate($query, $options);
0 ignored issues
show
Bug introduced by
It seems like $query defined by $this->newQueryWithoutScopes() on line 562 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...
Unused Code introduced by
The call to EloquentModel::performUpdate() has too many arguments starting with $options.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
576
        }
577
578
        // If the model is brand new, we'll insert it into our database and set the
579
        // ID attribute on the model to the value of the newly inserted row's ID
580
        // which is typically an auto-increment value managed by the database.
581
        else {
582
            $saved = $this->performInsert($query, $options);
0 ignored issues
show
Bug introduced by
It seems like $query defined by $this->newQueryWithoutScopes() on line 562 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...
Unused Code introduced by
The call to EloquentModel::performInsert() has too many arguments starting with $options.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
583
        }
584
585
        if ($saved && !$this->isTranslatable()) {
586
            $this->finishSave($options);
587
        }
588
589
        return $saved;
590
    }
591
592
    /**
593
     * Save translations to the database.
594
     *
595
     * @return bool
596
     */
597
    protected function saveTranslations()
598
    {
599
        $saved = true;
600
601
        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...
602
            $translation->setRelation('parent', $this);
603
604
            /* @var EloquentModel $translation */
605
            if ($saved && $this->isTranslationDirty($translation)) {
606
                $translation->setAttribute($this->getRelationKey(), $this->getKey());
607
608
                $saved = $translation->save();
609
            }
610
        }
611
612
        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...
613
            $translation = $this->translateOrNew(config('streams::locales.default'));
614
615
            $translation->save();
616
        }
617
618
        $this->finishSave([]);
619
620
        return $saved;
621
    }
622
623
    protected function getTranslationOrNew($locale)
624
    {
625
        if (($translation = $this->getTranslation($locale, false)) === null) {
626
            $translation = $this->getNewTranslation($locale);
627
        }
628
629
        return $translation;
630
    }
631
632
    public function fill(array $attributes)
633
    {
634
        foreach ($attributes as $key => $values) {
635
            if (is_array($values) && $this->isKeyALocale($key)) {
636
                foreach ($values as $translationAttribute => $translationValue) {
637
                    if ($this->alwaysFillable() || $this->isFillable($translationAttribute)) {
638
                        $this->getTranslationOrNew($key)->$translationAttribute = $translationValue;
639
                    }
640
                }
641
                unset($attributes[$key]);
642
            }
643
        }
644
645
        return parent::fill($attributes);
646
    }
647
648
    private function getTranslationByLocaleKey($key)
649
    {
650 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...
651
            $translation->setRelation('parent', $this);
652
653
            if ($translation->getAttribute($this->getLocaleKey()) == $key) {
654
                return $translation;
655
            }
656
        }
657
658
        return null;
659
    }
660
661
    public function isTranslatedAttribute($key)
662
    {
663
        return in_array($key, $this->translatedAttributes);
664
    }
665
666
    protected function isTranslationAttribute($key)
667
    {
668
        return in_array($key, $this->translatedAttributes);
669
    }
670
671
    protected function isKeyALocale($key)
672
    {
673
        return config('streams::locales.supported.' . $key) !== null;
674
    }
675
676
    protected function isTranslationDirty(Model $translation)
677
    {
678
        $dirtyAttributes = $translation->getDirty();
679
        unset($dirtyAttributes[$this->getLocaleKey()]);
680
681
        return count($dirtyAttributes) > 0;
682
    }
683
684
    public function getNewTranslation($locale)
685
    {
686
        $modelName = $this->getTranslationModelName();
687
688
        /* @var EloquentModel $translation */
689
        $translation = new $modelName;
690
691
        $translation->setRelation('parent', $this);
692
693
        $translation->setAttribute($this->getLocaleKey(), $locale);
694
        $translation->setAttribute($this->getRelationKey(), $this->getKey());
695
696
        $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...
697
698
        return $translation;
699
    }
700
701
    public function scopeTranslatedIn(Builder $query, $locale)
702
    {
703
        return $query->whereHas(
704
            'translations',
705
            function (Builder $q) use ($locale) {
706
                $q->where($this->getLocaleKey(), '=', $locale);
707
            }
708
        );
709
    }
710
711
    public function scopeTranslated(Builder $query)
712
    {
713
        return $query->has('translations');
714
    }
715
716
    /**
717
     * Return unguarded attributes.
718
     *
719
     * @return array
720
     */
721
    public function getUnguardedAttributes()
722
    {
723
        foreach ($attributes = $this->getAttributes() as $attribute => $value) {
724
            $attributes[$attribute] = $value;
725
        }
726
727
        return array_diff_key($attributes, array_flip($this->getGuarded()));
728
    }
729
730
    /**
731
     * Get the default locale.
732
     *
733
     * @return string
734
     */
735
    protected function getDefaultLocale()
736
    {
737
        if (isset($this->cache['default_locale'])) {
738
            return $this->cache['default_locale'];
739
        }
740
741
        return $this->cache['default_locale'] = config('streams::locales.default');
742
    }
743
744
    /**
745
     * Get the fallback locale.
746
     *
747
     * @return string
748
     */
749
    protected function getFallbackLocale()
750
    {
751
        if (isset($this->cache['fallback_locale'])) {
752
            return $this->cache['fallback_locale'];
753
        }
754
755
        return $this->cache['fallback_locale'] = config('app.fallback_locale');
756
    }
757
758
    /**
759
     * This is to keep consistency with the
760
     * entry interface above us.
761
     *
762
     * @return string
763
     */
764
    public function getTableName()
765
    {
766
        return $this->getTable();
767
    }
768
769
    /**
770
     * Return if the entry is trashed or not.
771
     *
772
     * @return bool
773
     */
774
    public function trashed()
775
    {
776
        return parent::trashed();
777
    }
778
779
    public function toArray()
780
    {
781
        $attributes = $this->attributesToArray();
782
783
        foreach ($this->translatedAttributes as $field) {
784
            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...
785
                $attributes[$field] = $translation->$field;
786
            }
787
        }
788
789
        return $attributes;
790
    }
791
792
    /**
793
     * Return the routable array information.
794
     *
795
     * @return array
796
     */
797
    public function toRoutableArray()
798
    {
799
        return $this->toArray();
800
    }
801
802
    private function alwaysFillable()
803
    {
804
        return false;
805
    }
806
807
    /**
808
     * Determine if the given attribute exists.
809
     * Make sure to skip where there could be an
810
     * issue with relational "looking" properties.
811
     *
812
     * @param  mixed $offset
813
     * @return bool
814
     */
815
    public function offsetExists($offset)
816
    {
817
        return !method_exists($this, $offset) && isset($this->$offset);
818
    }
819
820
    /**
821
     * Get the criteria class.
822
     *
823
     * @return string
824
     */
825
    public function getCriteriaName()
826
    {
827
        $criteria = substr(get_class($this), 0, -5) . 'Criteria';
828
829
        return class_exists($criteria) ? $criteria : EloquentCriteria::class;
830
    }
831
832
    /**
833
     * Get the cascading actions.
834
     *
835
     * @return array
836
     */
837
    public function getCascades()
838
    {
839
        return $this->cascades;
840
    }
841
842
    public function __get($key)
843
    {
844
        if ($this->hasHook($hook = 'get_' . $key)) {
845
            return $this->call($hook, []);
846
        }
847
848
        return parent::__get($key);
849
    }
850
851
    public function __call($method, $parameters)
852
    {
853
        if ($this->hasHook($hook = snake_case($method))) {
854
            return $this->call($hook, $parameters);
855
        }
856
857
        return parent::__call($method, $parameters);
858
    }
859
860
    /**
861
     * Check if an attribute exists.
862
     *
863
     * @param  string $key
864
     * @return bool
865
     */
866
    public function __isset($key)
867
    {
868
        return (in_array($key, $this->translatedAttributes) || parent::__isset($key));
869
    }
870
871
    /**
872
     * Return the string form of the model.
873
     *
874
     * @return string
875
     */
876
    public function __toString()
877
    {
878
        return json_encode($this->toArray());
879
    }
880
881
    /**
882
     * Remove volatile cache from
883
     * objects before serialization.
884
     *
885
     * @return array
886
     */
887
    public function __sleep()
888
    {
889
        return array_diff(array_keys(get_object_vars($this)), ['cache']);
890
    }
891
}
892