Completed
Push — master ( 8a3554...20628b )
by Ryan
07:18
created

EntryModel::getPresenter()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 10
Ratio 100 %

Importance

Changes 0
Metric Value
dl 10
loc 10
c 0
b 0
f 0
rs 9.4285
cc 2
eloc 5
nc 2
nop 0
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 model's bound name.
130
     *
131
     * @return string
132
     */
133
    public function getBoundModelName()
134
    {
135
        return get_class(app(get_class($this)));
136
    }
137
138
    /**
139
     * Get the model's bound namespace.
140
     *
141
     * @return string
142
     */
143
    public function getBoundModelNamespace()
144
    {
145
        $namespace = explode('\\', $this->getBoundModelName());
146
147
        array_pop($namespace);
148
149
        return implode('\\', $namespace);
150
    }
151
152
    /**
153
     * Get the sort order.
154
     *
155
     * @return int
156
     */
157
    public function getSortOrder()
158
    {
159
        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...
160
    }
161
162
    /**
163
     * Get the entries title.
164
     *
165
     * @return mixed
166
     */
167
    public function getTitle()
168
    {
169
        return $this->{$this->getTitleName()};
170
    }
171
172
    /**
173
     * Get a field value.
174
     *
175
     * @param      $fieldSlug
176
     * @param null $locale
177
     * @return mixed
178
     */
179
    public function getFieldValue($fieldSlug, $locale = null)
180
    {
181
        if (!$locale) {
182
            $locale = config('app.locale');
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $locale. This often makes code more readable.
Loading history...
183
        }
184
185
        $assignment = $this->getAssignment($fieldSlug);
186
187
        $type = $assignment->getFieldType();
188
189
        $accessor = $type->getAccessor();
190
        $modifier = $type->getModifier();
191
192
        if ($assignment->isTranslatable()) {
193
194
            $entry = $this->translateOrDefault($locale);
195
196
            $type->setLocale($locale);
197
        } else {
198
            $entry = $this;
199
        }
200
201
        $type->setEntry($entry);
202
203
        $value = $modifier->restore($accessor->get());
204
205
        if (
206
            $value === null &&
207
            $assignment->isTranslatable() &&
208
            $assignment->isRequired() &&
209
            $translation = $this->translate()
210
        ) {
211
212
            $type->setEntry($translation);
213
214
            $value = $modifier->restore($accessor->get());
215
        }
216
217
        return $value;
218
    }
219
220
    /**
221
     * Set a field value.
222
     *
223
     * @param      $fieldSlug
224
     * @param      $value
225
     * @param null $locale
226
     * @return $this
227
     */
228
    public function setFieldValue($fieldSlug, $value, $locale = null)
229
    {
230
        if (!$locale) {
231
            $locale = config('app.locale');
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $locale. This often makes code more readable.
Loading history...
232
        }
233
234
        $assignment = $this->getAssignment($fieldSlug);
235
236
        $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...
237
238
        if ($assignment->isTranslatable()) {
239
240
            $entry = $this->translateOrNew($locale);
241
242
            $type->setLocale($locale);
243
        } else {
244
            $entry = $this;
245
        }
246
247
        $type->setEntry($entry);
248
249
        $accessor = $type->getAccessor();
250
        $modifier = $type->getModifier();
251
252
        $accessor->set($modifier->modify($value));
253
254
        return $this;
255
    }
256
257
    /**
258
     * Get an entry field.
259
     *
260
     * @param  $slug
261
     * @return FieldInterface|null
262
     */
263
    public function getField($slug)
264
    {
265
        $assignment = $this->getAssignment($slug);
266
267
        if (!$assignment instanceof AssignmentInterface) {
268
            return null;
269
        }
270
271
        return $assignment->getField();
272
    }
273
274
    /**
275
     * Return whether an entry has
276
     * a field with a given slug.
277
     *
278
     * @param  $slug
279
     * @return bool
280
     */
281
    public function hasField($slug)
282
    {
283
        return ($this->getField($slug) !== null);
284
    }
285
286
    /**
287
     * Get the field type from a field slug.
288
     *
289
     * @param  $fieldSlug
290
     * @return null|FieldType
291
     */
