Completed
Push — master ( 4a1c4b...dec28d )
by Angus
03:08
created

User_Options_Model   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 279
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 14.09%

Importance

Changes 0
Metric Value
dl 0
loc 279
ccs 11
cts 78
cp 0.1409
rs 10
c 0
b 0
f 0
wmc 28
lcom 1
cbo 5

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A get() 0 5 2
A set() 0 29 5
A set_db() 0 11 2
A parse_value() 0 22 5
A generate_radio_array() 0 25 4
B get_by_userid() 0 22 6
A get_db() 0 24 3
1
<?php declare(strict_types=1); defined('BASEPATH') or exit('No direct script access allowed');
2
3
class User_Options_Model extends CI_Model {
4
	public $options = array(
5
		/** GENERAL OPTIONS **/
6
		'category_custom_1' => array(
7
			'default' => 'disabled',
8
			'type' => 'int',
9
			'valid_options' => array(
10
				0 => 'disabled',
11
				1 => 'enabled'
12
			)
13
		),
14
		'category_custom_2' => array(
15
			'default' => 'disabled',
16
			'type' => 'int',
17
			'valid_options' => array(
18
				0 => 'disabled',
19
				1 => 'enabled'
20
			)
21
		),
22
		'category_custom_3' => array(
23
			'default' => 'disabled',
24
			'type' => 'int',
25
			'valid_options' => array(
26
				0 => 'disabled',
27
				1 => 'enabled'
28
			)
29
		),
30
		'category_custom_1_text' => array(
31
			'default' => 'Custom 1',
32
			'type' => 'string'
33
		),
34
		'category_custom_2_text' => array(
35
			'default' => 'Custom 2',
36
			'type' => 'string'
37
		),
38
		'category_custom_3_text' => array(
39
			'default' => 'Custom 3',
40
			'type' => 'string'
41
		),
42
43
		'enable_live_countdown_timer' => array(
44
			'default' => 'enabled',
45
			'type' => 'int',
46
			'valid_options' => array(
47
				0 => 'disabled',
48
				1 => 'enabled'
49
			)
50
		),
51
52
		'default_series_category' => array(
53
			'default' => 'reading',
54
			'type' => 'int',
55
			'valid_options' => array(
56
				0 => 'reading',
57
				1 => 'on-hold',
58
				2 => 'plan-to-read',
59
60
				//FIXME: (MAJOR) This should only be enabled if the custom categories are enabled
61
				// Problem is we can't easily check for this since the userscript uses it's own UserID, and not $this->User->id
62
				3 => 'custom1',
63
				4 => 'custom2',
64
				5 => 'custom3'
65
			)
66
		),
67
68
		'list_sort_type' => array(
69
			'default' => 'unread',
70
			'type' => 'int',
71
			'valid_options' => array(
72
				0 => 'unread',
73
				1 => 'alphabetical',
74
				2 => 'my_status',
75
				3 => 'latest',
76
				4 => 'unread_latest'
77
			)
78
		),
79
80
		'list_sort_order' => array(
81
			'default' => 'asc',
82
			'type' => 'int',
83
			'valid_options' => array(
84
				0 => 'asc',
85
				1 => 'desc'
86
			)
87
		),
88
89
		'theme' => array(
90
			'default' => 'light',
91
			'type' => 'int',
92
			'valid_options' => array(
93
				0 => 'light',
94
				1 => 'dark'
95
			)
96
		),
97
98
		'enable_public_list' => array(
99
			'default' => 'disabled',
100
			'type' => 'int',
101
			'valid_options' => array(
102
				0 => 'disabled',
103
				1 => 'enabled'
104
			)
105
		),
106
107
		'mal_sync' => array(
108
			'default' => 'disabled',
109
			'type' => 'int',
110
			'valid_options' => array(
111
				0 => 'disabled',
112
				1 => 'csrf',
113
				2 => 'api'
114
			)
115
		),
116
	);
117
118 96
	public function __construct() {
119 96
		parent::__construct();
120 96
	}
121
122
	/**
123
	 * Get user option, or default option if it does not exist.
124
	 *
125
	 * @param string   $option
126
	 * @param int|null $userID
127
	 *
128
	 * @return mixed Returns option value as STRING, or FALSE if option does not exist.
129
	 */
130 96
	public function get(string $option, ?int $userID = NULL) {
131 96
		$userID = (is_null($userID) ? (int) $this->User->id : $userID);
132
133 96
		return $this->get_by_userid($option, $userID);
134
	}
135
136
	/**
137
	 * @param string     $option
138
	 * @param string|int $value
139
	 *
140
	 * @return bool
141
	 */
142
	public function set(string $option, $value) : bool {
143
		//Check if user is logged in & set ID if so
144
		if($userID = $this->User->id) {
0 ignored issues
show
Unused Code introduced by
$userID is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
145
			//Check if option is valid
146
			if(array_key_exists($option, $this->options)) {
147
				//option is valid
148
149
				$idData = array(
150
					'user_id' => $this->User->id,
151
					'name'    => $option,
152
				);
153
154
				$valueData = array();
155
				if($this->options[$option]['type'] == 'int') {
156
					$valueData['value_int'] = array_search($value, $this->options[$option]['valid_options']);
157
				} else {
158
					$valueData['value_str'] = (string) $value;
159
				}
160
161
				$success = $this->set_db($idData, $valueData);
162
				if($success) $this->session->unset_tempdata("option_{$option}");
163
			} else {
164
				$success = FALSE;
165
			}
166
		} else {
167
			$success = FALSE;
168
		}
169
		return $success;
170
	}
171
172 96
	private function get_by_userid(string $option, int $userID) {
173
		//Check if option is valid
174 96
		if(array_key_exists($option, $this->options)) {
175
			//Check if userID is > 0
176 96
			if($userID) {
177
				//Check if user has option set.
178
				if($row = $this->get_db($option, $userID)) {
179
					//User has option set, get proper value.
180
					if($userValue = $this->parse_value($option, $row['value_str'], $row['value_int'])) {
181
						//Value is valid. Everything is good.
182
						$value = $userValue;
183
					}
184
				}
185
			}
186
187
			//Overall fallback method.
188 96
			if(!isset($value)) $value = $this->options[$option]['default'];
189
		} else {
190
			$value = FALSE;
191
		}
192 96
		return $value;
193
	}
194
195
	private function get_db(string $option, int $userID) {
196
		//This function assumes we've already done some basic validation.
197
198
		//FIXME: Query duplication.
199
		if($this->User->id !== $userID) {
200
			$query = $this->db->select('value_str, value_int')
201
			                  ->from('user_options')
202
			                  ->where('user_id', $userID)
203
			                  ->where('name',    $option)
204
			                  ->limit(1);
205
			$data = $query->get()->row_array();
206
		} else {
207
			if(!($data = $this->session->tempdata("option_{$option}"))) {
208
				$query = $this->db->select('value_str, value_int')
209
				                  ->from('user_options')
210
				                  ->where('user_id', $userID)
211
				                  ->where('name',    $option)
212
				                  ->limit(1);
213
				$data = $query->get()->row_array();
214
				$this->session->set_tempdata("option_{$option}", $data, 3600);
215
			}
216
		}
217
		return $data;
218
	}
219
220
	private function set_db(array $idData, array $valueData) : bool {
221
		if($this->db->get_where('user_options', $idData)->num_rows() === 0) {
0 ignored issues
show
Documentation introduced by
$idData is of type array, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
222
			//$data['type'] = (isset($a['value_int']) ? 0 : (isset($a['value_str']) == 'string' ? 1 : 2)); //FIXME: How does this work now?
223
			$success = $this->db->insert('user_options', array_merge($idData, $valueData));
224
		} else {
225
			$this->db->where($idData);
226
			$success = $this->db->update('user_options', $valueData);
227
		}
228
229
		return $success;
230
	}
231
232
	private function parse_value(string $option, $value_str, $value_int) {
233
		$type = $this->options[$option]['type'];
234
235
		switch($type) {
236
			case 'int':
237
				//TODO: How exactly should we handle INT? Just DB side?
238
				if(in_array($value_int, array_keys($this->options[$option]['valid_options']))) {
239
					$value = $this->options[$option]['valid_options'][$value_int];
240
				}
241
				break;
242
			case 'string':
243
				//TODO: We should have some basically XSS checking here?
244
				$value = (string) $value_str;
245
				break;
246
			default:
247
				//This should never happen.
248
				break;
249
		}
250
		if(!isset($value)) $value = FALSE; //FIXME: This won't play nice with BOOL type false?
251
252
		return $value;
253
	}
254
255
	//Used to quickly generate an array used with form_radio.
256
	public function generate_radio_array(string $option, string $selected_option) {
257
		if(array_key_exists($option, $this->options)) {
258
			$base_attributes = array(
259
				'name' => $option,
260
				'id'   => $option
261
			);
262
			//FIXME: Get a better solution than str_replace for removing special characters
263
			$elements = array();
264
			foreach (array_values($this->options[$option]['valid_options']) as $valid_option) {
265
				$elements[$option.'_'.str_replace(',', '_', $valid_option)] = array_merge($base_attributes, array(
266
					'value' => $valid_option
267
				));
268
			}
269
			if(isset($elements[$option.'_'.str_replace(',', '_', $selected_option)])) {
270
				$elements[$option.'_'.str_replace(',', '_', $selected_option)]['checked'] = TRUE;
271
			} else {
272
				//This should never occur, but fallbacks are always a good idea..
273
				$elements[$option.'_'.$this->options[$option]['default']]['checked'] = TRUE;
274
			}
275
			//CHECK: Should we attach this to body_data here?
276
			return $elements;
277
		} else {
278
			return FALSE;
279
		}
280
	}
281
}
282