Completed
Push — master ( 6524bd...3580eb )
by Angus
13:20
created

Tracker_List_Model::update()   C

Complexity

Conditions 10
Paths 9

Size

Total Lines 56
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 0
Metric Value
cc 10
eloc 37
nc 9
nop 5
dl 0
loc 56
rs 6.7741
c 0
b 0
f 0
ccs 0
cts 0
cp 0
crap 110

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 115
	public function __construct() {
5 115
		parent::__construct();
6 115
	}
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
			//FIXME: This is not good for speed, but we're kind of required to do this for UX purposes.
65
			//       Tablesorter has a weird sorting algorithm and has a delay before sorting which is why I'd like to avoid it.
66
			//FIXME: Is it possible to reduce duplication here without reducing speed?
67
			$sortOrder = $this->User_Options->get('list_sort_order');
68
			switch($this->User_Options->get('list_sort_type')) {
69
				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...
70
					foreach (array_keys($arr['series']) as $category) {
71
						usort($arr['series'][$category]['manga'], function ($a, $b) use($sortOrder) {
72
							$a_text = strtolower("{$a['new_chapter_exists']} - {$a['title_data']['title']}");
73
							$b_text = strtolower("{$b['new_chapter_exists']} - {$b['title_data']['title']}");
74
75
							if($sortOrder == 'asc') {
76
								return $a_text <=> $b_text;
77
							} else {
78
								return $b_text <=> $a_text;
79
							}
80
						});
81
					}
82
					break;
83
84 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...
85
					foreach (array_keys($arr['series']) as $category) {
86
						usort($arr['series'][$category]['manga'], function($a, $b) use($sortOrder) {
87
							$a_text = strtolower("{$a['title_data']['title']}");
88
							$b_text = strtolower("{$b['title_data']['title']}");
89
90
							if($sortOrder == 'asc') {
91
								return $a_text <=> $b_text;
92
							} else {
93
								return $b_text <=> $a_text;
94
							}
95
						});
96
					}
97
					break;
98
99 View Code Duplication
				case 'my_status':
100
					foreach (array_keys($arr['series']) as $category) {
101
						usort($arr['series'][$category]['manga'], function($a, $b) use($sortOrder) {
102
							$a_text = strtolower("{$a['generated_current_data']['number']}");
103
							$b_text = strtolower("{$b['generated_current_data']['number']}");
104
105
							if($sortOrder == 'asc') {
106
								return $a_text <=> $b_text;
107
							} else {
108
								return $b_text <=> $a_text;
109
							}
110
						});
111
					}
112
					break;
113
114 View Code Duplication
				case 'latest':
115
					foreach (array_keys($arr['series']) as $category) {
116
						usort($arr['series'][$category]['manga'], function($a, $b) use($sortOrder) {
117
							$a_text = strtolower("{$a['generated_latest_data']['number']}");
118
							$b_text = strtolower("{$b['generated_latest_data']['number']}");
119
120
							if($sortOrder == 'asc') {
121
								return $a_text <=> $b_text;
122
							} else {
123
								return $b_text <=> $a_text;
124
							}
125
						});
126
					}
127
					break;
128
129
				default:
130
					break;
131
			}
132
		}
133
		return $arr;
134
	}
135
136
137
	public function update(int $userID, string $site, string $title, string $chapter, bool $active = TRUE) : bool {
138
		$success = FALSE;
139
		if($siteData = $this->Tracker->title->getSiteDataFromURL($site)) {
140
			//Validate user input
141
			if(!$this->sites->{$siteData->site_class}) {
142
				log_message('error', "{$siteData->site_class} Class doesn't exist?");
143
				return FALSE;
144
			}
145
			if(!$this->sites->{$siteData->site_class}->isValidTitleURL($title)) {
146
				//Error is already logged via isValidTitleURL
147
				return FALSE;
148
			}
149
			if(!$this->sites->{$siteData->site_class}->isValidChapter($chapter)) {
150
				//Error is already logged via isValidChapter
151
				return FALSE;
152
			}
153
154
			//NOTE: If the title doesn't exist it will be created. This maybe isn't perfect, but it works for now.
155
			$titleID = $this->Tracker->title->getID($title, (int) $siteData->id);
156
			if($titleID === 0) {
157
				//Something went wrong.
158
				log_message('error', "TitleID = 0 for {$title} @ {$siteData->id}");
159
				return FALSE;
160
			}
161
162
			$idQuery = $this->db->select('id')
163
			                    ->where('user_id', $userID)
164
			                    ->where('title_id', $titleID)
165
			                    ->get('tracker_chapters');
166
			if($idQuery->num_rows() > 0) {
167
				$success = (bool) $this->db->set(['current_chapter' => $chapter, 'active' => 'Y', 'last_updated' => NULL])
168
				                           ->where('user_id', $userID)
169
				                           ->where('title_id', $titleID)
170
				                           ->update('tracker_chapters');
171
172
				if($success) {
173
					$idQueryRow = $idQuery->row();
174
					$this->History->userUpdateTitle((int) $idQueryRow->id, $chapter);
175
				}
176
			} else {
177
				$category = $this->User_Options->get_by_userid('default_series_category', $userID);
178
				$success = (bool) $this->db->insert('tracker_chapters', [
179
					'user_id'         => $userID,
180
					'title_id'        => $titleID,
181
					'current_chapter' => $chapter,
182
					'category'        => $category,
183
					'active'          => ($active ? 'Y' : 'N')
184
				]);
185
186
				if($success) {
187
					$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...
188
				}
189
			}
190
		}
191
		return $success;
192
	}
193
	public function updateByID(int $userID, int $chapterID, string $chapter) : bool {
194
		$success = (bool) $this->db->set(['current_chapter' => $chapter, 'active' => 'Y', 'last_updated' => NULL])
195
		                           ->where('user_id', $userID)
196
		                           ->where('id', $chapterID)
197
		                           ->update('tracker_chapters');
198
199
		if($success) {
200
			$this->History->userUpdateTitle($chapterID, $chapter);
201
		}
202
		return  $success;
203
	}
204
205 View Code Duplication
	public function deleteByID(int $userID, int $chapterID) {
206
		//Series are not fully deleted, they are just marked as inactive as to hide them from the user.
207
		//This is to allow user history to function properly.
208
209
		$success = $this->db->set(['active' => 'N', 'last_updated' => NULL])
210
		                    ->where('user_id', $userID)
211
		                    ->where('id', $chapterID)
212
		                    ->update('tracker_chapters');
213
214
		return (bool) $success;
215
	}
216
	public function deleteByIDList(array $idList) : array {
217
		/*
218
		 * 0 = Success
219
		 * 1 = Invalid IDs
220
		 */
221
		$status = ['code' => 0];
222
223 View Code Duplication
		foreach($idList as $id) {
224
			if(!(ctype_digit($id) && $this->deleteByID($this->User->id, (int) $id))) {
225
				$status['code'] = 1;
226
			} else {
227
				//Delete was successful, update history too.
228
				$this->History->userRemoveTitle((int) $id);
229
			}
230
		}
231
232
		return $status;
233
	}
234
}
235