EntryModel   F
last analyzed

Complexity

Total Complexity 93

Size/Duplication

Total Lines 881
Duplicated Lines 5.45 %

Coupling/Cohesion

Components 1
Dependencies 11

Importance

Changes 0
Metric Value
dl 48
loc 881
rs 3.9999
c 0
b 0
f 0
wmc 93
lcom 1
cbo 11

57 Methods

Rating   Name   Duplication   Size   Complexity  
B boot() 0 23 6
A scopeSorted() 0 4 1
A getId() 0 4 1
A getEntryId() 0 4 1
A getEntryTitle() 0 4 1
A getBoundModelName() 0 4 1
A getBoundModelNamespace() 0 8 1
A getSortOrder() 0 4 1
A getTitle() 0 4 1
C getFieldValue() 0 38 7
B setFieldValue() 0 27 3
A getField() 0 10 2
A hasField() 0 4 1
B getFieldType() 27 27 3
A getFieldTypeQuery() 0 8 2
A getFieldTypePresenter() 0 8 2
A setAttribute() 0 10 4
A getAttribute() 0 16 4
A getRawAttribute() 0 8 2
A setRawAttribute() 0 6 1
A getStream() 0 4 1
A getStreamNamespace() 0 6 1
A getStreamSlug() 0 6 1
A getStreamName() 0 6 1
A getStreamPrefix() 0 6 1
A getTableName() 0 6 1
A getTranslationsTableName() 0 6 1
A getAssignments() 0 6 1
A getAssignmentFieldSlugs() 0 6 1
A getAssignmentsByFieldType() 0 6 1
A getAssignment() 0 6 1
A getTranslatableAssignments() 0 7 1
A getRelationshipAssignments() 0 7 1
A isTranslatable() 0 6 1
A isTrashable() 0 6 1
A lastModified() 0 4 2
A getCreatedBy() 0 4 1
A createdBy() 0 4 1
A getUpdatedBy() 0 4 1
A updatedBy() 0 4 1
A titleColumnIsTranslatable() 0 4 1
A assignmentIsTranslatable() 0 4 1
A assignmentIsRelationship() 0 6 1
A fireFieldTypeEvents() 0 19 2
A stream() 0 8 2
A newCollection() 10 10 2
A getPresenter() 10 10 2
A newPresenter() 0 4 1
A route() 0 6 1
A newRouter() 0 4 1
A getRouter() 0 8 2
A getRouterName() 0 6 2
A newEloquentBuilder() 0 4 1
A getCriteriaName() 0 6 2
A isSearchable() 0 4 1
A toSearchableArray() 0 13 3
A __get() 0 8 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like EntryModel often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EntryModel, and based on these observations, apply Extract Interface, too.

1
<?php namespace Anomaly\Streams\Platform\Entry;
2
3
use Anomaly\Streams\Platform\Addon\FieldType\FieldType;
4
use Anomaly\Streams\Platform\Addon\FieldType\FieldTypePresenter;
5
use Anomaly\Streams\Platform\Addon\FieldType\FieldTypeQuery;
6
use Anomaly\Streams\Platform\Assignment\AssignmentCollection;
7
use Anomaly\Streams\Platform\Assignment\Contract\AssignmentInterface;
8
use Anomaly\Streams\Platform\Entry\Contract\EntryInterface;
9
use Anomaly\Streams\Platform\Field\Contract\FieldInterface;
10
use Anomaly\Streams\Platform\Model\EloquentModel;
11
use Anomaly\Streams\Platform\Stream\Contract\StreamInterface;
12
use Carbon\Carbon;
13
use Illuminate\Contracts\Auth\Authenticatable;
14
use Illuminate\Database\Eloquent\Builder;
15
use Laravel\Scout\ModelObserver;
16
use Laravel\Scout\Searchable;
17
use Robbo\Presenter\PresentableInterface;
18
19
/**
20
 * Class EntryModel
21
 *
22
 * @link   http://pyrocms.com/
23
 * @author PyroCMS, Inc. <[email protected]>
24
 * @author Ryan Thompson <[email protected]>
25
 */
