Completed
Pull Request — master (#123)
by Jakub
11:31
created

manager::delete_ad()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 5
nc 1
nop 1
crap 1
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
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_end_date = 0
87 8
						OR a.ad_end_date > ' . time() . ")
88
					$sql_where_views
89 8
					$sql_where_clicks
90 8
					$sql_where_non_content
91 8
					$sql_where_user_groups
92 8
					AND " . $this->db->sql_in_set('al.location_id', $ad_locations) . '
93 8
				ORDER BY al.location_id, (' . $this->sql_random() . ' * a.ad_priority) DESC';
94 8
		$result = $this->db->sql_query($sql);
95 8
		$data = $this->db->sql_fetchrowset($result);
96 8
		$this->db->sql_freeresult($result);
97
98 8
		$current_location_id = '';
99 8
		$data = array_filter($data, function ($row) use (&$current_location_id) {
100 5
			$return = $current_location_id !== $row['location_id'];
101 5
			$current_location_id = $row['location_id'];
102 5
			return $return;
103 8
		});
104
105 8
		return $data;
106
	}
107
108
	/**
109
	 * Get all advertisements.
110
	 *
111
	 * @return    array    List of all ads
112
	 */
113 2 View Code Duplication
	public function get_all_ads()
114
	{
115
		$sql = 'SELECT ad_id, ad_priority, ad_name, ad_enabled, ad_end_date, ad_views, ad_clicks, ad_views_limit, ad_clicks_limit
116 2
			FROM ' . $this->ads_table;
117 2
		$result = $this->db->sql_query($sql);
118 2
		$data = $this->db->sql_fetchrowset($result);
119 2
		$this->db->sql_freeresult($result);
120
121 2
		return $data;
122
	}
123
124
	/**
125
	 * Get all owner's ads
126
	 *
127
	 * @param    int $user_id Ad owner
128
	 * @return    array    List of owner's ads
129
	 */
130 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...
131
	{
132
		$sql = 'SELECT ad_id, ad_name, ad_enabled, ad_end_date, ad_views, ad_views_limit, ad_clicks, ad_clicks_limit
133 5
			FROM ' . $this->ads_table . '
134 5
			WHERE ad_owner = ' . (int) $user_id;
135 5
		$result = $this->db->sql_query($sql);
136 5
		$data = $this->db->sql_fetchrowset($result);
137 5
		$this->db->sql_freeresult($result);
138
139 5
		return $data;
140
	}
141
142
	/**
143
	 * Increment views for specified ads
144
	 *
145
	 * Note, that views are incremented only by one even when
146
	 * an ad is displayed multiple times on the same page.
147
	 *
148
	 * @param    array $ad_ids IDs of ads to increment views
149
	 * @return    void
150
	 */
151 2 View Code Duplication
	public function increment_ads_views($ad_ids)
152
	{
153 2
		if (!empty($ad_ids))
154 2
		{
155 2
			$sql = 'UPDATE ' . $this->ads_table . '
156
				SET ad_views = ad_views + 1
157 2
				WHERE ' . $this->db->sql_in_set('ad_id', $ad_ids);
158 2
			$this->db->sql_query($sql);
159 2
		}
160 2
	}
161
162
	/**
163
	 * Increment clicks for specified ad
164
	 *
165
	 * @param    int $ad_id ID of an ad to increment clicks
166
	 * @return    void
167
	 */
168 2
	public function increment_ad_clicks($ad_id)
169
	{
170 2
		$sql = 'UPDATE ' . $this->ads_table . '
171
			SET ad_clicks = ad_clicks + 1
172 2
			WHERE ad_id = ' . (int) $ad_id;
173 2
		$this->db->sql_query($sql);
174 2
	}
175
176
	/**
177
	 * Insert new advertisement to the database
178
	 *
179
	 * @param    array $data New ad data
180
	 * @return    int        New advertisement ID
181
	 */
182 2
	public function insert_ad($data)
183
	{
184 2
		$ad_groups = $data['ad_groups'];
185 2
		$data = $this->intersect_ad_data($data);
186
187
		// add a row to ads table
188 2
		$sql = 'INSERT INTO ' . $this->ads_table . ' ' . $this->db->sql_build_array('INSERT', $data);
189 2
		$this->db->sql_query($sql);
190 2
		$ad_id = $this->db->sql_nextid();
191
192 2
		$this->insert_ad_group_data($ad_id, $ad_groups);
193
194 2
		return $ad_id;
195
	}
