Post   B
last analyzed

Complexity

Total Complexity 43

Size/Duplication

Total Lines 393
Duplicated Lines 0 %

Importance

Changes 4
Bugs 1 Features 1
Metric Value
wmc 43
eloc 87
dl 0
loc 393
rs 8.96
c 4
b 1
f 1

29 Methods

Rating   Name   Duplication   Size   Complexity  
A has_image() 0 3 1
A imageUrl() 0 6 1
A authorString() 0 13 2
A search_result_page_url() 0 3 1
A check_valid_image_size() 0 3 1
A post_body_output() 0 3 1
A genSeoTitle() 0 7 2
A gen_seo_title() 0 3 1
A image_tag() 0 6 1
A author() 0 3 1
A categories() 0 7 1
A url() 0 3 1
A sluggable() 0 5 1
A hasImage() 0 5 2
A comments() 0 3 1
A boot() 0 10 1
A full_view_file_path() 0 3 1
A renderBody() 0 20 6
A imageTag() 0 17 3
A image_url() 0 3 1
A bladeViewFile() 0 7 2
A author_string() 0 3 1
A generate_introduction() 0 3 1
A generateIntroduction() 0 10 2
A editUrl() 0 3 1
A edit_url() 0 3 1
A isPublic() 0 3 2
A search_result_page_title() 0 3 1
A checkValidImageSize() 0 7 2

How to fix   Complexity   

Complex Class

Complex classes like Post 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.

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 Post, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace WebDevEtc\BlogEtc\Models;
4
5
use App\User;
6
use Carbon\Carbon;
7
use Cviebrock\EloquentSluggable\Sluggable;
8
use Illuminate\Database\Eloquent\Model;
9
use Illuminate\Database\Eloquent\Relations\BelongsTo;
10
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
11
use Illuminate\Database\Eloquent\Relations\HasMany;
12
use Illuminate\Support\Str;
13
use InvalidArgumentException;
14
use RuntimeException;
15
use WebDevEtc\BlogEtc\Interfaces\SearchResultInterface;
16
use WebDevEtc\BlogEtc\Scopes\BlogEtcPublishedScope;
17
18
/**
19
 * Class BlogEtcPost.
20
 */
