Completed
Pull Request — master (#211)
by Ryan
07:26
created

EntryModel   F

Complexity

Total Complexity 72

Size/Duplication

Total Lines 707
Duplicated Lines 8.35 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 1
Bugs 1 Features 0
Metric Value
wmc 72
c 1
b 1
f 0
lcom 1
cbo 9
dl 59
loc 707
rs 3.5918

44 Methods

Rating   Name   Duplication   Size   Complexity  
B boot() 0 18 5
A scopeSorted() 0 4 1
A getId() 0 4 1
A getEntryId() 0 4 1
A getEntryTitle() 0 4 1
A getSortOrder() 0 4 1
A getTitle() 0 4 1
C getFieldValue() 0 40 7
A setFieldValue() 0 13 1
A getField() 0 10 2
A hasField() 0 4 1
B getFieldType() 28 28 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 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 getPresenter() 10 10 2
A newPresenter() 0 4 1
A newQuery() 11 11 1
A __get() 0 8 2
A newCollection() 10 10 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\Database\Eloquent\Builder;
14
use Robbo\Presenter\PresentableInterface;
15
16
/**
17
 * Class EntryModel
18
 *
19
 * @method        Builder sorted()
20
 * @link    http://anomaly.is/streams-platform
21
 * @author  AnomalyLabs, Inc. <[email protected]>
22
 * @author  Ryan Thompson <[email protected]>
23
 * @package Anomaly\Streams\Platform\Entry
24
 */
25
class EntryModel extends EloquentModel implements EntryInterface, PresentableInterface
26
{
27
28
    /**
29
     * The foreign key for translations.
30
     *
31
     * @var string
32
     */
33
    protected $translationForeignKey = 'entry_id';
34
35
    /**
36
     * The validation rules. These are
37
     * overridden on the compiled models.
38
     *
39
     * @var array
40
     */
41
    protected $rules = [];
42
43
    /**
44
     * The field slugs. These are
45
     * overridden on compiled models.
46
     *
47
     * @var array
48
     */
49
    protected $fields = [];
50
51
    /**
52
     * The entry relationships by field slug.
53
     *
54
     * @var array
55
     */
56
    protected $relationships = [];
57
58
    /**
59
     * The compiled stream data.
60
     *
61
     * @var array|StreamInterface
62
     */
63
    protected $stream = [];
64
65
    /**
66
     * Boot the model
67
     */
68
    protected static function boot()
69
    {
70
        $instance = new static;
71
72
        $class    = get_class($instance);
73
        $events   = $instance->getObservableEvents();
74
        $observer = substr($class, 0, -5) . 'Observer';
75
76
        if ($events && class_exists($observer)) {
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...
77
            self::observe(app($observer));
78
        }
79
80
        if ($events && !static::$dispatcher->hasListeners('eloquent.' . array_shift($events) . ': ' . $class)) {
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...
81
            self::observe(EntryObserver::class);
82
        }
83
84
        parent::boot();
85
    }
86
87
    /**
88
     * Sort the query.
89
     *
90
     * @param Builder $builder
91
     * @param string  $direction
92
     */
93
    public function scopeSorted(Builder $builder, $direction = 'asc')
94
    {
95
        $builder->orderBy('sort_order', $direction);
96
    }
97
98
    /**
99
     * Get the ID.
100
     *
101
     * @return mixed
102
     */
103
    public function getId()
104
    {
105
        return $this->getKey();
106
    }
107
108
    /**
109
     * Get the entry ID.
110
     *
111
     * @return mixed
112
     */
113
    public function getEntryId()
114
    {
115
        return $this->getId();
116
    }
117
118
    /**
119
     * Get the entry title.
120
     *
121
     * @return mixed
122
     */
123
    public function getEntryTitle()
124
    {
125
        return $this->getTitle();
126
    }
127
128
    /**
129
     * Get the sort order.
130
     *
131
     * @return int
132
     */
133
    public function getSortOrder()
134
    {
135
        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...
136
    }
137
138
    /**
139
     * Get the entries title.
140
     *
141
     * @return mixed
142
     */
143
    public function getTitle()
144
    {
145
        return $this->{$this->getTitleName()};
146
    }
147
148
    /**
149
     * Get a field value.
150
     *
151
     * @param      $fieldSlug
152
     * @param null $locale
153
     * @return mixed
154
     */
155
    public function getFieldValue($fieldSlug, $locale = null)
156
    {
157
        if (!$locale) {
158
            $locale = config('app.locale');
159
        }
160
161
        $assignment = $this->getAssignment($fieldSlug);
162
163
        $type = $assignment->getFieldType();
164
165
        $accessor = $type->getAccessor();
166
        $modifier = $type->getModifier();
167
168
        if ($assignment->isTranslatable()) {
169
170
            $entry = $this->translateOrDefault($locale);
171
172
            $type->setLocale($locale);
173
        } else {
174
            $entry = $this;
175
        }
176
177
        $type->setEntry($entry);
178
179
        $value = $modifier->restore($accessor->get());
180
181
        if (
182
            $value === null &&
183
            $assignment->isTranslatable() &&
184
            $assignment->isRequired() &&
185
            $translation = $this->translate()
186
        ) {
187
188
            $type->setEntry($translation);
189
190
            $value = $modifier->restore($accessor->get());
191
        }
192
193
        return $value;
194
    }
195
196
    /**
197
     * Set a field value.
198
     *
199
     * @param $fieldSlug
200
     * @param $value
201
     */
202
    public function setFieldValue($fieldSlug, $value)
203
    {
204
        $assignment = $this->getAssignment($fieldSlug);
205
206
        $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...
207
208
        $type->setEntry($this);
209
210
        $accessor = $type->getAccessor();
211
        $modifier = $type->getModifier();
212
213
        $accessor->set($modifier->modify($value));
214
    }
215
216
    /**
217
     * Get an entry field.
218
     *
219
     * @param  $slug
220
     * @return FieldInterface|null
221
     */
222
    public function getField($slug)
223
    {
224
        $assignment = $this->getAssignment($slug);
225
226
        if (!$assignment instanceof AssignmentInterface) {
227
            return null;
228
        }
229
230
        return $assignment->getField();
231
    }
232
233
    /**
234
     * Return whether an entry has
235
     * a field with a given slug.
236
     *
237
     * @param  $slug
238
     * @return bool
239
     */
240
    public function hasField($slug)
241
    {
242
        return ($this->getField($slug) !== null);
243
    }
244
245
    /**
246
     * Get the field type from a field slug.
247
     *
248
     * @param  $fieldSlug
249
     * @return null|FieldType
250
     */
251 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...
252
    {
253
        $locale = config('app.locale');
254
255
        $assignment = $this->getAssignment($fieldSlug);
256
257
        if (!$assignment) {
258
            return null;
259
        }
260
261
        $type = $assignment->getFieldType();
262
263
        if ($assignment->isTranslatable()) {
264
265
            $entry = $this->translateOrDefault($locale);
266
267
            $type->setLocale($locale);
268
        } else {
269
            $entry = $this;
270
        }
271
272
        $type->setEntry($entry);
273
274
        $type->setValue($this->getFieldValue($fieldSlug));
275
        $type->setEntry($this);
276
277
        return $type;
278
    }
279
280
    /**
281
     * Get the field type query.
282
     *
283
     * @param $fieldSlug
284
     * @return FieldTypeQuery
285
     */
286
    public function getFieldTypeQuery($fieldSlug)
287
    {
288
        if (!$type = $this->getFieldType($fieldSlug)) {
289
            return null;
290
        }
291
292
        return $type->getQuery();
293
    }
294
295
    /**
296
     * Get the field type presenter.
297
     *
298
     * @param $fieldSlug
299
     * @return FieldTypePresenter
300
     */
301
    public function getFieldTypePresenter($fieldSlug)
302
    {
303
        if (!$type = $this->getFieldType($fieldSlug)) {
304
            return null;
305
        }
306
307
        return $type->getPresenter();
308
    }
309
310
    /**
311
     * Set a given attribute on the model.
312
     * Override the behavior here to give
313
     * the field types a chance to modify things.
314
     *
315
     * @param  string $key
316
     * @param  mixed  $value
317
     * @return $this
318
     */
319
    public function setAttribute($key, $value)
320
    {
321
        if (!$this->isKeyALocale($key) && !$this->hasSetMutator($key) && $this->getFieldType($key)) {
322
            $this->setFieldValue($key, $value);
323
        } else {
324
            parent::setAttribute($key, $value);
325
        }
326
327
        return $this;
328
    }
329
330
    /**
331
     * Get a given attribute on the model.
332
     * Override the behavior here to give
333
     * the field types a chance to modify things.
334
     *
335
     * @param  string $key
336
     * @return mixed
337
     */
338
    public function getAttribute($key)
339
    {
340
        // Check if it's a relationship first.
341
        if (in_array($key, $this->relationships)) {
342
            return parent::getAttribute(camel_case($key));
343
        }
344
345
        if (
346
            !$this->hasGetMutator($key)
347
            && in_array($key, $this->fields)
348
        ) {
349
            return $this->getFieldValue($key);
350
        } else {
351
            return parent::getAttribute($key);
352
        }
353
    }
354
355
    /**
356
     * Get a raw unmodified attribute.
357
     *
358
     * @param      $key
359
     * @param bool $process
360
     * @return mixed|null
361
     */
362
    public function getRawAttribute($key, $process = true)
363
    {
364
        if (!$process) {
365
            return $this->getAttributeFromArray($key);
366
        }
367
368
        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...
369
    }
370
371
    /**
372
     * Set a raw unmodified attribute.
373
     *
374
     * @param $key
375
     * @param $value
376
     * @return $this
377
     */
378
    public function setRawAttribute($key, $value)
379
    {
380
        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...
381
382
        return $this;
383
    }
384
385
    /**
386
     * Get the stream.
387
     *
388
     * @return StreamInterface
389
     */
390
    public function getStream()
391
    {
392
        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 392 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...
393
    }
394
395
    /**
396
     * Get the stream namespace.
397
     *
398
     * @return string
399
     */
400
    public function getStreamNamespace()
401
    {
402
        $stream = $this->getStream();
403
404
        return $stream->getNamespace();
405
    }
406
407
    /**
408
     * Get the stream slug.
409
     *
410
     * @return string
411
     */
412
    public function getStreamSlug()
413
    {
414
        $stream = $this->getStream();
415
416
        return $stream->getSlug();
417
    }
418
419
    /**
420
     * Get the entry's stream name.
421
     *
422
     * @return string
423
     */
424
    public function getStreamName()
425
    {
426
        $stream = $this->getStream();
427
428
        return $stream->getName();
429
    }
430
431
    /**
432
     * Get the stream prefix.
433
     *
434
     * @return string
435
     */
436
    public function getStreamPrefix()
437
    {
438
        $stream = $this->getStream();
439
440
        return $stream->getPrefix();
441
    }
442
443
    /**
444
     * Get the table name.
445
     *
446
     * @return string
447
     */
448
    public function getTableName()
449
    {
450
        $stream = $this->getStream();
451
452
        return $stream->getEntryTableName();
453
    }
454
455
    /**
456
     * Get the translations table name.
457
     *
458
     * @return string
459
     */
460
    public function getTranslationsTableName()
461
    {
462
        $stream = $this->getStream();
463
464
        return $stream->getEntryTranslationsTableName();
465
    }
466
467
    /**
468
     * Get all assignments.
469
     *
470
     * @return AssignmentCollection
471
     */
472
    public function getAssignments()
473
    {
474
        $stream = $this->getStream();
475
476
        return $stream->getAssignments();
477
    }
478
479
    /**
480
     * Get the field slugs for assigned fields.
481
     *
482
     * @param null $prefix
483
     * @return array
484
     */
485
    public function getAssignmentFieldSlugs($prefix = null)
486
    {
487
        $assignments = $this->getAssignments();
488
489
        return $assignments->fieldSlugs($prefix);
490
    }
491
492
    /**
493
     * Get all assignments of the
494
     * provided field type namespace.
495
     *
496
     * @param $fieldType
497
     * @return AssignmentCollection
498
     */
499
    public function getAssignmentsByFieldType($fieldType)
500
    {
501
        $assignments = $this->getAssignments();
502
503
        return $assignments->findAllByFieldType($fieldType);
504
    }
505
506
    /**
507
     * Get an assignment by field slug.
508
     *
509
     * @param  $fieldSlug
510
     * @return AssignmentInterface
511
     */
512
    public function getAssignment($fieldSlug)
513
    {
514
        $assignments = $this->getAssignments();
515
516
        return $assignments->findByFieldSlug($fieldSlug);
517
    }
518
519
    /**
520
     * Return translated assignments.
521
     *
522
     * @return AssignmentCollection
523
     */
524
    public function getTranslatableAssignments()
525
    {
526
        $stream      = $this->getStream();
527
        $assignments = $stream->getAssignments();
528
529
        return $assignments->translatable();
530
    }
531
532
    /**
533
     * Return relation assignments.
534
     *
535
     * @return AssignmentCollection
536
     */
537
    public function getRelationshipAssignments()
538
    {
539
        $stream      = $this->getStream();
540
        $assignments = $stream->getAssignments();
541
542
        return $assignments->relations();
543
    }
544
545
    /**
546
     * Get the translatable flag.
547
     *
548
     * @return bool
549
     */
550
    public function isTranslatable()
551
    {
552
        $stream = $this->getStream();
553
554
        return $stream->isTranslatable();
555
    }
556
557
    /**
558
     * Return whether the entry is trashable or not.
559
     *
560
     * @return bool
561
     */
562
    public function isTrashable()
563
    {
564
        $stream = $this->getStream();
565
566
        return $stream->isTrashable();
567
    }
568
569
    /**
570
     * Return the last modified datetime.
571
     *
572
     * @return Carbon
573
     */
574
    public function lastModified()
575
    {
576
        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...
577
    }
578
579
    /**
580
     * Return whether the title column is
581
     * translatable or not.
582
     *
583
     * @return bool
584
     */
585
    public function titleColumnIsTranslatable()
586
    {
587
        return $this->assignmentIsTranslatable($this->getTitleName());
588
    }
589
590
    /**
591
     * Return whether or not the assignment for
592
     * the given field slug is translatable.
593
     *
594
     * @param $fieldSlug
595
     * @return bool
596
     */
597
    public function assignmentIsTranslatable($fieldSlug)
598
    {
599
        return $this->isTranslatedAttribute($fieldSlug);
600
    }
601
602
    /**
603
     * Return whether or not the assignment for
604
     * the given field slug is a relationship.
605
     *
606
     * @param $fieldSlug
607
     * @return bool
608
     */
609
    public function assignmentIsRelationship($fieldSlug)
610
    {
611
        $relationships = $this->getRelationshipAssignments();
612
613
        return in_array($fieldSlug, $relationships->fieldSlugs());
614
    }
615
616
    /**
617
     * Fire field type events.
618
     *
619
     * @param       $trigger
620
     * @param array $payload
621
     */
622
    public function fireFieldTypeEvents($trigger, $payload = [])
623
    {
624
        $assignments = $this->getAssignments();
625
626
        /* @var AssignmentInterface $assignment */
627
        foreach ($assignments->notTranslatable() as $assignment) {
628
629
            $fieldType = $assignment->getFieldType();
630
631
            $fieldType->setValue($this->getFieldValue($assignment->getFieldSlug()));
632
633
            $fieldType->setEntry($this);
634
635
            $payload['entry']     = $this;
636
            $payload['fieldType'] = $fieldType;
637
638
            $fieldType->fire($trigger, $payload);
639
        }
640
    }
641
642
    /**
643
     * Return the related stream.
644
     *
645
     * @return StreamInterface|array
646
     */
647
    public function stream()
648
    {
649
        if (!$this->stream instanceof StreamInterface) {
650
            $this->stream = app('Anomaly\Streams\Platform\Stream\StreamModel')->make($this->stream);
651
        }
652
653
        return $this->stream;
654
    }
655
656
    /**
657
     * @param array $items
658
     * @return EntryCollection
659
     */
660 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...
661
    {
662
        $collection = substr(get_class($this), 0, -5) . 'Collection';
663
664
        if (class_exists($collection)) {
665
            return new $collection($items);
666
        }
667
668
        return new EntryCollection($items);
669
    }
670
671
    /**
672
     * Return the entry presenter.
673
     *
674
     * This is against standards but required
675
     * by the presentable interface.
676
     *
677
     * @return EntryPresenter
678
     */
679 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...
680
    {
681
        $presenter = substr(get_class($this), 0, -5) . 'Presenter';
682
683
        if (class_exists($presenter)) {
684
            return app()->make($presenter, ['object' => $this]);
685
        }
686
687
        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...
688
    }
689
690
    /**
691
     * Return a new presenter instance.
692
     *
693
     * @return EntryPresenter
694
     */
695
    public function newPresenter()
696
    {
697
        return $this->getPresenter();
698
    }
699
700
    /**
701
     * Get a new query builder for the model's table.
702
     *
703
     * @return \Illuminate\Database\Eloquent\Builder
704
     */
705 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...
706
    {
707
        $builder = new EntryQueryBuilder($this->newBaseQueryBuilder());
708
709
        // Once we have the query builders, we will set the model instances so the
710
        // builder can easily access any information it may need from the model
711
        // while it is constructing and executing various queries against it.
712
        $builder->setModel($this)->with($this->with);
713
714
        return $this->applyGlobalScopes($builder);
715
    }
716
717
    /**
718
     * Override the __get method.
719
     *
720
     * @param string $key
721
     * @return EntryPresenter|mixed
722
     */
723
    public function __get($key)
724
    {
725
        if ($key === 'decorated') {
726
            return $this->getPresenter();
727
        }
728
729
        return parent::__get($key); // TODO: Change the autogenerated stub
730
    }
731
}
732