Completed
Pull Request — master (#123)
by Jakub
36:02
created

manager::delete_ad_locations()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
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 54
	public function __construct(\phpbb\db\driver\driver_interface $db, \phpbb\config\config $config, $ads_table, $ad_locations_table, $ad_group_table)
40
	{
41 54
		$this->db = $db;
42 54
		$this->config = $config;
43 54
		$this->ads_table = $ads_table;
44 54
		$this->ad_locations_table = $ad_locations_table;
45 54
		$this->ad_group_table = $ad_group_table;
46 54
	}
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 6
	public function get_ads($ad_locations, $user_groups, $non_content_page = false)
75
	{
76 6
		$sql_where_views = $this->config['phpbb_ads_enable_views'] ? 'AND (a.ad_views_limit = 0 OR a.ad_views_limit > a.ad_views)' : '';
77 6
		$sql_where_clicks = $this->config['phpbb_ads_enable_clicks'] ? 'AND (a.ad_clicks_limit = 0 OR a.ad_clicks_limit > a.ad_clicks)' : '';
78 6
		$sql_where_non_content = $non_content_page ? 'AND a.ad_content_only = 0' : '';
79 6
		$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 6
				FROM ' . $this->ad_locations_table . ' al
83 6
				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 6
						OR a.ad_end_date > ' . time() . ")
88
					$sql_where_views
89 6
					$sql_where_clicks
90 6
					$sql_where_non_content
91 6
					$sql_where_user_groups
92 6
					AND " . $this->db->sql_in_set('al.location_id', $ad_locations) . '
93 6
				ORDER BY al.location_id, (' . $this->sql_random() . ' * a.ad_priority) DESC';
94 6
		$result = $this->db->sql_query($sql);
95 6
		$data = $this->db->sql_fetchrowset($result);
96 6
		$this->db->sql_freeresult($result);
97
98 6
		$current_location_id = '';
99 6
		$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 6
		});
104
105 6
		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
		// add rows to ad_group table
193 2
		$sql_ary = array();
194 2
		foreach ($ad_groups as $group)
195
		{
196
			$sql_ary[] = array(
197
				'ad_id'		=> $ad_id,
198
				'group_id'	=> $group,
199
			);
200 2
		}
201 2
		$this->db->sql_multi_insert($this->ad_group_table, $sql_ary);
202
203 2
		return $ad_id;
204
	}
205
206
	/**
207
	 * Update advertisement
208
	 *
209
	 * @param    int   $ad_id Advertisement ID
210
	 * @param    array $data  List of data to update in the database
211
	 * @return    int        Number of affected rows. Can be used to determine if any ad has been updated.
212
	 */
213 4
	public function update_ad($ad_id, $data)
214
	{
215 4
		$ad_groups = isset($data['ad_groups']) ? $data['ad_groups'] : array();
216 4
		$data = $this->intersect_ad_data($data);
217
218 4
		$sql = 'UPDATE ' . $this->ads_table . '
219 4
			SET ' . $this->db->sql_build_array('UPDATE', $data) . '
220 4
			WHERE ad_id = ' . (int) $ad_id;
221 4
		$this->db->sql_query($sql);
222 4
		$result = $this->db->sql_affectedrows();
223
224
		// remove old ad_group table data
225 4
		$sql = 'DELETE FROM ' . $this->ad_group_table . '
226 4
			WHERE ad_id = ' . (int) $ad_id;
227 4
		$this->db->sql_query($sql);
228
229
		// add rows to ad_group table
230 4
		$sql_ary = array();
231 4
		foreach ($ad_groups as $group)
232
		{
233
			$sql_ary[] = array(
234
				'ad_id'		=> $ad_id,
235
				'group_id'	=> $group,
236
			);
237 4
		}
238 4
		$this->db->sql_multi_insert($this->ad_group_table, $sql_ary);
239
240 4
		return $result;
241
	}
242
243
	/**
244
	 * Delete advertisement
245
	 *
246
	 * @param    int $ad_id Advertisement ID
247
	 * @return    int        Number of affected rows. Can be used to determine if any ad has been deleted.
248
	 */
249 1
	public function delete_ad($ad_id)
250
	{
251 1
		$sql = 'DELETE FROM ' . $this->ads_table . '
252 1
			WHERE ad_id = ' . (int) $ad_id;
253 1
		$this->db->sql_query($sql);
254
255 1
		return $this->db->sql_affectedrows();
256
	}
257
258
	/**
259
	 * Remove ad owner
260
	 *
261
	 * @param    array $user_ids User IDs
262
	 * @return    void
263
	 */
264 3 View Code Duplication
	public function remove_ad_owner(array $user_ids)
265
	{
266 3
		if (empty($user_ids))
267 3
		{
268
			return;
269
		}
270
271 3
		$sql = 'UPDATE ' . $this->ads_table . '
272
			SET ad_owner = 0
273 3
			WHERE ' . $this->db->sql_in_set('ad_owner', $user_ids);
274 3
		$this->db->sql_query($sql);
275 3
	}
276
277
	/**
278
	 * Get all locations for specified advertisement
279
	 *
280
	 * @param	int		$ad_id	Advertisement ID
281
	 * @return	array	List of template locations for specified ad
282
	 */
