Completed
Push — master ( 7d29c5...8ac802 )
by Jakub
20s
created

manager::update_ad()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 11
cts 11
cp 1
rs 9.7
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2
1
<?php
2
/**
3
 *
4
 * Advertisement management. An extension for the phpBB Forum Software package.
5
 *
6
 * @copyright (c) 2017 phpBB Limited <https://www.phpbb.com>
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace phpbb\ads\ad;
12
13
class manager
14
{
15
	/** @var \phpbb\db\driver\driver_interface */
16
	protected $db;
17
18
	/** @var \phpbb\config\config */
19
	protected $config;
20
21
	/** @var string */
22
	protected $ads_table;
23
24
	/** @var string */
25
	protected $ad_locations_table;
26
27
	/** @var string */
28
	protected $ad_group_table;
29
30
	/**
31
	 * Constructor
32
	 *
33
	 * @param    \phpbb\db\driver\driver_interface $db                 DB driver interface
34
	 * @param    \phpbb\config\config              $config             Config object
35
	 * @param    string                            $ads_table          Ads table
36
	 * @param    string                            $ad_locations_table Ad locations table
37
	 * @param    string                            $ad_group_table 	   Ad group table
38
	 */
39 56
	public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, $ads_table, $ad_locations_table, $ad_group_table)
40
	{
41 56
		$this->db = $db;
42 56
		$this->config = $config;
43 56
		$this->ads_table = $ads_table;
44 56
		$this->ad_locations_table = $ad_locations_table;
45 56
		$this->ad_group_table = $ad_group_table;
46 56
	}
47
48
	/**
49
	 * Get specific ad
50
	 *
51
	 * @param	int	$ad_id	Advertisement ID
52
	 * @return	array	Array with advertisement data
53
	 */
54 13
	public function get_ad($ad_id)
55
	{
56
		$sql = 'SELECT *
57 13
			FROM ' . $this->ads_table . '
58 13
			WHERE ad_id = ' . (int) $ad_id;
59 13
		$result = $this->db->sql_query($sql);
60 13
		$data = $this->db->sql_fetchrow($result);
61 13
		$this->db->sql_freeresult($result);
62
63 13
		return $data !== false ? $data : array();
64
	}
65
66
	/**
67
	 * Get one ad per every location
68
	 *
69
	 * @param    array $ad_locations List of ad locations to fetch ads for
70
	 * @param    array $user_groups List of user groups
71
	 * @param    bool  $non_content_page Is current page non-content oriented (e.g.: login, UCP, MCP)? Default is false.
72
	 * @return    array    List of ad codes for each location
73
	 */
74 8
	public function get_ads($ad_locations, $user_groups, $non_content_page = false)
