rating   B
last analyzed

Complexity

Total Complexity 44

Size/Duplication

Total Lines 457
Duplicated Lines 0 %

Test Coverage

Coverage 50.78%

Importance

Changes 0
Metric Value
wmc 44
eloc 137
c 0
b 0
f 0
dl 0
loc 457
ccs 65
cts 128
cp 0.5078
rs 8.8798

14 Methods

Rating   Name   Duplication   Size   Complexity  
A album_data() 0 18 4
A is_allowed() 0 5 5
A loader() 0 10 3
A get_image_rating() 0 27 5
A image_data() 0 18 3
A __construct() 0 15 1
A is_able() 0 3 1
A delete_ratings() 0 23 3
A recalc_image_rating() 0 27 3
A display_box() 0 34 3
A get_user_rating() 0 21 4
A get_image_rating_value() 0 9 1
A submit_rating() 0 23 6
A insert_rating() 0 9 2

How to fix   Complexity   

Complex Class

Complex classes like rating often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use rating, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * phpBB Gallery - Core Extension
4
 *
5
 * @package   phpbbgallery/core
6
 * @author    nickvergessen
7
 * @author    satanasov
8
 * @author    Leinad4Mind
9
 * @copyright 2007-2012 nickvergessen, 2014- satanasov, 2018- Leinad4Mind
10
 * @license   GPL-2.0-only
11
 */
12
13
namespace phpbbgallery\core;
14
15
class rating
16
{
17
	/**
18
	* @var \phpbb\db\driver\driver_interface
0 ignored issues
show
Bug introduced by
The type phpbb\db\driver\driver_interface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
	*/
20
	protected $db;
21
22
	/**
23
	* @var \phpbb\template\template
0 ignored issues
show
Bug introduced by
The type phpbb\template\template was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
	*/
25
	protected $template;
26
27
	/**
28
	* @var \phpbb\user
0 ignored issues
show
Bug introduced by
The type phpbb\user was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
29
	*/
30
	protected $user;
31
32
	/**
33
	* @var \phpbb\language\language
0 ignored issues
show
Bug introduced by
The type phpbb\language\language was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
34
	*/
35
	protected $language;
36
37
	/**
38
	* @var \phpbb\request\request
0 ignored issues
show
Bug introduced by
The type phpbb\request\request was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
39
	*/
40
	protected $request;
41
42
	/**
43
	* @var \phpbbgallery\core\config
44
	*/
45
	protected $gallery_config;
46
47
	/**
48
	* @var \phpbbgallery\core\auth\auth
49
	*/
50
	protected $gallery_auth;
51
52
	/**
53
	* @var string
54
	*/
55
	protected $images_table;
56
57
	/**
58
	* @var string
59
	*/
60
	protected $albums_table;
61
62
	/**
63
	* @var string
64
	*/
65
	protected $rates_table;
66
67
	/**
68
	* The image ID we want to rate
69
	*/
70
	public $image_id = 0;
71
72
	/**
73
	* Private objects with the values for the image/album from the database
74
	*/
75
	private $image_data = null;
76
	private $album_data = null;
77
78
	/**
79
	* Rating the user gave the image.
80
	*/
81
	public $user_rating = null;
82
83
	/**
84
	* Is rating currently possible?
85
	* Might be blocked because of contest-settings.
86
	*/
87
	public $rating_enabled = false;
88
89
	/**
90
	* Classic-rating box with a dropdown.
91
	*/
92
	const MODE_SELECT = 1;
93
94
	/**
95
	* Rating with stars, like the old-system from youtube.
96
	//@todo: const MODE_STARS = 2;
97
	*/
98
99
	/**
100
	* Simple thumbs up or down.
101
	//@todo: const MODE_THUMB = 3;
102
	*/
103
104
	/**
105
	 * Constructor
106
	 *
107
	 * @param \phpbb\db\driver\driver_interface $db
108
	 * @param \phpbb\template\template          $template
109
	 * @param \phpbb\user                       $user
110
	 * @param \phpbb\language\language          $language
111
	 * @param \phpbb\request\request            $request
112
	 * @param config                            $gallery_config
113
	 * @param auth\auth                         $gallery_auth
114
	 * @param                                   $images_table
115
	 * @param                                   $albums_table
116
	 * @param                                   $rates_table
117
	 */
118 24
	public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\template\template $template, \phpbb\user $user,
119
		\phpbb\language\language $language, \phpbb\request\request $request, \phpbbgallery\core\config $gallery_config,
120
		\phpbbgallery\core\auth\auth $gallery_auth,
121
		$images_table, $albums_table, $rates_table)