283 7 View Code Duplication
	public function get_ad_locations($ad_id)
284
	{
285 7
		$ad_locations = array();
286
287
		$sql = 'SELECT location_id
288 7
			FROM ' . $this->ad_locations_table . '
289 7
			WHERE ad_id = ' . (int) $ad_id;
290 7
		$result = $this->db->sql_query($sql);
291 7
		while ($row = $this->db->sql_fetchrow($result))
292
		{
293 5
			$ad_locations[] = $row['location_id'];
294 5
		}
295 7
		$this->db->sql_freeresult($result);
296
297 7
		return $ad_locations;
298
	}
299
300
	/**
301
	 * Insert advertisement locations
302
	 *
303
	 * @param	int		$ad_id			Advertisement ID
304
	 * @param	array	$ad_locations	List of template locations for this ad
305
	 * @return	void
306
	 */
307 2
	public function insert_ad_locations($ad_id, $ad_locations)
308
	{
309 2
		$sql_ary = array();
310 2
		foreach ($ad_locations as $ad_location)
311
		{
312 2
			$sql_ary[] = array(
313 2
				'ad_id'			=> $ad_id,
314 2
				'location_id'	=> $ad_location,
315
			);
316 2
		}
317 2
		$this->db->sql_multi_insert($this->ad_locations_table, $sql_ary);
318 2
	}
319
320
	/**
321
	 * Delete advertisement locations
322
	 *
323
	 * @param	int		$ad_id	Advertisement ID
324
	 * @return	void
325
	 */
326 3
	public function delete_ad_locations($ad_id)
327
	{
328 3
		$sql = 'DELETE FROM ' . $this->ad_locations_table . '
329 3
			WHERE ad_id = ' . (int) $ad_id;
330 3
		$this->db->sql_query($sql);
331 3
	}
332
333
	/**
334
	 * Load memberships of the user
335
	 *
336
	 * @param	int		$user_id	User ID to load memberships
337
	 * @return	array	List of group IDs user is member of
338
	 */
339 5 View Code Duplication
	public function load_memberships($user_id)
340
	{
341 5
		$memberships = array();
342
		$sql = 'SELECT group_id
343 5
			FROM ' . USER_GROUP_TABLE . '
344 5
			WHERE user_id = ' . (int) $user_id . '
345 5
			AND user_pending = 0';
346 5
		$result = $this->db->sql_query($sql, 3600);
347 5
		while ($row = $this->db->sql_fetchrow($result))
348
		{
349 5
			$memberships[] = $row['group_id'];
350 5
		}
351 5
		$this->db->sql_freeresult($result);
352 5
		return $memberships;
353
	}
354
355
	/**
356
	 * Load all board groups
357
	 *
358
	 * @return	array	List of groups
359
	 */
360 1
	public function load_groups($ad_id)
361
	{
362
		$sql = 'SELECT g.group_id, g.group_name, (
363
				SELECT COUNT(ad_id)
364 1
				FROM ' . $this->ad_group_table . ' ag
365 1
				WHERE ag.ad_id = ' . (int) $ad_id . '
366
					AND ag.group_id = g.group_id
367
			) as group_selected
368 1
			FROM ' . GROUPS_TABLE . " g
369
			WHERE g.group_name <> 'BOTS'
370 1
			ORDER BY g.group_name ASC";
371 1
		$result = $this->db->sql_query($sql);
372 1
		$groups = $this->db->sql_fetchrowset($result);
373 1
		$this->db->sql_freeresult($result);
374
375 1
		return $groups;
376
	}
377
378
	/**
379
	 * Make sure only necessary data make their way to SQL query
380
	 *
381
	 * @param	array	$data	List of data to query the database
382
	 * @return	array	Cleaned data that contain only valid keys
383
	 */
384 6
	protected function intersect_ad_data($data)
385
	{
386 6
		return array_intersect_key($data, array(
387 6
			'ad_name'			=> '',
388 6
			'ad_note'			=> '',
389 6
			'ad_code'			=> '',
390 6
			'ad_enabled'		=> '',
391 6
			'ad_end_date'		=> '',
392 6
			'ad_priority'		=> '',
393 6
			'ad_views_limit'	=> '',
394 6
			'ad_clicks_limit'	=> '',
395 6
			'ad_owner'			=> '',
396 6
			'ad_content_only'	=> '',
397 6
		));
398
	}
399
400
	/**
401
	 * Get the random statement for this database layer
402
	 * Random function should generate a float value between 0 and 1
403
	 *
404
	 * @return	string	Random statement for current database layer
405
	 */
406 6
	protected function sql_random()
407
	{
408 6
		switch ($this->db->get_sql_layer())
409
		{
410 6
			case 'oracle':
411
				return 'VALUE()';
412
413 6
			case 'postgres':
414
				return 'RANDOM()';
415
416
			// https://stackoverflow.com/a/35369410/2908600
417 6
			case 'sqlite':
418 6
			case 'sqlite3':
419
				return '(0.5 - RANDOM() / CAST(-9223372036854775808 AS REAL) / 2)';
420
421 6
			default:
422 6
				return 'RAND()';
423 6
		}
424
	}
425
}
426