292 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...
293
    {
294
        $locale = config('app.locale');
295
296
        $assignment = $this->getAssignment($fieldSlug);
297
298
        if (!$assignment) {
299
            return null;
300
        }
301
302
        $type = $assignment->getFieldType();
303
304
        if ($assignment->isTranslatable()) {
305
306
            $entry = $this->translateOrDefault($locale);
307
308
            $type->setLocale($locale);
309
        } else {
310
            $entry = $this;
311
        }
312
313
        $type->setEntry($entry);
314
315
        $type->setValue($this->getFieldValue($fieldSlug));
316
        $type->setEntry($this);
317
318
        return $type;
319
    }
320
321
    /**
322
     * Get the field type query.
323
     *
324
     * @param $fieldSlug
325
     * @return FieldTypeQuery
326
     */
327
    public function getFieldTypeQuery($fieldSlug)
328
    {
329
        if (!$type = $this->getFieldType($fieldSlug)) {
330
            return null;
331
        }
332
333
        return $type->getQuery();
334
    }
335
336
    /**
337
     * Get the field type presenter.
338
     *
339
     * @param $fieldSlug
340
     * @return FieldTypePresenter
341
     */
342
    public function getFieldTypePresenter($fieldSlug)
343
    {
344
        if (!$type = $this->getFieldType($fieldSlug)) {
345
            return null;
346
        }
347
348
        return $type->getPresenter();
349
    }
350
351
    /**
352
     * Set a given attribute on the model.
353
     * Override the behavior here to give
354
     * the field types a chance to modify things.
355
     *
356
     * @param  string $key
357
     * @param  mixed  $value
358
     * @return $this
359
     */
360
    public function setAttribute($key, $value)
361
    {
362
        if (!$this->isKeyALocale($key) && !$this->hasSetMutator($key) && $this->getFieldType($key)) {
363
            $this->setFieldValue($key, $value);
364
        } else {
365
            parent::setAttribute($key, $value);
366
        }
367
368
        return $this;
369
    }
370
371
    /**
372
     * Get a given attribute on the model.
373
     * Override the behavior here to give
374
     * the field types a chance to modify things.
375
     *
376
     * @param  string $key
377
     * @return mixed
378
     */
379
    public function getAttribute($key)
380
    {
381
        // Check if it's a relationship first.
382
        if (in_array($key, $this->relationships)) {
383
            return parent::getAttribute(camel_case($key));
384
        }
385
386
        if (
387
            !$this->hasGetMutator($key)
388
            && in_array($key, $this->fields)
389
        ) {
390
            return $this->getFieldValue($key);
391
        } else {
392
            return parent::getAttribute($key);
393
        }
394
    }
395
396
    /**
397
     * Get a raw unmodified attribute.
398
     *
399
     * @param      $key
400
     * @param bool $process
401
     * @return mixed|null
402
     */
403
    public function getRawAttribute($key, $process = true)
404
    {
405
        if (!$process) {
406
            return $this->getAttributeFromArray($key);
407
        }
408
409
        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...
410
    }
411
412
    /**
413
     * Set a raw unmodified attribute.
414
     *
415
     * @param $key
416
     * @param $value
417
     * @return $this
418
     */
419
    public function setRawAttribute($key, $value)
420
    {
421
        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...
422
423
        return $this;
424
    }
425
426
    /**
427
     * Get the stream.
428
     *
429
     * @return StreamInterface
430
     */
431
    public function getStream()
432
    {
433
        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 433 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...
434
    }
435
436
    /**
437
     * Get the stream namespace.
438
     *
439
     * @return string
440
     */
441
    public function getStreamNamespace()
442
    {
443
        $stream = $this->getStream();
444
445
        return $stream->getNamespace();
446
    }
447
448
    /**
449
     * Get the stream slug.
450
     *
451
     * @return string
452
     */
453
    public function getStreamSlug()
454
    {
455
        $stream = $this->getStream();
456
457
        return $stream->getSlug();
458
    }
459
460
    /**
461
     * Get the entry's stream name.
462
     *
463
     * @return string
464
     */
465
    public function getStreamName()
466
    {
467
        $stream = $this->getStream();
468
469
        return $stream->getName();
470
    }
471
472
    /**
473
     * Get the stream prefix.
474
     *
475
     * @return string
476
     */
477
    public function getStreamPrefix()
478
    {
479
        $stream = $this->getStream();
480
481
        return $stream->getPrefix();
482
    }