75
	{
76 8
		$sql_where_views = $this->config['phpbb_ads_enable_views'] ? 'AND (a.ad_views_limit = 0 OR a.ad_views_limit > a.ad_views)' : '';
77 8
		$sql_where_clicks = $this->config['phpbb_ads_enable_clicks'] ? 'AND (a.ad_clicks_limit = 0 OR a.ad_clicks_limit > a.ad_clicks)' : '';
78 8
		$sql_where_non_content = $non_content_page ? 'AND a.ad_content_only = 0' : '';
79 8
		$sql_where_user_groups = !empty($user_groups) ? 'AND NOT EXISTS (SELECT ag.group_id FROM ' . $this->ad_group_table . ' ag WHERE ag.ad_id = a.ad_id AND ' . $this->db->sql_in_set('ag.group_id', $user_groups) . ')' : '';
80
81
		$sql = 'SELECT al.location_id, a.ad_id, a.ad_code, a.ad_centering
82 8
				FROM ' . $this->ad_locations_table . ' al
83 8
				LEFT JOIN ' . $this->ads_table . ' a
84
					ON (al.ad_id = a.ad_id)
85
				WHERE a.ad_enabled = 1
86
					AND (a.ad_start_date = 0
87 8
						OR a.ad_start_date < ' . time() . ')
88
					AND (a.ad_end_date = 0
89 8
						OR a.ad_end_date > ' . time() . ")
90
					$sql_where_views
91 8
					$sql_where_clicks
92 8
					$sql_where_non_content
93 8
					$sql_where_user_groups
94 8
					AND " . $this->db->sql_in_set('al.location_id', $ad_locations) . '
95 8
				ORDER BY al.location_id, (' . $this->sql_random() . ' * a.ad_priority) DESC';
96 8
		$result = $this->db->sql_query($sql);
97 8
		$data = $this->db->sql_fetchrowset($result);
98 8
		$this->db->sql_freeresult($result);
99
100 8
		$current_location_id = '';
101 8
		$data = array_filter($data, function ($row) use (&$current_location_id) {
102 5
			$return = $current_location_id !== $row['location_id'];
103 5
			$current_location_id = $row['location_id'];
104 5
			return $return;
105 8
		});
106
107 8
		return $data;
108
	}
109
110
	/**
111
	 * Get all advertisements.
112
	 *
113
	 * @return    array    List of all ads
114
	 */
115 2 View Code Duplication
	public function get_all_ads()
116
	{
117
		$sql = 'SELECT ad_id, ad_priority, ad_name, ad_enabled, ad_start_date, ad_end_date, ad_views, ad_clicks, ad_views_limit, ad_clicks_limit
118 2
			FROM ' . $this->ads_table;
119 2
		$result = $this->db->sql_query($sql);
120 2
		$data = $this->db->sql_fetchrowset($result);
121 2
		$this->db->sql_freeresult($result);
122
123 2
		return $data;
124
	}
125
126
	/**
127
	 * Get all owner's ads
128
	 *
129
	 * @param    int $user_id Ad owner
130
	 * @return    array    List of owner's ads
131
	 */
132 5 View Code Duplication
	public function get_ads_by_owner($user_id)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
133
	{
134
		$sql = 'SELECT ad_id, ad_name, ad_enabled, ad_start_date, ad_end_date, ad_views, ad_views_limit, ad_clicks, ad_clicks_limit
135 5
			FROM ' . $this->ads_table . '
136 5
			WHERE ad_owner = ' . (int) $user_id;
137 5
		$result = $this->db->sql_query($sql);
138 5
		$data = $this->db->sql_fetchrowset($result);
139 5
		$this->db->sql_freeresult($result);
140
141 5
		return $data;
142
	}
143
144
	/**
145
	 * Increment views for specified ads
146
	 *
147
	 * Note, that views are incremented only by one even when
148
	 * an ad is displayed multiple times on the same page.
149
	 *
150
	 * @param    array $ad_ids IDs of ads to increment views
151
	 * @return    void
152
	 */
153 2 View Code Duplication
	public function increment_ads_views($ad_ids)
154
	{
155 2
		if (!empty($ad_ids))
156 2
		{
157 2
			$sql = 'UPDATE ' . $this->ads_table . '
158
				SET ad_views = ad_views + 1
159 2
				WHERE ' . $this->db->sql_in_set('ad_id', $ad_ids);
160 2
			$this->db->sql_query($sql);
161 2
		}
162 2
	}
163
164
	/**
165
	 * Increment clicks for specified ad
166
	 *
167
	 * @param    int $ad_id ID of an ad to increment clicks
168
	 * @return    void
169
	 */
170 2
	public function increment_ad_clicks($ad_id)
171
	{
172 2
		$sql = 'UPDATE ' . $this->ads_table . '
173
			SET ad_clicks = ad_clicks + 1
174 2
			WHERE ad_id = ' . (int) $ad_id;
175 2
		$this->db->sql_query($sql);
176 2
	}
177
178
	/**
179
	 * Insert new advertisement to the database
180
	 *
181
	 * @param    array $data New ad data
182
	 * @return    int        New advertisement ID
183
	 */
184 2
	public function insert_ad($data)
185
	{
186
		// extract ad groups here because it gets filtered in intersect_ad_data()
187 2
		$ad_groups = $data['ad_groups'];
188 2
		$data = $this->intersect_ad_data($data);
189
190
		// add a row to ads table
191 2
		$sql = 'INSERT INTO ' . $this->ads_table . ' ' . $this->db->sql_build_array('INSERT', $data);
192 2
		$this->db->sql_query($sql);
193 2
		$ad_id = $this->db->sql_nextid();
194
195 2
		$this->insert_ad_group_data($ad_id, $ad_groups);
196
197 2
		return $ad_id;
198
	}
199
200
	/**
201
	 * Update advertisement
202
	 *
203
	 * @param    int   $ad_id Advertisement ID
204
	 * @param    array $data  List of data to update in the database
205
	 * @return    int        Number of affected rows. Can be used to determine if any ad has been updated.
206
	 */
207 4
	public function update_ad($ad_id, $data)
208
	{
209
		// extract ad groups here because it gets filtered in intersect_ad_data()
210 4
		$ad_groups = isset($data['ad_groups']) ? $data['ad_groups'] : array();
211 4
		$data = $this->intersect_ad_data($data);
212
213 4
		$sql = 'UPDATE ' . $this->ads_table . '
214 4
			SET ' . $this->db->sql_build_array('UPDATE', $data) . '
215 4
			WHERE ad_id = ' . (int) $ad_id;
216 4
		$this->db->sql_query($sql);
217 4
		$result = $this->db->sql_affectedrows();
218
219 4
		$this->remove_ad_group_data($ad_id);
220 4
		$this->insert_ad_group_data($ad_id, $ad_groups);
221
222 4
		return $result;
223
	}
224
225
	/**
226
	 * Delete advertisement
227
	 *
228
	 * @param    int $ad_id Advertisement ID
229
	 * @return    int        Number of affected rows. Can be used to determine if any ad has been deleted.
230
	 */
231 1
	public function delete_ad($ad_id)
232
	{
233 1
		$sql = 'DELETE FROM ' . $this->ads_table . '
234 1
			WHERE ad_id = ' . (int) $ad_id;
235 1
		$this->db->sql_query($sql);
236
237 1
		return $this->db->sql_affectedrows();
238
	}
239
240
	/**
241
	 * Remove ad owner
242
	 *
243
	 * @param    array $user_ids User IDs
244
	 * @return    void
245
	 */
246 3 View Code Duplication
	public function remove_ad_owner(array $user_ids)
247
	{
248 3
		if (empty($user_ids))
249 3
		{
250
			return;
251
		}
252
253 3
		$sql = 'UPDATE ' . $this->ads_table . '
254
			SET ad_owner = 0
255 3
			WHERE ' . $this->db->sql_in_set('ad_owner', $user_ids);
256 3
		$this->db->sql_query($sql);
257 3
	}
258
259
	/**
260
	 * Get all locations for specified advertisement
261
	 *
262
	 * @param	int		$ad_id	Advertisement ID
263
	 * @return	array	List of template locations for specified ad
264
	 */
265 7 View Code Duplication
	public function get_ad_locations($ad_id)
266
	{
267 7
		$ad_locations = array();
268
269
		$sql = 'SELECT location_id
270 7
			FROM ' . $this->ad_locations_table . '
271 7
			WHERE ad_id = ' . (int) $ad_id;
272 7
		$result = $this->db->sql_query($sql);
273 7
		while ($row = $this->db->sql_fetchrow($result))
274
		{
275 5
			$ad_locations[] = $row['location_id'];
276 5
		}
277 7
		$this->db->sql_freeresult($result);
278
279 7
		return $ad_locations;
280
	}
281
282
	/**
283
	 * Insert advertisement locations
284
	 *
285
	 * @param	int		$ad_id			Advertisement ID
286
	 * @param	array	$ad_locations	List of template locations for this ad
287
	 * @return	void
288
	 */
289 2 View Code Duplication
	public function insert_ad_locations($ad_id, $ad_locations)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
290
	{
291 2
		$sql_ary = array();
292 2
		foreach ($ad_locations as $ad_location)
293
		{
294 2
			$sql_ary[] = array(
295 2
				'ad_id'			=> $ad_id,
296 2
				'location_id'	=> $ad_location,
297
			);
298 2
		}
299 2
		$this->db->sql_multi_insert($this->ad_locations_table, $sql_ary);
300 2
	}
301
302
	/**
303
	 * Delete advertisement locations
304
	 *
305
	 * @param	int		$ad_id	Advertisement ID
306
	 * @return	void
307
	 */
308 3
	public function delete_ad_locations($ad_id)
309
	{
310 3
		$sql = 'DELETE FROM ' . $this->ad_locations_table . '
311 3
			WHERE ad_id = ' . (int) $ad_id;
312 3
		$this->db->sql_query($sql);
313 3
	}
314
315
	/**
316
	 * Load memberships of the user
317
	 *
318
	 * @param	int		$user_id	User ID to load memberships
319
	 * @return	array	List of group IDs user is member of
320
	 */
321 2 View Code Duplication
	public function load_memberships($user_id)
322
	{
323 2
		$memberships = array();
324
		$sql = 'SELECT group_id
325 2
			FROM ' . USER_GROUP_TABLE . '
326 2
			WHERE user_id = ' . (int) $user_id . '
327 2
			AND user_pending = 0';
328 2
		$result = $this->db->sql_query($sql, 3600);
329 2
		while ($row = $this->db->sql_fetchrow($result))
330
		{
331 2
			$memberships[] = $row['group_id'];
332 2
		}
333 2
		$this->db->sql_freeresult($result);
334 2
		return $memberships;
335
	}
336
337
	/**
338
	 * Load all board groups
339
	 *
340
	 * @param	int		$ad_id	Advertisement ID
341
	 * @return	array	List of groups
342
	 */
343 1
	public function load_groups($ad_id)
344
	{
345
		$sql = 'SELECT g.group_id, g.group_name, (
346
				SELECT COUNT(ad_id)
347 1
				FROM ' . $this->ad_group_table . ' ag
348 1
				WHERE ag.ad_id = ' . (int) $ad_id . '
349
					AND ag.group_id = g.group_id
350
			) as group_selected
351 1
			FROM ' . GROUPS_TABLE . " g
352
			WHERE g.group_name <> 'BOTS'
353 1
			ORDER BY g.group_name ASC";
354 1
		$result = $this->db->sql_query($sql);
355 1
		$groups = $this->db->sql_fetchrowset($result);
356 1
		$this->db->sql_freeresult($result);
357
358 1
		return $groups;
359
	}