26
class EntryModel extends EloquentModel implements EntryInterface, PresentableInterface
27
{
28
29
    use Searchable;
30
31
    /**
32
     * The foreign key for translations.
33
     *
34
     * @var string
35
     */
36
    protected $translationForeignKey = 'entry_id';
37
38
    /**
39
     * By default nothing is searchable.
40
     *
41
     * @var boolean
42
     */
43
    protected $searchable = false;
44
45
    /**
46
     * The validation rules. These are
47
     * overridden on the compiled models.
48
     *
49
     * @var array
50
     */
51
    protected $rules = [];
52
53
    /**
54
     * The field slugs. These are
55
     * overridden on compiled models.
56
     *
57
     * @var array
58
     */
59
    protected $fields = [];
60
61
    /**
62
     * The entry relationships by field slug.
63
     *
64
     * @var array
65
     */
66
    protected $relationships = [];
67
68
    /**
69
     * The compiled stream data.
70
     *
71
     * @var array|StreamInterface
72
     */
73
    protected $stream = [];
74
75
    /**
76
     * Boot the model
77
     */
78
    protected static function boot()
79
    {
80
        $instance = new static;
81
82
        $class     = get_class($instance);
83
        $events    = $instance->getObservableEvents();
84
        $observer  = substr($class, 0, -5) . 'Observer';
85
        $observing = class_exists($observer);
86
87
        if ($events && $observing) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $events of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
88
            self::observe(app($observer));
89
        }
90
91
        if (!$instance->isSearchable()) {
92
            ModelObserver::disableSyncingFor(get_class(new static));
93
        }
94
95
        if ($events && !$observing) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $events of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
96
            self::observe(EntryObserver::class);
97
        }
98
99
        parent::boot();
100
    }
101
102
    /**
103
     * Sort the query.
104
     *
105
     * @param Builder $builder
106
     * @param string  $direction
107
     */
108
    public function scopeSorted(Builder $builder, $direction = 'asc')
109
    {
110
        $builder->orderBy('sort_order', $direction);
111
    }
112
113
    /**
114
     * Get the ID.
115
     *
116
     * @return mixed
117
     */
118
    public function getId()
119
    {
120
        return $this->getKey();
121
    }
122
123
    /**
124
     * Get the entry ID.
125
     *
126
     * @return mixed
127
     */
128
    public function getEntryId()
129
    {
130
        return $this->getId();
131
    }
132
133
    /**
134
     * Get the entry title.
135
     *
136
     * @return mixed
137
     */
138
    public function getEntryTitle()
139
    {
140
        return $this->getTitle();
141
    }
142
143
    /**
144
     * Get the model's bound name.
145
     *
146
     * @return string
147
     */
148
    public function getBoundModelName()
149
    {
150
        return get_class(app(get_class($this)));
151
    }
152
153
    /**
154
     * Get the model's bound namespace.
155
     *
156
     * @return string
157
     */
158
    public function getBoundModelNamespace()
159
    {
160
        $namespace = explode('\\', $this->getBoundModelName());
161
162
        array_pop($namespace);
163
164
        return implode('\\', $namespace);
165
    }
166
167
    /**
168
     * Get the sort order.
169
     *
170
     * @return int
171
     */
172
    public function getSortOrder()
173
    {
174
        return $this->sort_order;
0 ignored issues
show
Documentation introduced by
The property sort_order does not exist on object<Anomaly\Streams\Platform\Entry\EntryModel>. 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...
175
    }
176
177
    /**
178
     * Get the entries title.
179
     *
180
     * @return mixed
181
     */
182
    public function getTitle()
183
    {
184
        return $this->{$this->getTitleName()};
185
    }
186
187
    /**
188
     * Get a field value.
189
     *
190
     * @param        $fieldSlug
191
     * @param  null  $locale
192
     * @return mixed
193
     */
194
    public function getFieldValue($fieldSlug, $locale = null)
195
    {
196
        if (!$locale) {
197
            $locale = config('app.locale');
198
        }
199
200
        $assignment = $this->getAssignment($fieldSlug);
201
202
        $type = $assignment->getFieldType();
203
204
        $accessor = $type->getAccessor();
205
        $modifier = $type->getModifier();
206
207
        if ($assignment->isTranslatable()) {
208
            $entry = $this->translateOrDefault($locale);
209
210
            $type->setLocale($locale);
211
        } else {
212
            $entry = $this;
213
        }
214
215
        $type->setEntry($entry);
216
217
        $value = $modifier->restore($accessor->get());
218
219
        if (
220
            $value === null &&
221
            $assignment->isTranslatable() &&
222
            $assignment->isRequired() &&
223
            $translation = $this->translate()
224
        ) {
225
            $type->setEntry($translation);
226
227
            $value = $modifier->restore($accessor->get());
228
        }
229
230
        return $value;
231
    }
