Completed
Push — master ( a9d217...4040dd )
by Ryan
08:20
created

EntryModel::getAssignments()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
c 0
b 0
f 0
rs 9.4285
cc 1
eloc 3
nc 1
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 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
     * @param null $locale
202
     * @return $this
203
     */
204
    public function setFieldValue($fieldSlug, $value, $locale = null)
205
    {
206
        if (!$locale) {
207
            $locale = config('app.locale');
208
        }
209
210
        $assignment = $this->getAssignment($fieldSlug);
211
212
        $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...
213
214
        if ($assignment->isTranslatable()) {
215
216
            $entry = $this->translateOrNew($locale);
217
218
            $type->setLocale($locale);
219
        } else {
220
            $entry = $this;
221
        }
222
223
        $type->setEntry($entry);
224
225
        $accessor = $type->getAccessor();
226
        $modifier = $type->getModifier();
227
228
        $accessor->set($modifier->modify($value));
229
230
        return $this;
231
    }
232
233
    /**
234
     * Get an entry field.
235
     *
236
     * @param  $slug
237
     * @return FieldInterface|null
238
     */
239
    public function getField($slug)
240
    {
241
        $assignment = $this->getAssignment($slug);
242
243
        if (!$assignment instanceof AssignmentInterface) {
244
            return null;
245
        }
246
247
        return $assignment->getField();
248
    }
249
250
    /**
251
     * Return whether an entry has
252
     * a field with a given slug.
253
     *
254
     * @param  $slug
255
     * @return bool
256
     */
257
    public function hasField($slug)
258
    {
259
        return ($this->getField($slug) !== null);
260
    }
261
262
    /**
263
     * Get the field type from a field slug.
264
     *
265
     * @param  $fieldSlug
266
     * @return null|FieldType
267
     */
268 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...
269
    {
270
        $locale = config('app.locale');
271
272
        $assignment = $this->getAssignment($fieldSlug);
273
274
        if (!$assignment) {
275
            return null;
276
        }
277
278
        $type = $assignment->getFieldType();
279
280
        if ($assignment->isTranslatable()) {
281
282
            $entry = $this->translateOrDefault($locale);
283
284
            $type->setLocale($locale);
285
        } else {
286
            $entry = $this;
287
        }
288
289
        $type->setEntry($entry);
290
291
        $type->setValue($this->getFieldValue($fieldSlug));
292
        $type->setEntry($this);
293
294
        return $type;
295
    }
296
297
    /**
298
     * Get the field type query.
299
     *
300
     * @param $fieldSlug
301
     * @return FieldTypeQuery
302
     */
303
    public function getFieldTypeQuery($fieldSlug)
304
    {
305
        if (!$type = $this->getFieldType($fieldSlug)) {
306
            return null;
307
        }
308
309
        return $type->getQuery();
310
    }
311
312
    /**
313
     * Get the field type presenter.
314
     *
315
     * @param $fieldSlug
316
     * @return FieldTypePresenter
317
     */
318
    public function getFieldTypePresenter($fieldSlug)
319
    {
320
        if (!$type = $this->getFieldType($fieldSlug)) {
321
            return null;
322
        }
323
324
        return $type->getPresenter();
325
    }
326
327
    /**
328
     * Set a given attribute on the model.
329
     * Override the behavior here to give
330
     * the field types a chance to modify things.
331
     *
332
     * @param  string $key
333
     * @param  mixed  $value
334
     * @return $this
335
     */
336
    public function setAttribute($key, $value)
337
    {
338
        if (!$this->isKeyALocale($key) && !$this->hasSetMutator($key) && $this->getFieldType($key)) {
339
            $this->setFieldValue($key, $value);
340
        } else {
341
            parent::setAttribute($key, $value);
342
        }
343
344
        return $this;
345
    }
346
347
    /**
348
     * Get a given attribute on the model.
349
     * Override the behavior here to give
350
     * the field types a chance to modify things.
351
     *
352
     * @param  string $key
353
     * @return mixed
354
     */
355
    public function getAttribute($key)
356
    {
357
        // Check if it's a relationship first.
358
        if (in_array($key, $this->relationships)) {
359
            return parent::getAttribute(camel_case($key));
360
        }
361
362
        if (
363
            !$this->hasGetMutator($key)
364
            && in_array($key, $this->fields)
365
        ) {
366
            return $this->getFieldValue($key);
367
        } else {
368
            return parent::getAttribute($key);
369
        }
370
    }
