Completed
Push — dev ( 547fcf...46c257 )
by Zach
03:31
created

Project   D

Complexity

Total Complexity 59

Size/Duplication

Total Lines 616
Duplicated Lines 0 %

Coupling/Cohesion

Components 4
Dependencies 4

Importance

Changes 5
Bugs 1 Features 0
Metric Value
wmc 59
lcom 4
cbo 4
dl 0
loc 616
rs 4.4
c 5
b 1
f 0

41 Methods

Rating   Name   Duplication   Size   Complexity  
A getRouteKeyName() 0 4 1
A boot() 0 12 1
A allVisible() 0 6 1
A allHidden() 0 6 1
A allGrouped() 0 6 1
A allOrdered() 0 6 1
A orderAndGroupQuery() 0 20 3
A hasBlockNamed() 0 4 1
A hasImageNamed() 0 4 1
A hasLinkNamed() 0 4 1
A hasRelationshipNamed() 0 7 1
A blocks() 0 4 1
A images() 0 4 1
A links() 0 4 1
A id() 0 4 1
A name() 0 4 1
A type() 0 4 1
A slug() 0 4 1
A order() 0 4 1
A hasBlocks() 0 4 1
A block() 0 4 1
A blockText() 0 12 3
A getProjectBlock() 0 10 3
A getProjectBlockText() 0 12 4
A hasImages() 0 4 1
A image() 0 4 1
A imageUrl() 0 8 2
A imageCaption() 0 8 2
A imageAlt() 0 8 2
A getProjectImage() 0 10 3
A getProjectImageUrl() 0 10 2
A hasLinks() 0 4 1
A link() 0 4 1
A linkUrl() 0 8 2
A linkText() 0 8 2
A getFromRelationshipByName() 0 10 2
A scopeWithBlocks() 0 5 1
A scopeFull() 0 6 1
A imagesWithProps() 0 7 1
A scopeOrderRelationship() 0 6 1
A generateProps() 0 9 1

How to fix   Complexity   

Complex Class