232
233
    /**
234
     * Set a field value.
235
     *
236
     * @param        $fieldSlug
237
     * @param        $value
238
     * @param  null  $locale
239
     * @return $this
240
     */
241
    public function setFieldValue($fieldSlug, $value, $locale = null)
242
    {
243
        if (!$locale) {
244
            $locale = config('app.locale');
245
        }
246
247
        $assignment = $this->getAssignment($fieldSlug);
248
249
        $type = $assignment->getFieldType($this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Anomaly\Streams\Platform\Entry\EntryModel>, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
250
251
        if ($assignment->isTranslatable()) {
252
            $entry = $this->translateOrNew($locale);
253
254
            $type->setLocale($locale);
255
        } else {
256
            $entry = $this;
257
        }
258
259
        $type->setEntry($entry);
260
261
        $accessor = $type->getAccessor();
262
        $modifier = $type->getModifier();
263
264
        $accessor->set($modifier->modify($value));
265
266
        return $this;
267
    }
268
269
    /**
270
     * Get an entry field.
271
     *
272
     * @param  $slug
273
     * @return FieldInterface|null
274
     */
275
    public function getField($slug)
276
    {
277
        $assignment = $this->getAssignment($slug);
278
279
        if (!$assignment instanceof AssignmentInterface) {
280
            return null;
281
        }
282
283
        return $assignment->getField();
284
    }
285
286
    /**
287
     * Return whether an entry has
288
     * a field with a given slug.
289
     *
290
     * @param  $slug
291
     * @return bool
292
     */
293
    public function hasField($slug)
294
    {
295
        return ($this->getField($slug) !== null);
296
    }
297
298
    /**
299
     * Get the field type from a field slug.
300
     *
301
     * @param  $fieldSlug
302
     * @return null|FieldType
303
     */
304 View Code Duplication
    public function getFieldType($fieldSlug)
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...
305
    {
306
        $locale = config('app.locale');
307
308
        $assignment = $this->getAssignment($fieldSlug);
309
310
        if (!$assignment) {
311
            return null;
312
        }
313
314
        $type = $assignment->getFieldType();
315
316
        if ($assignment->isTranslatable()) {
317
            $entry = $this->translateOrDefault($locale);
318
319
            $type->setLocale($locale);
320
        } else {
321
            $entry = $this;
322
        }
323
324
        $type->setEntry($entry);
325
326
        $type->setValue($this->getFieldValue($fieldSlug));
327
        $type->setEntry($this);
328
329
        return $type;
330
    }
331
332
    /**
333
     * Get the field type query.
334
     *
335
     * @param $fieldSlug
336
     * @return FieldTypeQuery
337
     */
338
    public function getFieldTypeQuery($fieldSlug)
339
    {
340
        if (!$type = $this->getFieldType($fieldSlug)) {
341
            return null;
342
        }
343
344
        return $type->getQuery();
345
    }
346
347
    /**
348
     * Get the field type presenter.
349
     *
350
     * @param $fieldSlug
351
     * @return FieldTypePresenter
352
     */
353
    public function getFieldTypePresenter($fieldSlug)
354
    {
355
        if (!$type = $this->getFieldType($fieldSlug)) {
356
            return null;
357
        }
358
359
        return $type->getPresenter();
360
    }
361
362
    /**
363
     * Set a given attribute on the model.
364
     * Override the behavior here to give
365
     * the field types a chance to modify things.
366
     *
367
     * @param  string $key
368
     * @param  mixed  $value
369
     * @return $this
370
     */
371
    public function setAttribute($key, $value)
372
    {
373
        if (!$this->isKeyALocale($key) && !$this->hasSetMutator($key) && $this->getFieldType($key)) {
374
            $this->setFieldValue($key, $value);
375
        } else {
376
            parent::setAttribute($key, $value);
377
        }
378
379
        return $this;
380
    }
381
382
    /**
383
     * Get a given attribute on the model.
384
     * Override the behavior here to give
385
     * the field types a chance to modify things.
386
     *
387
     * @param  string $key
388
     * @return mixed
389
     */
390
    public function getAttribute($key)
391
    {
392
        // Check if it's a relationship first.
393
        if (in_array($key, array_merge($this->relationships, ['created_by', 'updated_by']))) {
394
            return parent::getAttribute(camel_case($key));
395
        }
396
397
        if (
398
            !$this->hasGetMutator($key)
399
            && in_array($key, $this->fields)
400
        ) {
401
            return $this->getFieldValue($key);
402
        } else {
403
            return parent::getAttribute($key);
404
        }
405
    }
406
407
    /**
408
     * Get a raw unmodified attribute.
409
     *
410
     * @param             $key
411
     * @param  bool       $process
412
     * @return mixed|null
413
     */
414
    public function getRawAttribute($key, $process = true)
415
    {
416
        if (!$process) {
417
            return $this->getAttributeFromArray($key);
418
        }
419
420
        return parent::getAttribute($key);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getAttribute() instead of getRawAttribute()). Are you sure this is correct? If so, you might want to change this to $this->getAttribute().

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

Consider the following code:

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

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

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

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

Loading history...
421
    }