371
372
    /**
373
     * Get a raw unmodified attribute.
374
     *
375
     * @param      $key
376
     * @param bool $process
377
     * @return mixed|null
378
     */
379
    public function getRawAttribute($key, $process = true)
380
    {
381
        if (!$process) {
382
            return $this->getAttributeFromArray($key);
383
        }
384
385
        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...
386
    }
387
388
    /**
389
     * Set a raw unmodified attribute.
390
     *
391
     * @param $key
392
     * @param $value
393
     * @return $this
394
     */
395
    public function setRawAttribute($key, $value)
396
    {
397
        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...
398
399
        return $this;
400
    }
401
402
    /**
403
     * Get the stream.
404
     *
405
     * @return StreamInterface
406
     */
407
    public function getStream()
408
    {
409
        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 409 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...
410
    }
411
412
    /**
413
     * Get the stream namespace.
414
     *
415
     * @return string
416
     */
417
    public function getStreamNamespace()
418
    {
419
        $stream = $this->getStream();
420
421
        return $stream->getNamespace();
422
    }
423
424
    /**
425
     * Get the stream slug.
426
     *
427
     * @return string
428
     */
429
    public function getStreamSlug()
430
    {
431
        $stream = $this->getStream();
432
433
        return $stream->getSlug();
434
    }
435
436
    /**
437
     * Get the entry's stream name.
438
     *
439
     * @return string
440
     */
441
    public function getStreamName()
442
    {
443
        $stream = $this->getStream();
444
445
        return $stream->getName();
446
    }
447
448
    /**
449
     * Get the stream prefix.
450
     *
451
     * @return string
452
     */
453
    public function getStreamPrefix()
454
    {
455
        $stream = $this->getStream();
456
457
        return $stream->getPrefix();
458
    }
459
460
    /**
461
     * Get the table name.
462
     *
463
     * @return string
464
     */
465
    public function getTableName()
466
    {
467
        $stream = $this->getStream();
468
469
        return $stream->getEntryTableName();
470
    }
471
472
    /**
473
     * Get the translations table name.
474
     *
475
     * @return string
476
     */
477
    public function getTranslationsTableName()
478
    {
479
        $stream = $this->getStream();
480
481
        return $stream->getEntryTranslationsTableName();
482
    }
483
484
    /**
485
     * Get all assignments.
486
     *
487
     * @return AssignmentCollection
488
     */
489
    public function getAssignments()
490
    {
491
        $stream = $this->getStream();
492
493
        return $stream->getAssignments();
494
    }
495
496
    /**
497
     * Get the field slugs for assigned fields.
498
     *
499
     * @param null $prefix
500
     * @return array
501
     */
502
    public function getAssignmentFieldSlugs($prefix = null)
503
    {
504
        $assignments = $this->getAssignments();
505
506
        return $assignments->fieldSlugs($prefix);
507
    }
508
509
    /**
510
     * Get all assignments of the
511
     * provided field type namespace.
512
     *
513
     * @param $fieldType
514
     * @return AssignmentCollection
515
     */
516
    public function getAssignmentsByFieldType($fieldType)
517
    {
518
        $assignments = $this->getAssignments();
519
520
        return $assignments->findAllByFieldType($fieldType);
521
    }
522
523
    /**
524
     * Get an assignment by field slug.
525
     *
526
     * @param  $fieldSlug
527
     * @return AssignmentInterface
528
     */
529
    public function getAssignment($fieldSlug)
530
    {
531
        $assignments = $this->getAssignments();
532
533
        return $assignments->findByFieldSlug($fieldSlug);
534
    }
535
536
    /**
537
     * Return translated assignments.
538
     *
539
     * @return AssignmentCollection
540
     */
541
    public function getTranslatableAssignments()
542
    {
543
        $stream      = $this->getStream();
544
        $assignments = $stream->getAssignments();
545
546
        return $assignments->translatable();
547
    }
548
549
    /**
550
     * Return relation assignments.
551
     *
552
     * @return AssignmentCollection
553
     */
554
    public function getRelationshipAssignments()
555
    {
556
        $stream      = $this->getStream();
557
        $assignments = $stream->getAssignments();
558
559
        return $assignments->relations();
560
    }
561
562
    /**
563
     * Get the translatable flag.
564
     *
565
     * @return bool
566
     */
567
    public function isTranslatable()
568
    {
569
        $stream = $this->getStream();
570
571
        return $stream->isTranslatable();
572
    }