122
	{
123 24
		$this->db = $db;
124 24
		$this->template = $template;
125 24
		$this->user = $user;
126 24
		$this->language = $language;
127 24
		$this->request = $request;
128 24
		$this->gallery_config = $gallery_config;
129 24
		$this->gallery_auth = $gallery_auth;
130 24
		$this->images_table = $images_table;
131 24
		$this->albums_table = $albums_table;
132 24
		$this->rates_table = $rates_table;
133 24
	}
134
135
	/**
136
	 * Load data for the class to work with
137
	 *
138
	 * @param    int $image_id
139
	 * @param array|bool $image_data Array with values from the image-table of the image
140
	 * @param array|bool $album_data Array with values from the album-table of the image's album
141
	 */
142 9
	public function loader($image_id, $image_data = false, $album_data = false)
143
	{
144 9
		$this->image_id = (int) $image_id;
145 9
		if ($image_data)
146
		{
147
			$this->image_data = $image_data;
148
		}
149 9
		if ($album_data)
150
		{
151
			$this->album_data = $album_data;
152
		}
153 9
	}
154
155
	/**
156
	 * Returns the value of image_data key.
157
	 * If the value is missing, it is queried from the database.
158
	 * @param $key
159
	 * @return
160
	 */
161
	private function image_data($key)
162
	{
163
		if ($this->image_data == null)
164
		{
165
			$sql = 'SELECT *
166
				FROM ' . $this->images_table . '
167
				WHERE image_id = ' . (int) $this->image_id;
168
			$result = $this->db->sql_query($sql);
169
			$this->image_data = $this->db->sql_fetchrow($result);
170
			$this->db->sql_freeresult($result);
171
172
			if ($this->image_data == false)
173
			{
174
				trigger_error('IMAGE_NOT_EXIST');
175
			}
176
		}
177
178
		return $this->image_data[$key];
179
	}
180
181
	/**
182
	 * Returns the value of album_data key.
183
	 * If the value is missing, it is queried from the database.
184
	 *
185
	 * @param    $key    string    The value of the album data, if true it returns the hole array.
186
	 * @return mixed|null
187
	 */
188
	private function album_data($key)
189
	{
190
		if ($this->album_data == null)
191
		{
192
			$sql = 'SELECT *
193
				FROM ' . $this->albums_table . '
194
				WHERE album_id = ' . (int) $this->image_data('album_id');
195
			$result = $this->db->sql_query($sql);
196
			$this->album_data = $this->db->sql_fetchrow($result);
197
			$this->db->sql_freeresult($result);
198
199
			if ($this->album_data == false)
200
			{
201
				trigger_error('ALBUM_NOT_EXIST');
202
			}
203
		}
204
205
		return ($key === true) ? $this->album_data : $this->album_data[$key];
206
	}
207
208
	/**
209
	* Displays the box where the user can rate the image.
210
	*/
211
	public function display_box()