196
197
	/**
198
	 * Update advertisement
199
	 *
200
	 * @param    int   $ad_id Advertisement ID
201
	 * @param    array $data  List of data to update in the database
202
	 * @return    int        Number of affected rows. Can be used to determine if any ad has been updated.
203
	 */
204 4
	public function update_ad($ad_id, $data)
205
	{
206 4
		$ad_groups = isset($data['ad_groups']) ? $data['ad_groups'] : array();
207 4
		$data = $this->intersect_ad_data($data);
208
209 4
		$sql = 'UPDATE ' . $this->ads_table . '
210 4
			SET ' . $this->db->sql_build_array('UPDATE', $data) . '
211 4
			WHERE ad_id = ' . (int) $ad_id;
212 4
		$this->db->sql_query($sql);
213 4
		$result = $this->db->sql_affectedrows();
214
215 4
		$this->remove_ad_group_data($ad_id);
216 4
		$this->insert_ad_group_data($ad_id, $ad_groups);
217
218 4
		return $result;
219
	}
220
221
	/**
222
	 * Delete advertisement
223
	 *
224
	 * @param    int $ad_id Advertisement ID
225
	 * @return    int        Number of affected rows. Can be used to determine if any ad has been deleted.
226
	 */
227 1
	public function delete_ad($ad_id)
228
	{
229 1
		$sql = 'DELETE FROM ' . $this->ads_table . '
230 1
			WHERE ad_id = ' . (int) $ad_id;
231 1
		$this->db->sql_query($sql);
232
233 1
		return $this->db->sql_affectedrows();
234
	}
235
236
	/**
237
	 * Remove ad owner
238
	 *
239
	 * @param    array $user_ids User IDs
240
	 * @return    void
241
	 */
242 3 View Code Duplication
	public function remove_ad_owner(array $user_ids)
243
	{
244 3
		if (empty($user_ids))
245 3
		{
246
			return;
247
		}
248
249 3
		$sql = 'UPDATE ' . $this->ads_table . '
250
			SET ad_owner = 0
251 3
			WHERE ' . $this->db->sql_in_set('ad_owner', $user_ids);
252 3
		$this->db->sql_query($sql);
253 3
	}
254
255
	/**
256
	 * Get all locations for specified advertisement
257
	 *
258
	 * @param	int		$ad_id	Advertisement ID
259
	 * @return	array	List of template locations for specified ad
260
	 */
261 7 View Code Duplication
	public function get_ad_locations($ad_id)
262
	{
263 7
		$ad_locations = array();
264
265
		$sql = 'SELECT location_id
266 7
			FROM ' . $this->ad_locations_table . '
267 7
			WHERE ad_id = ' . (int) $ad_id;
268 7
		$result = $this->db->sql_query($sql);
269 7
		while ($row = $this->db->sql_fetchrow($result))
270
		{
271 5
			$ad_locations[] = $row['location_id'];
272 5
		}
273 7
		$this->db->sql_freeresult($result);
274
275 7
		return $ad_locations;
276
	}
277
278
	/**
279
	 * Insert advertisement locations
280
	 *
281
	 * @param	int		$ad_id			Advertisement ID
282
	 * @param	array	$ad_locations	List of template locations for this ad
283
	 * @return	void
284
	 */
285 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...
286
	{
287 2
		$sql_ary = array();
288 2
		foreach ($ad_locations as $ad_location)
289
		{
290 2
			$sql_ary[] = array(
291 2
				'ad_id'			=> $ad_id,
292 2
				'location_id'	=> $ad_location,
293
			);
294 2
		}
295 2
		$this->db->sql_multi_insert($this->ad_locations_table, $sql_ary);
296 2
	}
297
298
	/**
299
	 * Delete advertisement locations
300
	 *
301
	 * @param	int		$ad_id	Advertisement ID
302
	 * @return	void
303
	 */
304 3
	public function delete_ad_locations($ad_id)
305
	{
306 3
		$sql = 'DELETE FROM ' . $this->ad_locations_table . '
307 3
			WHERE ad_id = ' . (int) $ad_id;
308 3
		$this->db->sql_query($sql);
309 3
	}
310
311
	/**
312
	 * Load memberships of the user
313
	 *
314
	 * @param	int		$user_id	User ID to load memberships
315
	 * @return	array	List of group IDs user is member of
316
	 */