21
class Post extends Model implements SearchResultInterface
22
{
23
    use Sluggable;
24
25
    /**
26
     * @var array
27
     */
28
    public $casts = [
29
        'posted_at' => 'datetime',
30
        'is_published' => 'boolean',
31
    ];
32
    /**
33
     * @var array
34
     */
35
    public $dates = [
36
        'posted_at',
37
    ];
38
    /**
39
     * @var array
40
     */
41
    public $fillable = [
42
        'title',
43
        'subtitle',
44
        'short_description',
45
        'post_body',
46
        'seo_title',
47
        'meta_desc',
48
        'slug',
49
        'use_view_file',
50
        'is_published',
51
        'posted_at',
52
    ];
53
54
    protected $table = 'blog_etc_posts';
55
56
    protected static function boot()
57
    {
58
        parent::boot();
59
60
//        static::$authorNameResolver = config('blogetc.comments.user_field_for_author_name');
61
62
        /* If user is logged in and \Auth::user()->canManageBlogEtcPosts() == true, show any/all posts.
63
           otherwise (which will be for most users) it should only show published posts that have a posted_at
64
           time <= Carbon::now(). This sets it up: */
65
        static::addGlobalScope(new BlogEtcPublishedScope());
66
    }
67
68
    public function isPublic(): bool
69
    {
70
        return $this->is_published && $this->posted_at->lte(Carbon::now());
71
    }
72
73
    /**
74
     * Return the sluggable configuration array for this model.
75
     */
76
    public function sluggable(): array
77
    {
78
        return [
79
            'slug' => [
80
                'source' => 'title',
81
            ],
82
        ];
83
    }
84
85
    /**
86
     * @deprecated
87
     */
88
    public function search_result_page_url()
89
    {
90
        return $this->url();
91
    }
92
93
    /**
94
     * Returns the public facing URL to view this blog post.
95
     */
96
    public function url(): string
97
    {
98
        return route('blogetc.single', $this->slug);
99
    }
100
101
    public function search_result_page_title()
102
    {
103
        return $this->title;
104
    }
105
106
    /**
107
     * The associated author (if user_id) is set.
108
     */
109
    public function author(): BelongsTo
110
    {
111
        return $this->belongsTo(config('blogetc.user_model', User::class), 'user_id');
112
    }
113
114
    /**
115
     * The associated categories relationship for this blog post.
116
     */
117
    public function categories(): BelongsToMany
118
    {
119
        return $this->belongsToMany(
120
            Category::class,
121
            'blog_etc_post_categories',
122
            'blog_etc_post_id',
123
            'blog_etc_category_id'
124
        );
125
    }
126
127
    /**
128
     * Comments relationship for this post.
129
     */
130
    public function comments(): HasMany
131
    {
132
        return $this->hasMany(Comment::class, 'blog_etc_post_id');
133
    }
134
135
    /**
136
     * @deprecated - use genSeoTitle() instead
137
     */
138
    public function gen_seo_title(): ?string
139
    {
140
        return $this->genSeoTitle();
141
    }
142
143
    /**
144
     * If $this->seo_title was set, return that.
145
     * Otherwise just return $this->title.
146
     *
147
     * Basically return $this->seo_title ?? $this->title;
148
     *
149
     * TODO - what convention do we use for gen/generate/etc for naming of this.
150
     *
151
     * @return string
152
     */
153
    public function genSeoTitle(): ?string
154
    {
155
        if ($this->seo_title) {
156
            return $this->seo_title;
157
        }
158
159
        return $this->title;
160
    }
161
162
    /**
163
     * @param mixed ...$args
164
     *
165
     * @deprecated - use imageTag() instead
166
     */
167
    public function image_tag($size = 'medium',
168
        $addAHref = true,
169
        $imgTagClass = null,
170
        $anchorTagClass = null)
171
    {
172
        return $this->imageTag($size, $addAHref, $imgTagClass, $anchorTagClass);
173
    }
174
175
    /**
176
     * Generate a full <img src='' alt=''> img tag.
177
     *
178
     * TODO - return HtmlString
179
     *
180
     * @param string $size - large, medium, thumbnail
181
     * @param bool $addAHref - if true then it will add <a href=''>...</a> around the <img> tag
182
     * @param string|null $imgTagClass - if you want any additional CSS classes for this tag for the <IMG>
183
     * @param string|null $anchorTagClass - is you want any additional CSS classes in the <a> anchor tag
184
     */
185
    public function imageTag(
186
        $size = 'medium',
187
        $addAHref = true,
188
        $imgTagClass = null,
189
        $anchorTagClass = null
190
    ) {
191
        if (!$this->hasImage($size)) {
192
            return '';
193
        }
194
195
        $imageUrl = e($this->imageUrl($size));
196
        $imageAltText = e($this->title);
197
        $imgTag = '<img src="'.$imageUrl.'" alt="'.$imageAltText.'" class="'.e($imgTagClass).'">';
198
199
        return $addAHref
200
            ? '<a class="'.e($anchorTagClass).'" href="'.e($this->url()).'">'.$imgTag.'</a>'
201
            : $imgTag;
202
    }
203
204
    /**
205
     * Returns true if the database record indicates that this blog post
206
     * has a featured image of size $size.
207
     *
208
     * @param string $size
209
     */
210
    public function hasImage($size = 'medium'): bool
211
    {
212
        $this->checkValidImageSize($size);
213
214
        return array_key_exists('image_'.$size, $this->getAttributes()) && $this->{'image_'.$size};
215
    }
216
217
    /**
218
     * Throws an exception if $size is not valid
219
     * It should be either 'large','medium','thumbnail'.
220
     *
221
     * @throws InvalidArgumentException
222
     */
223
    protected function checkValidImageSize(string $size = 'medium'): bool
224
    {
225
        if (array_key_exists('image_'.$size, config('blogetc.image_sizes', []))) {
226
            return true;
227
        }
228
229
        throw new InvalidArgumentException('BlogEtcPost image size should be \'large\', \'medium\', \'thumbnail\''.' or another field as defined in config/blogetc.php. Provided size ('.e($size).') is not valid');
230
    }
231
232
    /**
233
     * Get the full URL for an image
234
     * You should use ::has_image($size) to check if the size is valid.
235
     *
236
     * @param string $size - should be 'medium' , 'large' or 'thumbnail'
237
     */
238
    public function imageUrl($size = 'medium'): string
239
    {
240
        $this->checkValidImageSize($size);
241
        $filename = $this->{'image_'.$size};
242
243
        return asset(config('blogetc.blog_upload_dir', 'blog_images').'/'.$filename);
244
//        return UploadsService::publicUrl($filename);
245
    }
246
247
    /**
248
     * @deprecated - use hasImage() instead
249
     */
250
    public function has_image($size = 'medium'): bool
251
    {
252
        return $this->hasImage($size);
253
    }
254
255
    /**
256
     * @deprecated - use authorString() instead
257
     */
258
    public function author_string(): ?string
259
    {
260
        return $this->authorString();
261
    }
262
263
    /**
264
     * Return author string (either from the User (via ->user_id), or the submitted author_name value.
265
     *
266
     * @return string
267
     */
268
    public function authorString(): ?string
269
    {
270
        // TODO
271
//        if ($this->author) {
272
//            return is_callable(self::$authorNameResolver)
273
//                ? call_user_func(self::$authorNameResolver, $this->author)
274
//                : $this->author->{self::$authorNameResolver};
275
//        }
276
        if ($this->author) {
0 ignored issues
show
Bug introduced by
The property author does not seem to exist on WebDevEtc\BlogEtc\Models\Post. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
277
            return (string) optional($this->author)->name;
278
        }
279
280
        return 'Unknown Author';
281
    }
282
283
    /**
284
     * @deprecated - use editUrl() instead
285
     */
286
    public function edit_url(): string
287
    {
288
        return $this->editUrl();
289
    }
290
291
    /**
292
     * Return the URL for editing the post (used for admin users).
293
     */
294
    public function editUrl(): string
295
    {
296
        return route('blogetc.admin.edit_post', $this->id);
297
    }
298
299
    /**
300
     * @deprecated - use bladeViewFile() instead
301
     */
302
    public function full_view_file_path(): string
303
    {
304
        return $this->bladeViewFile();
305
    }
306
307
    /**
308
     * If $this->user_view_file is not empty, then it'll return the dot syntax
309
     * location of the blade file it should look for.
310
     */
311
    public function bladeViewFile(): string
312
    {
313
        if (!$this->use_view_file) {
314
            throw new RuntimeException('use_view_file was empty, so cannot use bladeViewFile()');
315
        }
316
317
        return 'custom_blog_posts.'.$this->use_view_file;
318
    }
319
320
    /**
321
     * @deprecated - use imageUrl() instead
322
     */
323
    public function image_url($size = 'medium'): string
324
    {
325
        return $this->imageUrl($size);
326
    }
327
328
    /**
329
     * @deprecated - use generateIntroduction() instead
330
     */
331
    public function generate_introduction(int $maxLen = 500): string
332
    {
333
        return $this->generateIntroduction($maxLen);
334
    }
335
336
    /**
337
     * Generate an introduction, max length $max_len characters.
338
     */
339
    public function generateIntroduction(int $maxLen = 500): string
340
    {
341
        $base_text_to_use = $this->short_description;
342
343
        if (!trim($base_text_to_use)) {
344
            $base_text_to_use = $this->post_body;
345
        }
346
        $base_text_to_use = strip_tags($base_text_to_use);
347
348
        return Str::limit($base_text_to_use, $maxLen);
349
    }
350
351
    /**
352
     * @deprecated - use renderBody() instead
353
     */
354
    public function post_body_output()
355
    {
356
        return $this->renderBody();
357
    }
358
359
    /**
360
     * Return post body HTML, ready for output.
361
     *
362
     * TODO: return HtmlString
363
     *
364
     * @throws Throwable
365
     */
366
    public function renderBody()
367
    {
368
        if ($this->use_view_file && config('blogetc.use_custom_view_files')) {
369
            $return = (string) view('blogetc::partials.use_view_file', ['post' => $this])->render();
370
        } else {
371
            $return = $this->post_body;
372
        }
373
374
        if (!config('blogetc.echo_html')) {
375
            if (config('blogetc.strip_html')) {
376
                $return = strip_tags($return);
377
            }
378
379
            $return = e($return);
380
            if (config('blogetc.auto_nl2br')) {
381
                $return = nl2br($return);
382
            }
383
        }
384
385
        return $return;
386
        // New logic todo:
387
//        $body = $this->use_view_file && config('blogetc.use_custom_view_files')
388
//            ? view('blogetc::partials.use_view_file', ['post' => $this])->render()
389
//            : $this->post_body;
390
//
391
//        if (!config('blogetc.echo_html')) {
392
//            // if this is not true, then we should escape the output
393
//            if (config('blogetc.strip_html')) {
394
//                // not perfect, but it will get wrapped in htmlspecialchars in e() anyway
395
//                $body = strip_tags($body);
396
//            }
397
//
398
//            $body = e($body);
399
//
400
//            if (config('blogetc.auto_nl2br')) {
401
//                $body = nl2br($body);
402
//            }
403
//        }
404
//
405
//        return new HtmlString($body);
406
    }
407
408
    /**
409
     * @deprecated - use checkValidImageSize()
410
     */
411
    protected function check_valid_image_size(string $size = 'medium'): bool
412
    {
413
        return $this->checkValidImageSize($size);
414
    }
415
}
416