422
423
    /**
424
     * Set a raw unmodified attribute.
425
     *
426
     * @param $key
427
     * @param $value
428
     * @return $this
429
     */
430
    public function setRawAttribute($key, $value)
431
    {
432
        parent::setAttribute($key, $value);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (setAttribute() instead of setRawAttribute()). Are you sure this is correct? If so, you might want to change this to $this->setAttribute().

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

Consider the following code:

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

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

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

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

Loading history...
433
434
        return $this;
435
    }
436
437
    /**
438
     * Get the stream.
439
     *
440
     * @return StreamInterface
441
     */
442
    public function getStream()
443
    {
444
        return $this->stream();
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->stream(); of type Anomaly\Streams\Platform...t\StreamInterface|array adds the type array to the return on line 444 which is incompatible with the return type declared by the interface Anomaly\Streams\Platform...tryInterface::getStream of type Anomaly\Streams\Platform...ontract\StreamInterface.
Loading history...
445
    }
446
447
    /**
448
     * Get the stream namespace.
449
     *
450
     * @return string
451
     */
452
    public function getStreamNamespace()
453
    {
454
        $stream = $this->getStream();
455
456
        return $stream->getNamespace();
457
    }
458
459
    /**
460
     * Get the stream slug.
461
     *
462
     * @return string
463
     */
464
    public function getStreamSlug()
465
    {
466
        $stream = $this->getStream();
467
468
        return $stream->getSlug();
469
    }
470
471
    /**
472
     * Get the entry's stream name.
473
     *
474
     * @return string
475
     */
476
    public function getStreamName()
477
    {
478
        $stream = $this->getStream();
479
480
        return $stream->getName();
481
    }
482
483
    /**
484
     * Get the stream prefix.
485
     *
486
     * @return string
487
     */
488
    public function getStreamPrefix()
489
    {
490
        $stream = $this->getStream();
491
492
        return $stream->getPrefix();
493
    }
494
495
    /**
496
     * Get the table name.
497
     *
498
     * @return string
499
     */
500
    public function getTableName()
501
    {
502
        $stream = $this->getStream();
503
504
        return $stream->getEntryTableName();
505
    }
506
507
    /**
508
     * Get the translations table name.
509
     *
510
     * @return string
511
     */
512
    public function getTranslationsTableName()
513
    {
514
        $stream = $this->getStream();
515
516
        return $stream->getEntryTranslationsTableName();
517
    }
518
519
    /**
520
     * Get all assignments.
521
     *
522
     * @return AssignmentCollection
523
     */
524
    public function getAssignments()
525
    {
526
        $stream = $this->getStream();
527
528
        return $stream->getAssignments();
529
    }
530
531
    /**
532
     * Get the field slugs for assigned fields.
533
     *
534
     * @param  null $prefix
535
     * @return array
536
     */
537
    public function getAssignmentFieldSlugs($prefix = null)
538
    {
539
        $assignments = $this->getAssignments();
540
541
        return $assignments->fieldSlugs($prefix);
542
    }
543
544
    /**
545
     * Get all assignments of the
546
     * provided field type namespace.
547
     *
548
     * @param $fieldType
549
     * @return AssignmentCollection
550
     */
551
    public function getAssignmentsByFieldType($fieldType)
552
    {
553
        $assignments = $this->getAssignments();
554
555
        return $assignments->findAllByFieldType($fieldType);
556
    }
557
558
    /**
559
     * Get an assignment by field slug.
560
     *
561
     * @param  $fieldSlug
562
     * @return AssignmentInterface
563
     */
564
    public function getAssignment($fieldSlug)