212
	{
213
		$this->template->assign_var('GALLERY_RATING', self::MODE_SELECT);//@todo: phpbb_ext_gallery_core_config::get('rating_mode'));
214
215
		switch (self::MODE_SELECT)//@todo: phpbb_ext_gallery_core_config::get('rating_mode'))
216
		{
217
			//@todo: self::MODE_THUMB:
218
			//@todo: self::MODE_STARS:
219
			case self::MODE_SELECT:
220
			default:
221
				// @TODO We do not have contests for now
222
				/*if ($this->album_data('contest_id'))
223
				{
224
					if (time() < ($this->album_data('contest_start') + $this->album_data('contest_rating')))
225
					{
226
						$template->assign_var('GALLERY_NO_RATING_MESSAGE', $user->lang('CONTEST_RATING_STARTS', $user->format_date(($this->album_data('contest_start') + $this->album_data('contest_rating')), false, true)));
227
						return;
228
					}
229
					if (($this->album_data('contest_start') + $this->album_data('contest_end')) < time())
230
					{
231
						$template->assign_var('GALLERY_NO_RATING_MESSAGE', $user->lang('CONTEST_RATING_ENDED', $user->format_date(($this->album_data('contest_start') + $this->album_data('contest_end')), false, true)));
232
						return;
233
					}
234
				}*/
235
				for ($i = 1; $i <= $this->gallery_config->get('max_rating'); $i++)
236
				{
237
					$this->template->assign_block_vars('rate_scale', array(
238
						'RATE_POINT'	=> $i,
239
					));
240
				}
241
			break;
242
		}
243
244
		$this->rating_enabled = true;
245
	}
246
247
	/**
248
	 * Get rating for a image
249
	 *
250
	 * @param bool|Personal $user_rating Personal rating of the user is displayed in most cases.
0 ignored issues
show
Bug introduced by
The type phpbbgallery\core\Personal was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
251
	 * @param bool|Shall $display_contest_end Shall we display the end-time of the contest? This requires the album-data to be filled.
0 ignored issues
show
Bug introduced by
The type phpbbgallery\core\Shall was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
252
	 * @return string Returns a string containing the information how the image was rated in average and how often.
253
	 */
254
	public function get_image_rating($user_rating = false, $display_contest_end = true)
255
	{
256
		$this->template->assign_var('GALLERY_RATING', self::MODE_SELECT);//@todo: phpbb_ext_gallery_core_config::get('rating_mode'));
257
258
		switch (self::MODE_SELECT)//@todo: phpbb_ext_gallery_core_config::get('rating_mode'))
259
		{
260
			//@todo: self::MODE_THUMB:
261
			//@todo: self::MODE_STARS:
262
			case self::MODE_SELECT:
263
			default:
264
				if ($this->image_data('image_contest'))
265
				{
266
					if (!$display_contest_end)
267
					{
268
						return $this->language->lang('CONTEST_RATING_HIDDEN');
269
					}
270
					return $this->language->lang('CONTEST_RESULT_HIDDEN', $this->user->format_date(($this->album_data('contest_start') + $this->album_data('contest_end')), false, true));
271
				}
272
				else
273
				{
274
					if ($user_rating)
275
					{
276
						return $this->language->lang('RATING_STRINGS_USER', (int) $this->image_data('image_rates'), $this->get_image_rating_value(), $user_rating);
277
					}
278
					return $this->language->lang('RATING_STRINGS', (int) $this->image_data('image_rates'), $this->get_image_rating_value());
279
				}
280
			break;
281
		}
282
	}
283
284
	/**
285
	* Get rated value for a image
286
	*/
287
	private function get_image_rating_value()
288
	{
289
		/*if (phpbb_ext_gallery_core_contest::$mode == phpbb_ext_gallery_core_contest::MODE_SUM)
290
		{
291
			return $this->image_data('image_rate_points');
292
		}
293
		else
294
		{*/
295
			return ($this->image_data('image_rate_avg') / 100);
296
		//}
297
	}
298
299
	/**
300
	* Is the user allowed to rate?
301
	* Following statements must be true:
302
	*	- User must have permissions.
303
	*	- User is neither owner of the image nor guest.
304
	*	- Album and image are not locked.
305
	*
306
	* @return	bool
307
	*/
308
	public function is_allowed()
