Episode   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 178
Duplicated Lines 7.87 %

Coupling/Cohesion

Components 2
Dependencies 0

Importance

Changes 7
Bugs 3 Features 1
Metric Value
wmc 16
c 7
b 3
f 1
lcom 2
cbo 0
dl 14
loc 178
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A nextCached() 0 6 2
A previousCached() 0 6 2
A next() 7 7 2
A previous() 7 7 2
A beforeDelete() 0 4 1
B makeValidator() 0 16 5
A getSluggableUniqueAttributeValue() 0 20 2

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
2
3
namespace CosmicRadioTV\Podcast\Models;
4
5
6
use Carbon\Carbon;
7
use Illuminate\Database\Eloquent\Collection;
8
use October\Rain\Database\Model;
9
use October\Rain\Database\Traits\Sluggable;
10
use October\Rain\Database\Traits\Validation;
11
use System\Models\File;
12
use CosmicRadioTV\Podcast\Models\Release;
13
14
/**
15
 * Episode
16
 *
17
 * @package CosmicRadioTV\Podcast\Models
18
 * @property      int                  $id         ID
19
 * @property      int                  $show_id    Show's ID
20
 * @property      string               $title      Episode's title
21
 * @property      string               $slug       URL slug
22
 * @property      string               $summary    Episode description
23
 * @property      string               $content    Episode's Show notes
24
 * @property      int                  $length     Episode's length in seconds
25
 * @property      Carbon               $release    Episode's release time
26
 * @property      bool                 $published  Published state
27
 * @property      Carbon               $created_at Show creation time
28
 * @property      Carbon               $updated_at Show update time
29
 * @property-read Show                 $show       The show of this episode
30
 * @property-read Collection|Tag[]     $tags       Tags for this episode
31
 * @property-read Collection|Release[] $releases   Releases for this episode
32
 * @property      File                 $image      Shows image
33
 * @method \October\Rain\Database\Relations\BelongsTo show()
34
 * @method \October\Rain\Database\Relations\BelongsToMany tags()
35
 * @method \October\Rain\Database\Relations\HasMany releases()
36
 * @method \October\Rain\Database\Relations\MorphOne image()
37
 */