360
361
	/**
362
	 * Make sure only necessary data make their way to SQL query
363
	 *
364
	 * @param	array	$data	List of data to query the database
365
	 * @return	array	Cleaned data that contain only valid keys
366
	 */
367 6
	protected function intersect_ad_data($data)
368
	{
369 6
		return array_intersect_key($data, array(
370 6
			'ad_name'			=> '',
371 6
			'ad_note'			=> '',
372 6
			'ad_code'			=> '',
373 6
			'ad_enabled'		=> '',
374 6
			'ad_start_date'		=> '',
375 6
			'ad_end_date'		=> '',
376 6
			'ad_priority'		=> '',
377 6
			'ad_views_limit'	=> '',
378 6
			'ad_clicks_limit'	=> '',
379 6
			'ad_owner'			=> '',
380 6
			'ad_content_only'	=> '',
381 6
			'ad_centering'		=> '',
382 6
		));
383
	}
384
385
	/**
386
	 * Get the random statement for this database layer
387
	 * Random function should generate a float value between 0 and 1
388
	 *
389
	 * @return	string	Random statement for current database layer
390
	 */
391 8
	protected function sql_random()
392
	{
393 8
		switch ($this->db->get_sql_layer())
394
		{
395 8
			case 'oracle':
396
				return 'VALUE()';
397
398 8
			case 'postgres':
399
				return 'RANDOM()';
400
401
			// https://stackoverflow.com/a/35369410/2908600
402 8
			case 'sqlite':
403 8
			case 'sqlite3':
404
				return '(0.5 - RANDOM() / CAST(-9223372036854775808 AS REAL) / 2)';
405
406 8
			default:
407 8
				return 'RAND()';
408 8
		}
409
	}
410
411
	/**
412
	 * Add rows to ad_group table.
413
	 *
414
	 * @param int   $ad_id     Advertisement ID
415
	 * @param array $ad_groups List of groups that should not see this ad
416
	 * @return void
417
	 */
418 6 View Code Duplication
	protected function insert_ad_group_data($ad_id, $ad_groups)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
419
	{
420 6
		$sql_ary = array();
421 6
		foreach ($ad_groups as $group)
422
		{
423 2
			$sql_ary[] = array(
424 2
				'ad_id'		=> $ad_id,
425 2
				'group_id'	=> $group,
426
			);
427 6
		}
428 6
		$this->db->sql_multi_insert($this->ad_group_table, $sql_ary);
429 6
	}
430
431
	/**
432
	 * Remove all rows of specified ad in ad_group table
433
	 *
434
	 * @param int	$ad_id	Advertisement ID
435
	 * @return void
436
	 */
437 4
	protected function remove_ad_group_data($ad_id)
438
	{
439 4
		$sql = 'DELETE FROM ' . $this->ad_group_table . '
440 4
			WHERE ad_id = ' . (int) $ad_id;
441 4
		$this->db->sql_query($sql);
442 4
	}
443
}
444