565
    {
566
        $assignments = $this->getAssignments();
567
568
        return $assignments->findByFieldSlug($fieldSlug);
569
    }
570
571
    /**
572
     * Return translated assignments.
573
     *
574
     * @return AssignmentCollection
575
     */
576
    public function getTranslatableAssignments()
577
    {
578
        $stream      = $this->getStream();
579
        $assignments = $stream->getAssignments();
580
581
        return $assignments->translatable();
582
    }
583
584
    /**
585
     * Return relation assignments.
586
     *
587
     * @return AssignmentCollection
588
     */
589
    public function getRelationshipAssignments()
590
    {
591
        $stream      = $this->getStream();
592
        $assignments = $stream->getAssignments();
593
594
        return $assignments->relations();
595
    }
596
597
    /**
598
     * Get the translatable flag.
599
     *
600
     * @return bool
601
     */
602
    public function isTranslatable()
603
    {
604
        $stream = $this->getStream();
605
606
        return $stream->isTranslatable();
607
    }
608
609
    /**
610
     * Return whether the entry is trashable or not.
611
     *
612
     * @return bool
613
     */
614
    public function isTrashable()
615
    {
616
        $stream = $this->getStream();
617
618
        return $stream->isTrashable();
619
    }
620
621
    /**
622
     * Return the last modified datetime.
623
     *
624
     * @return Carbon
625
     */
626
    public function lastModified()
627
    {
628
        return $this->updated_at ?: $this->created_at;
0 ignored issues
show
Documentation introduced by
The property updated_at does not exist on object<Anomaly\Streams\Platform\Entry\EntryModel>. 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...
Documentation introduced by
The property created_at does not exist on object<Anomaly\Streams\Platform\Entry\EntryModel>. 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...
629
    }
630
631
    /**
632
     * Return the related creator.
633
     *
634
     * @return Authenticatable
635
     */
636
    public function getCreatedBy()
637
    {
638
        return $this->created_by;
0 ignored issues
show
Documentation introduced by
The property created_by does not exist on object<Anomaly\Streams\Platform\Entry\EntryModel>. 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...
639
    }
640
641
    /**
642
     * Return the creator relation.
643
     *
644
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
645
     */
646
    public function createdBy()
647
    {
648
        return $this->belongsTo(config('auth.providers.users.model'));
649
    }
650
651
    /**
652
     * Return the related updater.
653
     *
654
     * @return Authenticatable
655
     */
656
    public function getUpdatedBy()
657
    {
658
        return $this->updated_by;
0 ignored issues
show
Documentation introduced by
The property updated_by does not exist on object<Anomaly\Streams\Platform\Entry\EntryModel>. 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...
659
    }
660
661
    /**
662
     * Return the updater relation.
663
     *
664
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
665
     */
666
    public function updatedBy()
667
    {
668
        return $this->belongsTo(config('auth.providers.users.model'));
669
    }
670
671
    /**
672
     * Return whether the title column is
673
     * translatable or not.
674
     *
675
     * @return bool
676
     */
677
    public function titleColumnIsTranslatable()
678
    {
679
        return $this->assignmentIsTranslatable($this->getTitleName());
680
    }
681
682
    /**
683
     * Return whether or not the assignment for
684
     * the given field slug is translatable.
685
     *
686
     * @param $fieldSlug
687
     * @return bool
688
     */
689
    public function assignmentIsTranslatable($fieldSlug)
690
    {
691
        return $this->isTranslatedAttribute($fieldSlug);
692
    }
693
694
    /**
695
     * Return whether or not the assignment for
696
     * the given field slug is a relationship.
697
     *
698
     * @param $fieldSlug
699
     * @return bool
700
     */
701
    public function assignmentIsRelationship($fieldSlug)
702
    {
703
        $relationships = $this->getRelationshipAssignments();
704
705
        return in_array($fieldSlug, $relationships->fieldSlugs());
706
    }
707
708
    /**
709
     * Fire field type events.
710
     *
711
     * @param       $trigger
712
     * @param array $payload
713
     */
714
    public function fireFieldTypeEvents($trigger, $payload = [])
715
    {
716
        $assignments = $this->getAssignments();
717
718
        /* @var AssignmentInterface $assignment */
719
        foreach ($assignments->notTranslatable() as $assignment) {
720
721
            $fieldType = $assignment->getFieldType();
722
723
            $fieldType->setValue($this->getRawAttribute($assignment->getFieldSlug()));
724
725
            $fieldType->setEntry($this);
726
727
            $payload['entry']     = $this;
728
            $payload['fieldType'] = $fieldType;
729
730
            $fieldType->fire($trigger, $payload);
731
        }
732
    }