309
	{
310
		return $this->gallery_auth->acl_check('i_rate', $this->album_data('album_id'), $this->album_data('album_user_id')) &&
311
			($this->user->data['user_id'] != $this->image_data('image_user_id')) && ($this->user->data['user_id'] != ANONYMOUS) &&
0 ignored issues
show
Bug introduced by
The constant phpbbgallery\core\ANONYMOUS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
312
			($this->album_data('album_status') != (int) \phpbbgallery\core\block::ALBUM_LOCKED) && ($this->image_data('image_status') == (int) \phpbbgallery\core\block::STATUS_APPROVED);
313
	}
314
315
	/**
316
	* Is the user able to rate?
317
	* Following statements must be true:
318
	*	- User must be allowed to rate
319
	*	- If the image is in a contest, it must be in the rating timespan
320
	*
321
	* @return	bool
322
	*/
323
	public function is_able()
324
	{
325
		return $this->is_allowed(); //&& phpbb_ext_gallery_core_contest::is_step('rate', $this->album_data(true));
326
	}
327
328
	/**
329
	* Get rating from a user for a given image
330
	*
331
	* @param	int		$user_id
332
	*
333
	* @return	mixed	False if the user did not rate or is guest, otherwise int the points.
334
	*/
335 6
	public function get_user_rating($user_id)
336
	{
337 6
		if (isset($this->user_rating[$user_id]))
338
		{
339 1
			return $this->user_rating[$user_id];
340
		}
341 5
		if ($user_id == ANONYMOUS)
0 ignored issues
show
Bug introduced by
The constant phpbbgallery\core\ANONYMOUS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
342
		{
343 1
			return false;
344
		}
345
346
		$sql = 'SELECT rate_point
347 4
			FROM ' . $this->rates_table . '
348 4
			WHERE rate_image_id = ' . (int) $this->image_id . '
349 4
				AND rate_user_id = ' . (int) $user_id;
350 4
		$result = $this->db->sql_query($sql);
351 4
		$rating = $this->db->sql_fetchfield('rate_point');
352 4
		$this->db->sql_freeresult($result);
353
354 4
		$this->user_rating[$user_id] = (is_bool($rating)) ? $rating : (int) $rating;
355 4
		return $this->user_rating[$user_id];
356
	}
357
358
	/**
359
	 * Submit rating for an image.
360
	 *
361
	 * @param bool|int $user_id
362
	 * @param bool|int $points
363
	 * @param bool|string $user_ip Can be empty, function falls back to $user->ip
364
	 * @return bool
365
	 */
366 4
	public function submit_rating($user_id = false, $points = false, $user_ip = false)
367
	{
368 4
		switch (self::MODE_SELECT)//@todo: phpbb_ext_gallery_core_config::get('rating_mode'))
369
		{
370
			//@todo: self::MODE_THUMB:
371
			//@todo: self::MODE_STARS:
372 4
			case self::MODE_SELECT:
373
			default:
374 4
				$user_id = ($user_id) ? $user_id : $this->user->data['user_id'];
375 4
				$points = ($points) ? $points : $this->request->variable('rating', 0);
376 4
				$points = max(1, min($points, $this->gallery_config->get('max_rating')));
377 4
			break;
378
		}
379
380 4
		if (($user_id == ANONYMOUS) || $this->get_user_rating($user_id))
0 ignored issues
show
Bug introduced by
It seems like $user_id can also be of type true; however, parameter $user_id of phpbbgallery\core\rating::get_user_rating() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

380
		if (($user_id == ANONYMOUS) || $this->get_user_rating(/** @scrutinizer ignore-type */ $user_id))
Loading history...
Bug introduced by
The constant phpbbgallery\core\ANONYMOUS was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
381
		{
382 3
			return false;
383
		}
384
385 1
		$this->insert_rating($user_id, $points, $user_ip);
0 ignored issues
show
Bug introduced by
It seems like $user_id can also be of type true; however, parameter $user_id of phpbbgallery\core\rating::insert_rating() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

385
		$this->insert_rating(/** @scrutinizer ignore-type */ $user_id, $points, $user_ip);
Loading history...
386
387 1
		$this->recalc_image_rating($this->image_id);
388 1
		$this->user_rating[$user_id] = $points;
389 1
	}
