EpisodesComponent   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 274
Duplicated Lines 12.04 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 21
c 1
b 0
f 0
lcom 1
cbo 5
dl 33
loc 274
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A componentDetails() 0 7 1
A defineProperties() 0 56 1
A onRun() 0 21 4
A setState() 0 9 2
A loadShow() 10 10 2
B loadEpisodes() 0 42 5
A getEpisodePageOptions() 0 4 1
A getEpisodeURL() 0 5 1
A getTitlePlaceholderReplaces() 0 6 1
A setMetaTags() 23 23 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php namespace CosmicRadioTV\Podcast\Components;
2
3
use Cms\Classes\Page;
4
use CosmicRadioTV\Podcast\Classes\ComponentBase;
5
use CosmicRadioTV\Podcast\Classes\TitlePlaceholdersTrait;
6
use CosmicRadioTV\Podcast\Models\Episode;
7
use CosmicRadioTV\Podcast\Models\Show;
8
use CosmicRadioTV\Podcast\Models\Tag;
9
use Illuminate\Database\Eloquent\Collection;
10
use Illuminate\Database\Eloquent\ModelNotFoundException;
11
use Illuminate\Pagination\LengthAwarePaginator;
12
use October\Rain\Database\Builder;
13
use URL;
14
15
/**
16
 * Component that lists all of the episodes of a show
17
 *
18
 * @package CosmicRadioTV\Podcast\Components
19
 */