733
734
    /**
735
     * Return the related stream.
736
     *
737
     * @return StreamInterface|array
738
     */
739
    public function stream()
740
    {
741
        if (!$this->stream instanceof StreamInterface) {
742
            $this->stream = app('Anomaly\Streams\Platform\Stream\StreamModel')->make($this->stream);
743
        }
744
745
        return $this->stream;
746
    }
747
748
    /**
749
     * @param  array $items
750
     * @return EntryCollection
751
     */
752 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...
753
    {
754
        $collection = substr(get_class($this), 0, -5) . 'Collection';
755
756
        if (class_exists($collection)) {
757
            return new $collection($items);
758
        }
759
760
        return new EntryCollection($items);
761
    }
762
763
    /**
764
     * Return the entry presenter.
765
     *
766
     * This is against standards but required
767
     * by the presentable interface.
768
     *
769
     * @return EntryPresenter
770
     */
771 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...
772
    {
773
        $presenter = substr(get_class($this), 0, -5) . 'Presenter';
774
775
        if (class_exists($presenter)) {
776
            return app()->make($presenter, ['object' => $this]);
777
        }
778
779
        return new EntryPresenter($this);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Anomaly\Stre...\EntryPresenter($this); (Anomaly\Streams\Platform\Entry\EntryPresenter) 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...
780
    }
781
782
    /**
783
     * Return a new presenter instance.
784
     *
785
     * @return EntryPresenter
786
     */
787
    public function newPresenter()
788
    {
789
        return $this->getPresenter();
790
    }
791
792
    /**
793
     * Return a model route.
794
     *
795
     * @return string
796
     */
797
    public function route($route, array $parameters = [])
798
    {
799
        $router = $this->getRouter();
800
801
        return $router->make($route, $parameters);
802
    }
803
804
    /**
805
     * Return a new router instance.
806
     *
807
     * @return EntryRouter
808
     */
809
    public function newRouter()
810
    {
811
        return app()->make($this->getRouterName(), ['entry' => $this]);
812
    }
813
814
    /**
815
     * Get the router.
816
     *
817
     * @return EntryRouter
818
     */
819
    public function getRouter()
820
    {
821
        if (isset($this->cache['router'])) {
822
            return $this->cache['router'];
823
        }
824
825
        return $this->cache['router'] = $this->newRouter();
826
    }
827
828
    /**
829
     * Get the router name.
830
     *
831
     * @return string
832
     */
833
    public function getRouterName()
834
    {
835
        $router = substr(get_class($this), 0, -5) . 'Router';
836
837
        return class_exists($router) ? $router : EntryRouter::class;
838
    }
839
840
    /**
841
     * Create a new Eloquent query builder for the model.
842
     *
843
     * @param  \Illuminate\Database\Query\Builder $query
844
     * @return \Illuminate\Database\Eloquent\Builder|static
845
     */
846
    public function newEloquentBuilder($query)
847
    {
848
        return new EntryQueryBuilder($query);
849
    }
850
851
    /**
852
     * Get the criteria class.
853
     *
854
     * @return string
855
     */
856
    public function getCriteriaName()
857
    {
858
        $criteria = substr(get_class($this), 0, -5) . 'Criteria';
859
860
        return class_exists($criteria) ? $criteria : EntryCriteria::class;
861
    }
862
863
    /**
864
     * Return whether the model is searchable or not.
865
     *
866
     * @return boolean
867
     */
868
    public function isSearchable()
869
    {
870
        return $this->searchable;
871
    }
872
873
    /**
874
     * Return a searchable array.
875
     *
876
     * @return array
877
     */
878
    public function toSearchableArray()
879
    {
880
        $array = $this->toArray();
881
882
        foreach ($array as $key => &$value) {
883
            if (is_array($value)) {
884
                $value = json_encode($value);
885
                continue;
886
            }
887
        }
888
889
        return $array;
890
    }
891
892
    /**
893
     * Override the __get method.
894
     *
895
     * @param  string $key
896
     * @return EntryPresenter|mixed
897
     */
898
    public function __get($key)
899
    {
900
        if ($key === 'decorated') {
901
            return $this->getPresenter();
902
        }
903
904
        return parent::__get($key); // TODO: Change the autogenerated stub
905
    }
906
}
907