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

manager::get_ad_locations()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 16
Ratio 100 %

Code Coverage

Tests 10
CRAP Score 2

Importance

Changes 0
Metric Value
dl 16
loc 16
ccs 10
cts 10
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 10
nc 2
nop 1
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 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 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
		// remove old ad_group table data
216 4
		$sql = 'DELETE FROM ' . $this->ad_group_table . '
217 4
			WHERE ad_id = ' . (int) $ad_id;
218 4
		$this->db->sql_query($sql);
219
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 5 View Code Duplication
	public function load_memberships($user_id)
322
	{
323 5
		$memberships = array();
324
		$sql = 'SELECT group_id
325 5
			FROM ' . USER_GROUP_TABLE . '
326 5
			WHERE user_id = ' . (int) $user_id . '
327 5
			AND user_pending = 0';
328 5
		$result = $this->db->sql_query($sql, 3600);
329 5
		while ($row = $this->db->sql_fetchrow($result))
330
		{
331 5
			$memberships[] = $row['group_id'];
332 5
		}
333 5
		$this->db->sql_freeresult($result);
334 5
		return $memberships;
335
	}
336
337
	/**
338
	 * Load all board groups
339
	 *
340
	 * @return	array	List of groups
341
	 */
342 1
	public function load_groups($ad_id)
343
	{
344
		$sql = 'SELECT g.group_id, g.group_name, (
345
				SELECT COUNT(ad_id)
346 1
				FROM ' . $this->ad_group_table . ' ag
347 1
				WHERE ag.ad_id = ' . (int) $ad_id . '
348
					AND ag.group_id = g.group_id
349
			) as group_selected
350 1
			FROM ' . GROUPS_TABLE . " g
351
			WHERE g.group_name <> 'BOTS'
352 1
			ORDER BY g.group_name ASC";
353 1
		$result = $this->db->sql_query($sql);
354 1
		$groups = $this->db->sql_fetchrowset($result);
355 1
		$this->db->sql_freeresult($result);
356
357 1
		return $groups;
358
	}
359
360
	/**
361
	 * Make sure only necessary data make their way to SQL query
362
	 *
363
	 * @param	array	$data	List of data to query the database
364
	 * @return	array	Cleaned data that contain only valid keys
365
	 */
366 6
	protected function intersect_ad_data($data)
367
	{
368 6
		return array_intersect_key($data, array(
369 6
			'ad_name'			=> '',
370 6
			'ad_note'			=> '',
371 6
			'ad_code'			=> '',
372 6
			'ad_enabled'		=> '',
373 6
			'ad_end_date'		=> '',
374 6
			'ad_priority'		=> '',
375 6
			'ad_views_limit'	=> '',
376 6
			'ad_clicks_limit'	=> '',
377 6
			'ad_owner'			=> '',
378 6
			'ad_content_only'	=> '',
379 6
		));
380
	}
381
382
	/**
383
	 * Get the random statement for this database layer
384
	 * Random function should generate a float value between 0 and 1
385
	 *
386
	 * @return	string	Random statement for current database layer
387
	 */
388 6
	protected function sql_random()
389
	{
390 6
		switch ($this->db->get_sql_layer())
391
		{
392 6
			case 'oracle':
393
				return 'VALUE()';
394
395 6
			case 'postgres':
396
				return 'RANDOM()';
397
398
			// https://stackoverflow.com/a/35369410/2908600
399 6
			case 'sqlite':
400 6
			case 'sqlite3':
401
				return '(0.5 - RANDOM() / CAST(-9223372036854775808 AS REAL) / 2)';
402
403 6
			default:
404 6
				return 'RAND()';
405 6
		}
406
	}
407
408
	/**
409
	 * Add rows to ad_group table.
410
	 *
411
	 * @param int   $ad_id     Advertisement ID
412
	 * @param array $ad_groups List of groups that should not see this ad
413
	 * @return void
414
	 */
415 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...
416
	{
417 6
		$sql_ary = array();
418 6
		foreach ($ad_groups as $group)
419
		{
420 2
			$sql_ary[] = array(
421 2
				'ad_id'		=> $ad_id,
422 2
				'group_id'	=> $group,
423
			);
424 6
		}
425 6
		$this->db->sql_multi_insert($this->ad_group_table, $sql_ary);
426 6
	}
427
}
428