Completed
Push — master ( fd57b4...81f48e )
by Angus
06:22
created

Tracker_List_Model   B

Complexity

Total Complexity 37

Size/Duplication

Total Lines 229
Duplicated Lines 26.64 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
dl 61
loc 229
ccs 3
cts 3
cp 1
rs 8.6
c 0
b 0
f 0
wmc 37
lcom 1
cbo 8

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
D get() 42 125 20
B update() 0 55 9
A updateByID() 0 11 2
A deleteByID() 11 11 1
A deleteByIDList() 8 18 4

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 declare(strict_types=1); defined('BASEPATH') OR exit('No direct script access allowed');
2
3
class Tracker_List_Model extends Tracker_Base_Model {
4 112
	public function __construct() {
5 112
		parent::__construct();
6 112
	}
7
8
	public function get() {
9
		$query = $this->db
10
			->select('tracker_chapters.*,
11
			          tracker_titles.site_id, tracker_titles.title, tracker_titles.title_url, tracker_titles.latest_chapter, tracker_titles.last_updated AS title_last_updated, tracker_titles.status AS title_status, tracker_titles.last_checked > DATE_SUB(NOW(), INTERVAL 1 WEEK) AS title_active,
12
			          tracker_sites.site, tracker_sites.site_class, tracker_sites.status AS site_status')
13
			->from('tracker_chapters')
14
			->join('tracker_titles', 'tracker_chapters.title_id = tracker_titles.id', 'left')
15
			->join('tracker_sites', 'tracker_sites.id = tracker_titles.site_id', 'left')
16
			->where('tracker_chapters.user_id', $this->User->id)
17
			->where('tracker_chapters.active', 'Y')
18
			->get();
19
20
		$arr = ['series' => [], 'has_inactive' => FALSE];
21
		foreach($this->enabledCategories as $category => $name) {
22
			$arr['series'][$category] = [
23
				'name'         => $name,
24
				'manga'        => [],
25
				'unread_count' => 0
26
			];
27
		}
28
		if($query->num_rows() > 0) {
29
			foreach ($query->result() as $row) {
30
				$is_unread     = intval($row->latest_chapter == $row->current_chapter ? '1' : '0');
31
				$arr['series'][$row->category]['unread_count'] = (($arr['series'][$row->category]['unread_count'] ?? 0) + !$is_unread);
32
				$data = [
33
					'id' => $row->id,
34
					'generated_current_data' => $this->sites->{$row->site_class}->getChapterData($row->title_url, $row->current_chapter),
35
					'generated_latest_data'  => $this->sites->{$row->site_class}->getChapterData($row->title_url, $row->latest_chapter),
36
					'full_title_url'        =>  $this->sites->{$row->site_class}->getFullTitleURL($row->title_url),
37
38
					'new_chapter_exists'    => $is_unread,
39
					'tag_list'              => $row->tags,
40
					'has_tags'              => !empty($row->tags),
41
42
					'title_data' => [
43
						'id'              => $row->title_id,
44
						'title'           => $row->title,
45
						'title_url'       => $row->title_url,
46
						'latest_chapter'  => $row->latest_chapter,
47
						'current_chapter' => $row->current_chapter,
48
						'last_updated'    => $row->title_last_updated,
49
						//NOTE: active is used to warn the user if a title hasn't updated (Maybe due to nobody active tracking it or other reasons).
50
						//      This will ONLY be false when an actively updating series (site enabled & title status = 0) hasn't updated within the past week.
51
						'active'          => ($row->site_status == 'disabled' || in_array($row->title_status, [/*complete*/ 1, /* one-shot */ 2, /* ignored */ 255]) || $row->title_active == 1)
52
					],
53
					'site_data' => [
54
						'id'         => $row->site_id,
55
						'site'       => $row->site,
56
						'status'     => $row->site_status
57
					]
58
				];
59
				$arr['series'][$row->category]['manga'][] = $data;
60
61
				if(!$arr['has_inactive']) $arr['has_inactive'] = !$data['title_data']['active'];
62
			}
63
64
			//CHECK: Is this good for speed?
65
			//NOTE: This does not sort in the same way as tablesorter, but it works better.
66
			switch($this->User_Options->get('list_sort_type')) {
67
				case 'unread':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
68
					foreach (array_keys($arr['series']) as $category) {
69
						usort($arr['series'][$category]['manga'], function ($a, $b) {
70
							$a_text = strtolower("{$a['new_chapter_exists']} - {$a['title_data']['title']}");
71
							$b_text = strtolower("{$b['new_chapter_exists']} - {$b['title_data']['title']}");
72
73
							if($this->User_Options->get('list_sort_order') == 'asc') {
74
								return $a_text <=> $b_text;
75
							} else {
76
								return $b_text <=> $a_text;
77
							}
78
						});
79
					}
80
					break;
81
82 View Code Duplication
				case 'alphabetical':
1 ignored issue
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
83
					foreach (array_keys($arr['series']) as $category) {
84
						usort($arr['series'][$category]['manga'], function ($a, $b) {
85
							$a_text = strtolower("{$a['title_data']['title']}");
86
							$b_text = strtolower("{$b['title_data']['title']}");
87
88
							if($this->User_Options->get('list_sort_order') == 'asc') {
89
								return $a_text <=> $b_text;
90
							} else {
91
								return $b_text <=> $a_text;
92
							}
93
						});
94
					}
95
					break;
96
97 View Code Duplication
				case 'my_status':
98
					foreach (array_keys($arr['series']) as $category) {
99
						usort($arr['series'][$category]['manga'], function ($a, $b) {
100
							$a_text = strtolower("{$a['generated_current_data']['number']}");
101
							$b_text = strtolower("{$b['generated_current_data']['number']}");
102
103
							if($this->User_Options->get('list_sort_order') == 'asc') {
104
								return $a_text <=> $b_text;
105
							} else {
106
								return $b_text <=> $a_text;
107
							}
108
						});
109
					}
110
					break;
111
112 View Code Duplication
				case 'latest':
113
					foreach (array_keys($arr['series']) as $category) {
114
						usort($arr['series'][$category]['manga'], function ($a, $b) {
115
							$a_text = strtolower("{$a['generated_latest_data']['number']}");
116
							$b_text = strtolower("{$b['generated_latest_data']['number']}");
117
118
							if($this->User_Options->get('list_sort_order') == 'asc') {
119
								return $a_text <=> $b_text;
120
							} else {
121
								return $b_text <=> $a_text;
122
							}
123
						});
124
					}
125
					break;
126
127
				default:
128
					break;
129
			}
130
		}
131
		return $arr;
132
	}
133
134
135
	public function update(int $userID, string $site, string $title, string $chapter) : bool {
136
		$success = FALSE;
137
		if($siteData = $this->Tracker->title->getSiteDataFromURL($site)) {
138
			//Validate user input
139
			if(!$this->sites->{$siteData->site_class}) {
140
				log_message('error', "{$siteData->site_class} Class doesn't exist?");
141
				return FALSE;
142
			}
143
			if(!$this->sites->{$siteData->site_class}->isValidTitleURL($title)) {
144
				//Error is already logged via isValidTitleURL
145
				return FALSE;
146
			}
147
			if(!$this->sites->{$siteData->site_class}->isValidChapter($chapter)) {
148
				//Error is already logged via isValidChapter
149
				return FALSE;
150
			}
151
152
			//NOTE: If the title doesn't exist it will be created. This maybe isn't perfect, but it works for now.
153
			$titleID = $this->Tracker->title->getID($title, (int) $siteData->id);
154
			if($titleID === 0) {
155
				//Something went wrong.
156
				log_message('error', "TitleID = 0 for {$title} @ {$siteData->id}");
157
				return FALSE;
158
			}
159
160
			$idQuery = $this->db->select('id')
161
			                    ->where('user_id', $userID)
162
			                    ->where('title_id', $titleID)
163
			                    ->get('tracker_chapters');
164
			if($idQuery->num_rows() > 0) {
165
				$success = (bool) $this->db->set(['current_chapter' => $chapter, 'active' => 'Y', 'last_updated' => NULL])
166
				                           ->where('user_id', $userID)
167
				                           ->where('title_id', $titleID)
168
				                           ->update('tracker_chapters');
169
170
				if($success) {
171
					$idQueryRow = $idQuery->row();
172
					$this->History->userUpdateTitle((int) $idQueryRow->id, $chapter);
173
				}
174
			} else {
175
				$category = $this->User_Options->get_by_userid('default_series_category', $userID);
176
				$success = (bool) $this->db->insert('tracker_chapters', [
177
					'user_id'         => $userID,
178
					'title_id'        => $titleID,
179
					'current_chapter' => $chapter,
180
					'category'        => $category
181
				]);
182
183
				if($success) {
184
					$this->History->userAddTitle((int) $this->db->insert_id(), $chapter, $category);
0 ignored issues
show
Bug introduced by
The method insert_id() does not exist on CI_DB_query_builder. Did you maybe mean insert()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
185
				}
186
			}
187
		}
188
		return $success;
189
	}
190
	public function updateByID(int $userID, int $chapterID, string $chapter) : bool {
191
		$success = (bool) $this->db->set(['current_chapter' => $chapter, 'active' => 'Y', 'last_updated' => NULL])
192
		                           ->where('user_id', $userID)
193
		                           ->where('id', $chapterID)
194
		                           ->update('tracker_chapters');
195
196
		if($success) {
197
			$this->History->userUpdateTitle($chapterID, $chapter);
198
		}
199
		return  $success;
200
	}
201
202 View Code Duplication
	public function deleteByID(int $userID, int $chapterID) {
203
		//Series are not fully deleted, they are just marked as inactive as to hide them from the user.
204
		//This is to allow user history to function properly.
205
206
		$success = $this->db->set(['active' => 'N', 'last_updated' => NULL])
207
		                    ->where('user_id', $userID)
208
		                    ->where('id', $chapterID)
209
		                    ->update('tracker_chapters');
210
211
		return (bool) $success;
212
	}
213
	public function deleteByIDList(array $idList) : array {
214
		/*
215
		 * 0 = Success
216
		 * 1 = Invalid IDs
217
		 */
218
		$status = ['code' => 0];
219
220 View Code Duplication
		foreach($idList as $id) {
221
			if(!(ctype_digit($id) && $this->deleteByID($this->User->id, (int) $id))) {
222
				$status['code'] = 1;
223
			} else {
224
				//Delete was successful, update history too.
225
				$this->History->userRemoveTitle((int) $id);
226
			}
227
		}
228
229
		return $status;
230
	}
231
}
232