483
484
    /**
485
     * Get the table name.
486
     *
487
     * @return string
488
     */
489
    public function getTableName()
490
    {
491
        $stream = $this->getStream();
492
493
        return $stream->getEntryTableName();
494
    }
495
496
    /**
497
     * Get the translations table name.
498
     *
499
     * @return string
500
     */
501
    public function getTranslationsTableName()
502
    {
503
        $stream = $this->getStream();
504
505
        return $stream->getEntryTranslationsTableName();
506
    }
507
508
    /**
509
     * Get all assignments.
510
     *
511
     * @return AssignmentCollection
512
     */
513
    public function getAssignments()
514
    {
515
        $stream = $this->getStream();
516
517
        return $stream->getAssignments();
518
    }
519
520
    /**
521
     * Get the field slugs for assigned fields.
522
     *
523
     * @param null $prefix
524
     * @return array
525
     */
526
    public function getAssignmentFieldSlugs($prefix = null)
527
    {
528
        $assignments = $this->getAssignments();
529
530
        return $assignments->fieldSlugs($prefix);
531
    }
532
533
    /**
534
     * Get all assignments of the
535
     * provided field type namespace.
536
     *
537
     * @param $fieldType
538
     * @return AssignmentCollection
539
     */
540
    public function getAssignmentsByFieldType($fieldType)
541
    {
542
        $assignments = $this->getAssignments();
543
544
        return $assignments->findAllByFieldType($fieldType);
545
    }
546
547
    /**
548
     * Get an assignment by field slug.
549
     *
550
     * @param  $fieldSlug
551
     * @return AssignmentInterface
552
     */
553
    public function getAssignment($fieldSlug)
554
    {
555
        $assignments = $this->getAssignments();
556
557
        return $assignments->findByFieldSlug($fieldSlug);
558
    }
559
560
    /**
561
     * Return translated assignments.
562
     *
563
     * @return AssignmentCollection
564
     */
565
    public function getTranslatableAssignments()
566
    {
567
        $stream      = $this->getStream();
568
        $assignments = $stream->getAssignments();
569
570
        return $assignments->translatable();
571
    }
572
573
    /**
574
     * Return relation assignments.
575
     *
576
     * @return AssignmentCollection
577
     */
578
    public function getRelationshipAssignments()
579
    {
580
        $stream      = $this->getStream();
581
        $assignments = $stream->getAssignments();
582
583
        return $assignments->relations();
584
    }
585
586
    /**
587
     * Get the translatable flag.
588
     *
589
     * @return bool
590
     */
591
    public function isTranslatable()
592
    {
593
        $stream = $this->getStream();
594
595
        return $stream->isTranslatable();
596
    }
597
598
    /**
599
     * Return whether the entry is trashable or not.
600
     *
601
     * @return bool
602
     */
603
    public function isTrashable()
604
    {
605
        $stream = $this->getStream();
606
607
        return $stream->isTrashable();
608
    }
609
610
    /**
611
     * Return the last modified datetime.
612
     *
613
     * @return Carbon
614
     */
615
    public function lastModified()
616
    {
617
        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...
618
    }
619
620
    /**
621
     * Return whether the title column is
622
     * translatable or not.
623
     *
624
     * @return bool
625
     */
626
    public function titleColumnIsTranslatable()
627
    {
628
        return $this->assignmentIsTranslatable($this->getTitleName());
629
    }
630
631
    /**
632
     * Return whether or not the assignment for
633
     * the given field slug is translatable.
634
     *
635
     * @param $fieldSlug
636
     * @return bool
637
     */
638
    public function assignmentIsTranslatable($fieldSlug)
639
    {
640
        return $this->isTranslatedAttribute($fieldSlug);
641
    }
642
643
    /**
644
     * Return whether or not the assignment for
645
     * the given field slug is a relationship.
646
     *
647
     * @param $fieldSlug
648
     * @return bool
649
     */
650
    public function assignmentIsRelationship($fieldSlug)
651
    {
652
        $relationships = $this->getRelationshipAssignments();
653
654
        return in_array($fieldSlug, $relationships->fieldSlugs());
655
    }
656
657
    /**
658
     * Fire field type events.
659
     *
660
     * @param       $trigger
661
     * @param array $payload
662
     */
663
    public function fireFieldTypeEvents($trigger, $payload = [])