Complex classes like Project 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 Project, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Larafolio\Models;
4
5
use Larafolio\Models\Image;
6
use Larafolio\Models\Project;
7
use Larafolio\Helpers\Sluggable;
8
use Illuminate\Database\Eloquent\Model;
9
use Illuminate\Database\Eloquent\SoftDeletes;
10
11
class Project extends Model
12
{
13
    use Sluggable, SoftDeletes;
14
15
    /**
16
     * The table associated with the model.
17
     *
18
     * @var string
19
     */
20
    protected $table = 'projects';
21
22
    /**
23
     * The attributes that are mass assignable.
24
     *
25
     * @var array
26
     */
27
    protected $fillable = [
28
        'name', 'slug', 'type', 'visible', 'order',
29
    ];
30
31
    /**
32
     * Properties to always eager load.
33
     *
34
     * @var array
35
     */
36
    protected $with = ['blocks', 'images', 'links'];
37
38
    /**
39
     * The attributes that should be casted to native types.
40
     *
41
     * @var array
42
     */
43
    protected $casts = [
44
        'visible' => 'boolean',
45
    ];
46
47
    /**
48
     * Fields that are dates.
49
     *
50
     * @var array
51
     */
52
    protected $dates = ['created_at', 'updated_at', 'deleted_at'];
53
54
    /**
55
     * Get the route key for the model.
56
     *
57
     * @return string
58
     */
59
    public function getRouteKeyName()
60
    {
61
        return 'slug';
62
    }
63
64
    /**
65
     * Bootstrap model.
66
     */
67
    public static function boot()
68
    {
69
        parent::boot();
70
71
        static::creating(function (Project $project) {
72
            $project->setSlug('name');
73
        });
74
75
        static::updating(function (Project $project) {
76
            $project->setSlug('name');
77
        });
78
    }
79
80
    /**
81
     * Return all visible projects.
82
     *
83
     * @param bool $group If true, group projects by 'type'.
84
     * @param bool $order If true, order projects by 'order'.
85
     *
86
     * @return \Illuminate\Support\Collection
87
     */
88
    public static function allVisible($group = true, $order = true)
89
    {
90
        $query = static::where('visible', true);
91
92
        return static::orderAndGroupQuery($query, $group, $order);
93
    }
94
95
    /**
96
     * Return all hidden projects.
97
     *
98
     * @param bool $group If true, group projects by 'type'.
99
     * @param bool $order If true, order projects by 'order'.
100
     *
101
     * @return \Illuminate\Support\Collection
102
     */
103
    public static function allHidden($group = true, $order = true)
104
    {
105
        $query = static::where('visible', false);
106
107
        return static::orderAndGroupQuery($query, $group, $order);
108
    }
109
110
    /**
111
     * Return all projects grouped by 'type'.
112
     *
113
     * @param bool $order If true, order projects by 'order'.
114
     *
115
     * @return \Illuminate\Support\Collection
116
     */
117
    public static function allGrouped($order = true)
118
    {
119
        $query = static::query();
120
121
        return static::orderAndGroupQuery($query, true, $order);
0 ignored issues
show
Documentation introduced by
$query is of type object<Illuminate\Database\Eloquent\Builder>, but the function expects a object<Larafolio\Models\Builder>.

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...
122
    }
123
124
    /**
125
     * Return all projects ordered by 'order'.
126
     *
127
     * @return \Illuminate\Support\Collection
128
     */
129
    public static function allOrdered()
130
    {
131
        $query = static::query();
132
133
        return static::orderAndGroupQuery($query, false, true);
0 ignored issues
show
Documentation introduced by
$query is of type object<Illuminate\Database\Eloquent\Builder>, but the function expects a object<Larafolio\Models\Builder>.

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...
134
    }
135
136
    /**
137
     * Order and group query, return results.
138
     *
139
     * @param Builder $query Query to be ordered.
140
     * @param bool    $group If true, group projects by 'type'.
141
     * @param bool    $order If true, order projects by 'order'.
142
     *
143
     * @return \Illuminate\Support\Collection
144
     */
145
    protected static function orderAndGroupQuery($query, $group, $order)
146
    {
147
        if ($order) {
148
            $query->orderBy('order');
149
        }
150
151
        $query->orderRelationship('links');
152
153
        $query->orderRelationship('blocks');
154
155
        if ($group) {
156
            return $query->get()
157
                ->each(function ($project, $key) {
158
                    $project->index = $key;
159
                })
160
                ->groupBy('type');
161
        }
162
163
        return $query->get();
164
    }
165
166
    /**
167
     * Get all projects with given block name.
168
     *
169
     * @param string $blockName Name of block.
170
     *
171
     * @return \Illuminate\Support\Collection
172
     */
173
    public static function hasBlockNamed($blockName)
174
    {
175
        return static::hasRelationshipNamed('text_blocks', $blockName);
176
    }
177
178
    /**
179
     * Get all projects with given image name.
180
     *
181
     * @param string $imageName Name of image.
182
     *
183
     * @return \Illuminate\Support\Collection
184
     */
185
    public static function hasImageNamed($imageName)
186
    {
187
        return static::hasRelationshipNamed('images', $imageName);
188
    }
189
190
    /**
191
     * Get all projects with given link name.
192
     *
193
     * @param string $linkName Name of link.
194
     *
195
     * @return \Illuminate\Support\Collection
196
     */
197
    public static function hasLinkNamed($linkName)
198
    {
199
        return static::hasRelationshipNamed('links', $linkName);
200
    }
201
202
    /**
203
     * Get all projects with relationship on table that has given name.
204
     *
205
     * @param string $table Name of table relationship is on.
206
     * @param string $name  Relationship name.
207
     *
208
     * @return \Illuminate\Support\Collection
209
     */
210
    protected static function hasRelationshipNamed($table, $name)
211
    {
212
        return static::join($table, 'projects.id', '=', "{$table}.project_id")
213
            ->where("{$table}.name", '=', $name)
214
            ->select('projects.*')
215
            ->get();
216
    }
217
218
    /**
219
     * A project has many text blocks.
220
     *
221
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
222
     */
223
    public function blocks()
224
    {
225
        return $this->hasMany(TextBlock::class);
226
    }
227
228
    /**
229
     * A project has many images.
230
     *
231
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
232
     */
233
    public function images()
234
    {
235
        return $this->hasMany(Image::class);
236
    }
237
238
    /**
239
     * A project has many links.
240
     *
241
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
242
     */
243
    public function links()
244
    {
245
        return $this->hasMany(Link::class);
246
    }
247
248
    /**
249
     * Return the project id.
250
     *
251
     * @return int
252
     */
253
    public function id()
254
    {
255
        return $this->id;
1 ignored issue
show
Documentation introduced by
The property id does not exist on object<Larafolio\Models\Project>. 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...
256
    }
257
258
    /**
259
     * Return the project name.
260
     *
261
     * @return string
262
     */
263
    public function name()
264
    {
265
        return $this->name;
1 ignored issue
show
Documentation introduced by
The property name does not exist on object<Larafolio\Models\Project>. 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...
266
    }
267
268
    /**
269
     * Return the project type.
270
     *
271
     * @return string
272
     */
273
    public function type()
274
    {
275
        return $this->type;
1 ignored issue
show
Documentation introduced by
The property type does not exist on object<Larafolio\Models\Project>. 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...
276
    }
277
278
    /**
279
     * Return the project slug.
280
     *
281
     * @return string
282
     */
283
    public function slug()
284
    {
285
        return $this->slug;
1 ignored issue
show
Documentation introduced by
The property slug does not exist on object<Larafolio\Models\Project>. 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...
286
    }
287
288
    /**
289
     * Return the project order value.
290
     *
291
     * @return int
292
     */
293
    public function order()
294
    {
295
        return $this->order;
1 ignored issue
show
Documentation introduced by
The property order does not exist on object<Larafolio\Models\Project>. 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...
296
    }
297
298
    /**
299
     * Return true if project has blocks.
300
     *
301
     * @return bool
302
     */
303
    public function hasBlocks()
304
    {
305
        return !$this->blocks->isEmpty();
1 ignored issue
show
Documentation introduced by
The property blocks does not exist on object<Larafolio\Models\Project>. 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...
306
    }
307
308
    /**
309
     * Get a text block by name, if exists.
310
     *
311
     * @param string $name Name of text block to get.
312
     *
313
     * @return Larafolio\Models\TextBlock
314
     */
315
    public function block($name)
316
    {
317
        return $this->getFromRelationshipByName('blocks', $name);
318
    }
319
320
    /**
321
     * Get block text by block name, if block exists.
322
     *
323
     * @param string $name      Name of text block to get.
324
     * @param bool   $formatted If true, return formmated text.
325
     *
326
     * @return string|null
327
     */
328
    public function blockText($name, $formatted = true)
329
    {
330
        if (!$block = $this->block($name)) {
331
            return;
332
        }
333
334
        if ($formatted) {
335
            return $block->formattedText();
336
        }
337
338
        return $block->text();
339
    }
340
341
    /**
342
     * Get formatted text of block named description or first block.
343
     *
344
     * @return Larafolio\Models\TextBlock
345
     */
346
    public function getProjectBlock()
347
    {
348
        $block = $this->block($this->name());
349
350
        if ($block) {
351
            return $block;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $block; (Illuminate\Database\Eloquent\Model) is incompatible with the return type documented by Larafolio\Models\Project::getProjectBlock of type Larafolio\Models\Larafolio\Models\TextBlock.

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...
352
        } elseif ($this->hasBlocks()) {
353
            return $this->blocks()->first();
354
        }
355
    }
356
357
    /**
358
     * Get formatted text of block named description or first block.
359
     *
360
     * @param bool $formatted If true, return formatted text.
361
     *
362
     * @return string
363
     */
364
    public function getProjectBlockText($formatted = true)
365
    {
366
        $project = $this->getProjectBlock();
367
368
        if ($project && $formatted) {
369
            return $project->formattedText();
370
        } elseif ($project) {
371
            return $project->text();
372
        }
373
374
        return $project;
375
    }
376
377
    /**
378
     * Return true if project has images.
379
     *
380
     * @return bool
381
     */
382
    public function hasImages()
383
    {
384
        return !$this->images->isEmpty();
1 ignored issue
show
Documentation introduced by
The property images does not exist on object<Larafolio\Models\Project>. 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...
385
    }
386
387
    /**
388
     * Get image by name, if exists.
389
     *
390
     * @param string $name Name of image to get.
391
     *
392
     * @return Larafolio\Models\Image|null
393
     */
394
    public function image($name)
395
    {
396
        return $this->getFromRelationshipByName('images', $name);
397
    }
398
399
    /**
400
     * Get image url for given size.
401
     *
402
     * @param string $name Name of image to get url for.
403
     * @param string $size Size of image.
404
     *
405
     * @return string|null
406
     */
407
    public function imageUrl($name, $size = 'medium')
408
    {
409
        if (!$image = $this->image($name)) {
410
            return;
411
        }
412
413
        return $image->{$size}();
414
    }
415
416
    /**
417
     * Get caption for image.
418
     *
419
     * @param string $name Name of image to get caption for.
420
     *
421
     * @return string|null
422
     */
423
    public function imageCaption($name)
424
    {
425
        if (!$image = $this->image($name)) {
426
            return;
427
        }
428
429
        return $image->caption();
430
    }
431
432
    /**
433
     * Get alt for image.
434
     *
435
     * @param string $name Name of image to get caption for.
436
     *
437
     * @return string|null
438
     */
439
    public function imageAlt($name)
440
    {
441
        if (!$image = $this->image($name)) {
442
            return;
443
        }
444
445
        return $image->alt();
446
    }
447
448
    /**
449
     * Get url of small image with project name or first image in collection.
450
     *
451
     * @return string
452
     */
453
    public function getProjectImage()
454
    {
455
        $projectImage = $this->image($this->name());
456
457
        if ($projectImage) {
458
            return $projectImage;
459
        } elseif ($this->hasImages()) {
460
            return $this->images()->first();
461
        }
462
    }
463
464
    /**
465
     * Get url of small image with project name or first image in collection.
466
     *
467
     * @param string $size The size of the image, name of image cache filter.
468
     *
469
     * @return string
470
     */
471
    public function getProjectImageUrl($size = 'small')
472
    {
473
        $projectImage = $this->getProjectImage();
474
475
        if ($projectImage) {
476
            return $projectImage->{$size}();
0 ignored issues
show
Bug introduced by
The method $size cannot be called on $projectImage (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
477
        }
478
479
        return $projectImage;
480
    }
481
482
    /**
483
     * Return true if project has links.
484
     *
485
     * @return bool
486
     */
487
    public function hasLinks()
488
    {
489
        return !$this->links->isEmpty();
1 ignored issue
show
Documentation introduced by
The property links does not exist on object<Larafolio\Models\Project>. 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...
490
    }
491
492
    /**
493
     * Get link by name, if exists.
494
     *
495
     * @param string $name Name of link to get.
496
     *
497
     * @return Larafolio\Models\Link|null
498
     */
499
    public function link($name)
500
    {
501
        return $this->getFromRelationshipByName('links', $name);
502
    }
503
504
    /**
505
     * Get link url.
506
     *
507
     * @param string $name Name of link.
508
     *
509
     * @return string|null
510
     */
511
    public function linkUrl($name)
512
    {
513
        if (!$link = $this->link($name)) {
514
            return;
515
        }
516
517
        return $link->url();
518
    }
519
520
    /**
521
     * Get link text.
522
     *
523
     * @param string $name Name of link.
524
     *
525
     * @return string|null
526
     */
527
    public function linkText($name)
528
    {
529
        if (!$link = $this->link($name)) {
530
            return;
531
        }
532
533
        return $link->text();
534
    }
535
536
    /**
537
     * Get a model from a relationship by model name.
538
     *
539
     * @param string $relationship Name of relationship.
540
     * @param string $name         Name of model to get.
541
     *
542
     * @return \Illuminate\Database\Eloquent\Model|null
543
     */
544
    protected function getFromRelationshipByName($relationship, $name)
545
    {
546
        $items = $this->{$relationship}->where('name', $name);
547
548
        if ($items->isEmpty()) {
549
            return;
550
        }
551
552
        return $items->first();
553
    }
554
555
    /**
556
     * Get blocks sorted by order.
557
     *
558
     * @param \Builder $query Query builder.
559
     * @param string   $slug  Project slug.
560
     *
561
     * @return \Builder
562
     */
563
    public function scopeWithBlocks($query, $slug)
564
    {
565
        return $query->orderRelationship('blocks')
566
            ->where('slug', $slug);
567
    }
568
569
    /**
570
     * Get full project info (blocks and links sorted by order).
571
     *
572
     * @param \Builder $query Query builder.
573
     * @param string   $slug  Project slug.
574
     *
575
     * @return \Builder
576
     */
577
    public function scopeFull($query, $slug)
578
    {
579
        return $query->orderRelationship('blocks')
580
            ->orderRelationship('links')
581
            ->where('slug', $slug);
582
    }
583
584
    /**
585
     * Return images with all props needed for javascript.
586
     *
587
     * @return Collection
588
     */
589
    public function imagesWithProps()
590
    {
591
        return $this->images
1 ignored issue
show
Documentation introduced by
The property images does not exist on object<Larafolio\Models\Project>. 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...
592
            ->map(function (Image $image) {
593
                return $image->generateProps();
594
            })->reverse()->values();
595
    }
596
597
    /**
598
     * Order given relationship by order value.
599
     *
600
     * @param \Builder $query        Query builder.
601
     * @param string   $relationship Name of relationship to order.
602
     *
603
     * @return \Builder
604
     */
605
    public function scopeOrderRelationship($query, $relationship)
606
    {
607
        return $query->with([$relationship => function ($query) {
608
            $query->orderBy('order');
609
        }]);
610
    }
611
612
    /**
613
     * Return project properties to be passed to js.
614
     *
615
     * @return array
616
     */
617
    public function generateProps()
618
    {
619
        return [
620
            'deletedAt' => $this->deleted_at->diffForHumans(),
1 ignored issue
show
Documentation introduced by
The property deleted_at does not exist on object<Larafolio\Models\Project>. 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...
621
            'id'        => $this->id(),
622
            'name'      => $this->name(),
623
            'slug'      => $this->slug(),
624
        ];
625
    }
626
}
627