390
391
	/**
392
	 * Insert the rating into the database.
393
	 *
394
	 * @param    int $user_id
395
	 * @param    int $points
396
	 * @param bool|string $user_ip Can be empty, function falls back to $user->ip
397
	 */
398 1
	private function insert_rating($user_id, $points, $user_ip = false)
399
	{
400
		$sql_ary = array(
401 1
			'rate_image_id'	=> $this->image_id,
402 1
			'rate_user_id'	=> $user_id,
403 1
			'rate_user_ip'	=> ($user_ip) ? $user_ip : $this->user->ip,
404 1
			'rate_point'	=> $points,
405
		);
406 1
		$this->db->sql_query('INSERT INTO ' . $this->rates_table . ' ' . $this->db->sql_build_array('INSERT', $sql_ary));
407 1
	}
408
409
	/**
410
	* Recalculate the average image-rating and such stuff.
411
	*
412
	* @param	mixed	$image_ids	Array or integer with image_id where we recalculate the rating.
413
	*/
414 1
	public function recalc_image_rating($image_ids)
415
	{
416 1
		if (is_array($image_ids))
417
		{
418
			$image_ids = array_map('intval', $image_ids);
419
		}
420
		else
421
		{
422 1
			$image_ids = (int) $image_ids;
423
		}
424
425
		$sql = 'SELECT rate_image_id, COUNT(rate_user_ip) image_rates, AVG(rate_point) image_rate_avg, SUM(rate_point) image_rate_points
426 1
			FROM ' . $this->rates_table . '
427 1
			WHERE ' . $this->db->sql_in_set('rate_image_id', $image_ids, false, true) . '
428
			GROUP BY rate_image_id';
429 1
		$result = $this->db->sql_query($sql);
430
431 1
		while ($row = $this->db->sql_fetchrow($result))
432
		{
433 1
			$sql = 'UPDATE ' . $this->images_table . '
434 1
				SET image_rates = ' . (int) $row['image_rates'] . ',
435 1
					image_rate_points = ' . (int) $row['image_rate_points'] . ',
436 1
					image_rate_avg = ' . round($row['image_rate_avg'], 2) * 100 . '
437 1
				WHERE image_id = ' . (int) $row['rate_image_id'];
438 1
			$this->db->sql_query($sql);
439
		}
440 1
		$this->db->sql_freeresult($result);
441 1
	}
442
443
	/**
444
	* Delete all ratings for given image_ids
445
	*
446
	* @param	mixed	$image_ids		Array or integer with image_id where we delete the rating.
447
	* @param	bool	$reset_average	Shall we also reset the average? We can save that query, when the images are deleted anyway.
448
	*/
449
	public function delete_ratings($image_ids, $reset_average = false)
450
	{
451
		if (is_array($image_ids))
452
		{
453
			$image_ids = array_map('intval', $image_ids);
454
		}
455
		else
456
		{
457
			$image_ids = (int) $image_ids;
458
		}
459
460
		$sql = 'DELETE FROM ' . $this->rates_table . '
461
			WHERE ' . $this->db->sql_in_set('rate_image_id', $image_ids, false, true);
462
		$result = $this->db->sql_query($sql);
0 ignored issues
show
Unused Code introduced by
The assignment to $result is dead and can be removed.
Loading history...
463
464
		if ($reset_average)
465
		{
466
			$sql = 'UPDATE ' . $this->images_table . '
467
				SET image_rates = 0,
468
					image_rate_points = 0,
469
					image_rate_avg = 0
470
				WHERE ' . $this->db->sql_in_set('image_id', $image_ids);
471
			$this->db->sql_query($sql);
472
		}
473
	}
474
}
475