317 2 View Code Duplication
	public function load_memberships($user_id)
318
	{
319 2
		$memberships = array();
320
		$sql = 'SELECT group_id
321 2
			FROM ' . USER_GROUP_TABLE . '
322 2
			WHERE user_id = ' . (int) $user_id . '
323 2
			AND user_pending = 0';
324 2
		$result = $this->db->sql_query($sql, 3600);
325 2
		while ($row = $this->db->sql_fetchrow($result))
326
		{
327 2
			$memberships[] = $row['group_id'];
328 2
		}
329 2
		$this->db->sql_freeresult($result);
330 2
		return $memberships;
331
	}
332
333
	/**
334
	 * Load all board groups
335
	 *
336
	 * @param	int		$ad_id	Advertisement ID
337
	 * @return	array	List of groups
338
	 */
339 1
	public function load_groups($ad_id)
340
	{
341
		$sql = 'SELECT g.group_id, g.group_name, (
342
				SELECT COUNT(ad_id)
343 1
				FROM ' . $this->ad_group_table . ' ag
344 1
				WHERE ag.ad_id = ' . (int) $ad_id . '
345
					AND ag.group_id = g.group_id
346
			) as group_selected
347 1
			FROM ' . GROUPS_TABLE . " g
348
			WHERE g.group_name <> 'BOTS'
349 1
			ORDER BY g.group_name ASC";
350 1
		$result = $this->db->sql_query($sql);
351 1
		$groups = $this->db->sql_fetchrowset($result);
352 1
		$this->db->sql_freeresult($result);
353
354 1
		return $groups;
355
	}
356
357
	/**
358
	 * Make sure only necessary data make their way to SQL query
359
	 *
360
	 * @param	array	$data	List of data to query the database
361
	 * @return	array	Cleaned data that contain only valid keys
362
	 */
363 6
	protected function intersect_ad_data($data)
364
	{
365 6
		return array_intersect_key($data, array(
366 6
			'ad_name'			=> '',
367 6
			'ad_note'			=> '',
368 6
			'ad_code'			=> '',
369 6
			'ad_enabled'		=> '',
370 6
			'ad_end_date'		=> '',
371 6
			'ad_priority'		=> '',
372 6
			'ad_views_limit'	=> '',
373 6
			'ad_clicks_limit'	=> '',
374 6
			'ad_owner'			=> '',
375 6
			'ad_content_only'	=> '',
376 6
		));
377
	}
378
379
	/**
380
	 * Get the random statement for this database layer
381
	 * Random function should generate a float value between 0 and 1
382
	 *
383
	 * @return	string	Random statement for current database layer
384
	 */
385 8
	protected function sql_random()
386
	{
387 8
		switch ($this->db->get_sql_layer())
388
		{
389 8
			case 'oracle':
390
				return 'VALUE()';
391
392 8
			case 'postgres':
393
				return 'RANDOM()';
394
395
			// https://stackoverflow.com/a/35369410/2908600
396 8
			case 'sqlite':
397 8
			case 'sqlite3':
398
				return '(0.5 - RANDOM() / CAST(-9223372036854775808 AS REAL) / 2)';
399
400 8
			default:
401 8
				return 'RAND()';
402 8
		}
403
	}
404
405
	/**
406
	 * Add rows to ad_group table.
407
	 *
408
	 * @param int   $ad_id     Advertisement ID
409
	 * @param array $ad_groups List of groups that should not see this ad
410
	 * @return void
411
	 */
412 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...
413
	{
414 6
		$sql_ary = array();
415 6
		foreach ($ad_groups as $group)
416
		{
417 2
			$sql_ary[] = array(
418 2
				'ad_id'		=> $ad_id,
419 2
				'group_id'	=> $group,
420
			);
421 6
		}
422 6
		$this->db->sql_multi_insert($this->ad_group_table, $sql_ary);
423 6
	}
424
425
	/**
426
	 * @param int	$ad_id	Advertisement ID
427
	 * @return void
428
	 */
429 4
	protected function remove_ad_group_data($ad_id)
430
	{
431 4
		$sql = 'DELETE FROM ' . $this->ad_group_table . '
432 4
			WHERE ad_id = ' . (int) $ad_id;
433 4
		$this->db->sql_query($sql);
434 4
	}
435
}
436