38
class Episode extends Model
39
{
40
41
    use Sluggable;
42
    use Validation {
43
        makeValidator as baseMakeValidator;
44
    }
45
46
    protected $table = 'cosmicradiotv_podcast_episodes';
47
48
    protected $slugs = ['slug' => 'title'];
49
50
    protected $dates = ['release'];
51
52
    protected $fillable = ['show_id', 'title', 'slug', 'summary', 'content', 'length', 'release', 'published'];
53
54
    public $rules = [
55
        'show_id'   => ['required', 'exists:cosmicradiotv_podcast_shows,id'],
56
        'title'     => ['required'],
57
        // Unique rule: NULL gets replaced with ID if exists, must have all 3 for show_id based bellow
58
        'slug'      => ['alpha_dash', 'unique:cosmicradiotv_podcast_episodes,slug,NULL'],
59
        'summary'   => [],
60
        'content'   => [],
61
        'length'    => ['numeric', 'min:0'],
62
        'release'   => ['date'],
63
        'published' => ['boolean']
64
    ];
65
66
    /*
67
     * Relations
68
     */
69
    public $belongsTo = [
70
        'show' => ['CosmicRadioTV\Podcast\Models\Show'],
71
    ];
72
73
    public $belongsToMany = [
74
        'tags' => ['CosmicRadioTV\Podcast\Models\Tag', 'table' => 'cosmicradiotv_podcast_episodes_tags'],
75
    ];
76
77
    // Needed this to properly display releases in the create/update episode form
78
    public $hasMany = [
79
        'releases' => ['CosmicRadioTV\Podcast\Models\Release'],
80
    ];
81
82
    public $attachOne = [
83
        'image' => ['System\Models\File']
84
    ];
85
86
    /**
87
     * @var string Where the URL for the episode can be cached to
88
     */
89
    public $url;
90
91
    /**
92
     * @var Array Stores the cached next episode data
93
     */
94
    protected $nextEpisodeCache = [true => null, false => null];
95
96
    /**
97
     * @var Array Stores the cached previous episode data
98
     */
99
    protected $previousEpisodeCache = [true => null, false => null];
100
101
    /**
102
     * Returns the next episode (cached for this instance)
103
     * @param  boolean $ofShow If true returns the next episode of the same show
104
     * @return Episode         The next episode
105
     */
106
    public function nextCached($ofShow = false) {
107
        if (empty($this->nextEpisodeCache[$ofShow])) {
108
            $this->nextEpisodeCache[$ofShow] = $this->next($ofShow);
109
        }
110
        return $this->nextEpisodeCache[$ofShow];
111
    }
112
113
    /**
114
     * Returns the previous episode (cached for this instance)
115
     * @param  boolean $ofShow If true returns the next episode of the same show
116
     * @return Episode         The previous episode
117
     */
118
    public function previousCached($ofShow = false) {
119
        if (empty($this->previousEpisodeCache[$ofShow])) {
120
            $this->previousEpisodeCache[$ofShow] = $this->previous($ofShow);
121
        }
122
        return $this->previousEpisodeCache[$ofShow];
123
    }
124
 
125
    /**
126
     * Returns the next episode
127
     * @param  boolean  $ofShow If true returns the next episode of the same show
128
     * @return Episode          The next episode
129
     */
130 View Code Duplication
    public function next($ofShow = false) {
131
        $query = self::query();
132
        if ($ofShow) {
133
            $query = $query->where('show_id',$this->show_id);
134
        }
135
        return $query->where('published',true)->where('release','>',$this->release)->orderBy('release','asc')->take(1)->get()->first();
136
    }
137
    /**
138
     * Returns the previous episode
139
     * @param  boolean  $ofShow If true returns the previous episode of the same show
140
     * @return Episode          The previous episode
141
     */
142 View Code Duplication
    public function previous($ofShow = false) {
143
        $query = self::query();
144
        if ($ofShow) {
145
            $query = $query->where('show_id',$this->show_id);
146
        }
147
        return $query->where('published',true)->where('release','<',$this->release)->orderBy('release','desc')->take(1)->get()->first();
148
    }
149
150
    /**
151
     * Runs before an episode is deleted to remove all the releases that depend on it
152
     */
153
    protected function beforeDelete()
154
    {
155
        Release::where('episode_id', '=', $this->id)->delete();
156
    }
157
158
    /**
159
     * Modifies validation rules so unique checks take show_id into account
160
     *
161
     * @param $data
162
     * @param $rules
163
     * @param $customMessages
164
     * @param $attributeNames
165
     *
166
     * @return \Illuminate\Validation\Validator
167
     */
168
    protected static function makeValidator($data, $rules, $customMessages, $attributeNames)
169
    {
170
        foreach ($rules as $field => $ruleParts) {
171
            foreach ($ruleParts as $key => $rulePart) {
172
                if (starts_with($rulePart, 'unique')) {
173
                    // Has format up to current instance's ID
174
                    if ($data['show_id']) {
175
                        $ruleParts[$key] .= ',id,show_id,' . $data['show_id'];
176
                    }
177
                }
178
            }
179
            $rules[$field] = $ruleParts;
180
        }
181
182
        return self::baseMakeValidator($data, $rules, $customMessages, $attributeNames);
183
    }
184
185
    /**
186
     * Modified unique slug finder to take into account the show_id
187
     *
188
     * @param string $name  The database column name.
189
     * @param string $value The desired column value.
190
     *
191
     * @return string A safe value that is unique.
192
     */
193
    protected function getSluggableUniqueAttributeValue($name, $value)
194
    {
195
        $counter = 1;
196
        $separator = $this->getSluggableSeparator();
197
198
        // Remove any existing suffixes
199
        //$_value = preg_replace('/' . preg_quote($separator) . '[0-9]+$/', '', trim($value));
200
201
        // Don't remove any existing suffixes
202
        // Test case: 'Episode 3' -> 'episode-3' -> 'episode'
203
        // Can end up in episode-3-2 when slug episode-3 doesn't exist but episode does (see line+5)
204
        $_value = $value;
205
206
        while ($this->newQuery()->where('show_id', $this->show_id)->where($name, $_value)->count() > 0) {
207
            $counter++;
208
            $_value = $value . $separator . $counter;
209
        }
210
211
        return $_value;
212
    }
213
214
215
}