573
574
    /**
575
     * Return whether the entry is trashable or not.
576
     *
577
     * @return bool
578
     */
579
    public function isTrashable()
580
    {
581
        $stream = $this->getStream();
582
583
        return $stream->isTrashable();
584
    }
585
586
    /**
587
     * Return the last modified datetime.
588
     *
589
     * @return Carbon
590
     */
591
    public function lastModified()
592
    {
593
        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...
594
    }
595
596
    /**
597
     * Return whether the title column is
598
     * translatable or not.
599
     *
600
     * @return bool
601
     */
602
    public function titleColumnIsTranslatable()
603
    {
604
        return $this->assignmentIsTranslatable($this->getTitleName());
605
    }
606
607
    /**
608
     * Return whether or not the assignment for
609
     * the given field slug is translatable.
610
     *
611
     * @param $fieldSlug
612
     * @return bool
613
     */
614
    public function assignmentIsTranslatable($fieldSlug)
615
    {
616
        return $this->isTranslatedAttribute($fieldSlug);
617
    }
618
619
    /**
620
     * Return whether or not the assignment for
621
     * the given field slug is a relationship.
622
     *
623
     * @param $fieldSlug
624
     * @return bool
625
     */
626
    public function assignmentIsRelationship($fieldSlug)
627
    {
628
        $relationships = $this->getRelationshipAssignments();
629
630
        return in_array($fieldSlug, $relationships->fieldSlugs());
631
    }
632
633
    /**
634
     * Fire field type events.
635
     *
636
     * @param       $trigger
637
     * @param array $payload
638
     */
639
    public function fireFieldTypeEvents($trigger, $payload = [])
640
    {
641
        $assignments = $this->getAssignments();
642
643
        /* @var AssignmentInterface $assignment */
644
        foreach ($assignments->notTranslatable() as $assignment) {
645
646
            $fieldType = $assignment->getFieldType();
647
648
            $fieldType->setValue($this->getFieldValue($assignment->getFieldSlug()));
649
650
            $fieldType->setEntry($this);
651
652
            $payload['entry']     = $this;
653
            $payload['fieldType'] = $fieldType;
654
655
            $fieldType->fire($trigger, $payload);
656
        }
657
    }
658
659
    /**
660
     * Return the related stream.
661
     *
662
     * @return StreamInterface|array
663
     */
664
    public function stream()
665
    {
666
        if (!$this->stream instanceof StreamInterface) {
667
            $this->stream = app('Anomaly\Streams\Platform\Stream\StreamModel')->make($this->stream);
668
        }
669
670
        return $this->stream;
671
    }
672
673
    /**
674
     * @param array $items
675
     * @return EntryCollection
676
     */
677 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...
678
    {
679
        $collection = substr(get_class($this), 0, -5) . 'Collection';
680
681
        if (class_exists($collection)) {
682
            return new $collection($items);
683
        }
684
685
        return new EntryCollection($items);
686
    }
687
688
    /**
689
     * Return the entry presenter.
690
     *
691
     * This is against standards but required
692
     * by the presentable interface.
693
     *
694
     * @return EntryPresenter
695
     */
696 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...
697
    {
698
        $presenter = substr(get_class($this), 0, -5) . 'Presenter';
699
700
        if (class_exists($presenter)) {
701
            return app()->make($presenter, ['object' => $this]);
702
        }
703
704
        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...
705
    }
706
707
    /**
708
     * Return a new presenter instance.
709
     *
710
     * @return EntryPresenter
711
     */
712
    public function newPresenter()
713
    {
714
        return $this->getPresenter();
715
    }
716
717
    /**
718
     * Get a new query builder for the model's table.
719
     *
720
     * @return \Illuminate\Database\Eloquent\Builder
721
     */
722 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...
723
    {
724
        $builder = new EntryQueryBuilder($this->newBaseQueryBuilder());
725
726
        // Once we have the query builders, we will set the model instances so the
727
        // builder can easily access any information it may need from the model
728
        // while it is constructing and executing various queries against it.
729
        $builder->setModel($this)->with($this->with);
730
731
        return $this->applyGlobalScopes($builder);
732
    }
733
734
    /**
735
     * Override the __get method.
736
     *
737
     * @param string $key
738
     * @return EntryPresenter|mixed
739
     */
740
    public function __get($key)
741
    {
742
        if ($key === 'decorated') {
743
            return $this->getPresenter();
744
        }
745
746
        return parent::__get($key); // TODO: Change the autogenerated stub
747
    }
748
}
749