664
    {
665
        $assignments = $this->getAssignments();
666
667
        /* @var AssignmentInterface $assignment */
668
        foreach ($assignments->notTranslatable() as $assignment) {
669
670
            $fieldType = $assignment->getFieldType();
671
672
            $fieldType->setValue($this->getFieldValue($assignment->getFieldSlug()));
673
674
            $fieldType->setEntry($this);
675
676
            $payload['entry']     = $this;
677
            $payload['fieldType'] = $fieldType;
678
679
            $fieldType->fire($trigger, $payload);
680
        }
681
    }
682
683
    /**
684
     * Return the related stream.
685
     *
686
     * @return StreamInterface|array
687
     */
688
    public function stream()
689
    {
690
        if (!$this->stream instanceof StreamInterface) {
691
            $this->stream = app('Anomaly\Streams\Platform\Stream\StreamModel')->make($this->stream);
692
        }
693
694
        return $this->stream;
695
    }
696
697
    /**
698
     * @param array $items
699
     * @return EntryCollection
700
     */
701
    public function newCollection(array $items = [])
702
    {
703
        $collection = substr(get_class($this), 0, -5) . 'Collection';
704
705
        if (class_exists($collection)) {
706
            return new $collection($items);
707
        }
708
709
        return new EntryCollection($items);
710
    }
711
712
    /**
713
     * Return the entry presenter.
714
     *
715
     * This is against standards but required
716
     * by the presentable interface.
717
     *
718
     * @return EntryPresenter
719
     */
720 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...
721
    {
722
        $presenter = substr(get_class($this), 0, -5) . 'Presenter';
723
724
        if (class_exists($presenter)) {
725
            return app()->make($presenter, ['object' => $this]);
726
        }
727
728
        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...
729
    }
730
731
    /**
732
     * Return a new presenter instance.
733
     *
734
     * @return EntryPresenter
735
     */
736
    public function newPresenter()
737
    {
738
        return $this->getPresenter();
739
    }
740
741
    /**
742
     * Return a model route.
743
     *
744
     * @return string
745
     */
746
    public function route($route, array $parameters = [])
747
    {
748
        $router = $this->getRouter();
749
750
        return $router->make($route, $parameters);
751
    }
752
753
    /**
754
     * Return a new router instance.
755
     *
756
     * @return EntryRouter
757
     */
758
    public function newRouter()
759
    {
760
        return app()->make($this->getRouterName(), ['model' => $this]);
761
    }
762
763
    /**
764
     * Get the router.
765
     *
766
     * @return EntryRouter
767
     */
768
    public function getRouter()
769
    {
770
        if (isset($this->cache['router'])) {
771
            return $this->cache['router'];
772
        }
773
774
        return $this->cache['router'] = $this->newRouter();
775
    }
776
777
    /**
778
     * Get the router name.
779
     *
780
     * @return string
781
     */
782
    public function getRouterName()
783
    {
784
        $router = substr(get_class($this), 0, -5) . 'Router';
785
786
        return class_exists($router) ? $router : EntryRouter::class;
787
    }
788
789
    /**
790
     * Get a new query builder for the model's table.
791
     *
792
     * @return \Illuminate\Database\Eloquent\Builder
793
     */
794 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...
795
    {
796
        $builder = new EntryQueryBuilder($this->newBaseQueryBuilder());
797
798
        // Once we have the query builders, we will set the model instances so the
799
        // builder can easily access any information it may need from the model
800
        // while it is constructing and executing various queries against it.
801
        $builder->setModel($this)->with($this->with);
802
803
        return $this->applyGlobalScopes($builder);
804
    }
805
806
    /**
807
     * Get the criteria class.
808
     *
809
     * @return string
810
     */
811
    public function getCriteriaName()
812
    {
813
        $criteria = substr(get_class($this), 0, -5) . 'Criteria';
814
815
        return class_exists($criteria) ? $criteria : EntryCriteria::class;
816
    }
817
818
    /**
819
     * Override the __get method.
820
     *
821
     * @param string $key
822
     * @return EntryPresenter|mixed
823
     */
824
    public function __get($key)
825
    {
826
        if ($key === 'decorated') {
827
            return $this->getPresenter();
828
        }
829
830
        return parent::__get($key); // TODO: Change the autogenerated stub
831
    }
832
}
833