20
class EpisodesComponent extends ComponentBase
21
{
22
23
    use TitlePlaceholdersTrait;
24
25
    /**
26
     * @var bool
27
     */
28
    public $allowPagination;
29
30
    /**
31
     * @var LengthAwarePaginator|Collection|Episode[] Paginator instance of all of the episodes
32
     */
33
    public $episodes;
34
35
    /**
36
     * @var string[]
37
     */
38
    public $meta_tags = [];
39
40
    /**
41
     * @var Show The show being displayed
42
     */
43
    public $show;
44
    /**
45
     * @var Tag Tag to filter episodes by
46
     */
47
    public $tag;
48
49
    /**
50
     * Component Details
51
     *
52
     * @return array
53
     */
54
    public function componentDetails()
55
    {
56
        return [
57
            'name'        => 'cosmicradiotv.podcast::components.episodes.name',
58
            'description' => 'cosmicradiotv.podcast::components.episodes.description',
59
        ];
60
    }
61
62
    /**
63
     * User editable properties
64
     *
65
     * @return array
66
     */
67
    public function defineProperties()
68
    {
69
        return [
70
            'showSlug'        => [
71
                'title'       => 'cosmicradiotv.podcast::components.common.properties.show_slug.title',
72
                'description' => 'cosmicradiotv.podcast::components.episodes.properties.show_slug.description',
73
                'default'     => '{{ :show_slug }}',
74
                'type'        => 'string',
75
                'group'       => trans('cosmicradiotv.podcast::components.episodes.groups.filters'),
76
            ],
77
            'tagSlug'         => [
78
                'title'       => 'cosmicradiotv.podcast::components.common.properties.tag_slug.title',
79
                'description' => 'cosmicradiotv.podcast::components.episodes.properties.tag_slug.description',
80
                'default'     => '',
81
                'type'        => 'string',
82
                'group'       => trans('cosmicradiotv.podcast::components.episodes.groups.filters'),
83
            ],
84
            'episodePage'     => [
85
                'title'       => 'cosmicradiotv.podcast::components.episodes.properties.episode_page.title',
86
                'description' => 'cosmicradiotv.podcast::components.episodes.properties.episode_page.description',
87
                'type'        => 'dropdown',
88
                'default'     => 'podcast/episode',
89
                'required'    => true,
90
                'group'       => trans('cosmicradiotv.podcast::components.episodes.groups.links'),
91
            ],
92
            'perPage'         => [
93
                'title'             => 'cosmicradiotv.podcast::components.episodes.properties.per_page.title',
94
                'description'       => 'cosmicradiotv.podcast::components.episodes.properties.per_page.description',
95
                'default'           => 10,
96
                'type'              => 'string',
97
                'validationPattern' => '^[0-9]+$',
98
                'validationMessage' => trans('cosmicradiotv.podcast::components.episodes.properties.per_page.validationMessage'),
99
                'required'          => true,
100
                'group'             => trans('cosmicradiotv.podcast::components.episodes.groups.pagination')
101
            ],
102
            'allowPagination' => [
103
                'title'       => 'cosmicradiotv.podcast::components.episodes.properties.allow_pagination.title',
104
                'description' => 'cosmicradiotv.podcast::components.episodes.properties.allow_pagination.description',
105
                'default'     => true,
106
                'type'        => 'checkbox',
107
                'group'       => trans('cosmicradiotv.podcast::components.episodes.groups.pagination')
108
            ],
109
            'updateTitle'     => [
110
                'title'       => 'cosmicradiotv.podcast::components.common.properties.update_title.title',
111
                'description' => 'cosmicradiotv.podcast::components.common.properties.update_title.description',
112
                'default'     => true,
113
                'type'        => 'checkbox',
114
            ],
115
            'metaTags'        => [
116
                'title'       => 'cosmicradiotv.podcast::components.common.properties.meta_tags.title',
117
                'description' => 'cosmicradiotv.podcast::components.common.properties.meta_tags.description',
118
                'default'     => false,
119
                'type'        => 'checkbox',
120
            ],
121
        ];
122
    }
123
124
    /**
125
     * Prepare component
126
     *
127
     * @returns null|string
128
     */
129
    public function onRun()
130
    {
131
        try {
132
            $this->setState();
133
        } catch (ModelNotFoundException $e) {
134
            // Show not found, return 404
135
            $this->controller->setStatusCode(404);
136
137
            return $this->controller->run('404');
138
        }
139
140
        if ($this->property('updateTitle')) {
141
            $this->updateTitle();
142
        }
143
144
        if ($this->property('metaTags')) {
145
            $this->setMetaTags();
146
        }
147
148
        return null;
149
    }
150
151
    /**
152
     * Set components state based on parameters
153
     *
154
     * @throws ModelNotFoundException
155
     */
156
    public function setState()
157
    {
158
        $this->allowPagination = (bool) $this->property('allowPagination');
159
        $this->show = $this->loadShow();
160
        if ($this->property('tagSlug')) {
161
            $this->tag = Tag::query()->where('slug', $this->property('tagSlug'))->firstOrFail();
162
        }
163
        $this->episodes = $this->loadEpisodes();
164
    }
165
166
    /**
167
     * If a show is requested by slug loads it, or null if all shows (left blank)
168
     *
169
     * @throws ModelNotFoundException
170
     * @return Show|null
171
     */
172 View Code Duplication
    protected function loadShow()
173
    {
174
        $slug = $this->property('showSlug');
175
176
        if ($slug) {
177
            return Show::query()->where('slug', $this->property('showSlug'))->firstOrFail();
178
        } else {
179
            return null;
180
        }
181
    }
182
183
    /**
184
     * Loads episodes for the current show (or all shows if not set
185
     *
186
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator|Collection|Episode[]
187
     */
188
    protected function loadEpisodes()
189
    {
190
        if ($this->show) {
191
            // Show's episodes
192
            $query = $this->show->episodes();
193
            $setShows = true; // Skips loading from database
194
        } else {
195
            // All shows' episodes
196
            $query = Episode::query();
197
            $query->with('show');
198
            $setShows = false;
199
        }
200
201
        $query->with('image')
202
              ->where('published', true)
203
              ->orderBy('release', 'desc');
204
205
        if ($this->tag) {
206
            $query->whereHas('tags', function (Builder $q) {
207
                $q->where('cosmicradiotv_podcast_tags.id', $this->tag->id);
208
            });
209
        }
210
211
        if ($this->allowPagination) {
212
            /** @var LengthAwarePaginator|Episode[] $returns */
213
            $returns = $query->paginate(intval($this->property('perPage')));
214
            $collection = $returns->getCollection();
215
        } else {
216
            $returns = $collection = $query->take($this->property('perPage'))->get();
217
        }
218
219
        $collection->each(function (Episode $episode) use ($setShows) {
220
            if ($setShows) {
221
                $episode->setRelation('show', $this->show);
222
            }
223
224
            // Cache URL value to the model
225
            $episode->url = $this->getEpisodeURL($episode);
226
        });
227
228
        return $returns;
229
    }
230
231
    /**
232
     * Gives values for Episode Page dropdown
233
     *
234
     * @return array
235
     */
236
    public function getEpisodePageOptions()
237
    {
238
        return Page::getNameList();
239
    }
240
241
    /**
242
     * Get episode's URL
243
     *
244
     * @param Episode $episode
245
     *
246
     * @return string
247
     */
248
    public function getEpisodeURL(Episode $episode)
249
    {
250
        return $this->controller->pageUrl($this->property('episodePage'),
251
            ['show_slug' => $episode->show->slug, 'episode_slug' => $episode->slug]);
252
    }
253
254
    /**
255
     * Things to replace placeholders with
256
     *
257
     * @return object
258
     */
259
    protected function getTitlePlaceholderReplaces()
260
    {
261
        return (object) [
262
            'show' => $this->show,
263
        ];
264
    }
265
266
    /**
267
     * Injects meta tags into the header
268
     */
269 View Code Duplication
    protected function setMetaTags()
270
    {
271
        // Show related tags
272
        if ($this->show) {
273
            $this->page->meta_title = $this->show->name;
274
            $this->page->meta_description = $this->show->description;
275
276
            // Extra meta tags, available via {% placeholder head %}
277
            $this->meta_tags = [
278
                'twitter:card'   => 'summary',
279
                'og:title'       => $this->show->name,
280
                'og:description' => $this->show->description,
281
                'og:type'        => 'video.tv_show',
282
                'og:url'         => $this->controller->currentPageUrl(),
283
            ];
284
285
            if ($this->show->image) {
286
                // Full path
287
                $this->meta_tags['og:image'] = URL::to($this->show->image->getPath());
288
            }
289
290
        }
291
    }
292
293
}