Completed
Push — master ( 6d8026...334e81 )
by Matt
13s queued 10s
created

base::check()   C

Complexity

Conditions 12
Paths 46

Size

Total Lines 64

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 64
rs 6.3587
c 0
b 0
f 0
cc 12
nc 46
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
*
4
* Auto Groups extension for the phpBB Forum Software package.
5
*
6
* @copyright (c) 2014 phpBB Limited <https://www.phpbb.com>
7
* @license GNU General Public License, version 2 (GPL-2.0)
8
*
9
*/
10
11
namespace phpbb\autogroups\conditions\type;
12
13
use Symfony\Component\DependencyInjection\ContainerInterface;
14
15
/**
16
 * Auto Groups base class
17
 */
18
abstract class base implements type_interface
19
{
20
	/** @var ContainerInterface */
21
	protected $container;
22
23
	/** @var \phpbb\db\driver\driver_interface */
24
	protected $db;
25
26
	/** @var \phpbb\autogroups\conditions\type\helper */
27
	protected $helper;
28
29
	/** @var \phpbb\language\language */
30
	protected $language;
31
32
	/** @var string The database table the auto group rules are stored in */
33
	protected $autogroups_rules_table;
34
35
	/** @var string The database table the auto group types are stored in */
36
	protected $autogroups_types_table;
37
38
	/** @var string */
39
	protected $phpbb_root_path;
40
41
	/** @var string */
42
	protected $php_ext;
43
44
	/**
45
	 * Constructor
46
	 *
47
	 * @param ContainerInterface                $container              Service container interface
48
	 * @param \phpbb\db\driver\driver_interface $db                     Database object
49
	 * @param \phpbb\language\language          $language               Language object
50
	 * @param string                            $autogroups_rules_table Name of the table used to store auto group rules data
51
	 * @param string                            $autogroups_types_table Name of the table used to store auto group types data
52
	 * @param string                            $phpbb_root_path        phpBB root path
53
	 * @param string                            $php_ext                phpEx
54
	 *
55
	 * @access public
56
	 */
57
	public function __construct(ContainerInterface $container, \phpbb\db\driver\driver_interface $db, \phpbb\language\language $language, $autogroups_rules_table, $autogroups_types_table, $phpbb_root_path, $php_ext)
58
	{
59
		$this->container = $container;
60
		$this->db = $db;
61
		$this->language = $language;
62
63
		$this->autogroups_rules_table = $autogroups_rules_table;
64
		$this->autogroups_types_table = $autogroups_types_table;
65
66
		$this->phpbb_root_path = $phpbb_root_path;
67
		$this->php_ext = $php_ext;
68
69
		// Load the helper from the container instead of dependency injection to
70
		// help anyone extending auto groups avoid setting optional dependencies.
71
		$this->helper = $this->container->get('phpbb.autogroups.helper');
72
73
		if (!function_exists('group_user_add'))
74
		{
75
			include $this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext;
76
		}
77
	}
78
79
	/**
80
	 * {@inheritdoc}
81
	 */
82
	public function get_group_rules($type = '')
83
	{
84
		$sql_array = array(
85
			'SELECT'	=> 'agr.*, agt.autogroups_type_name',
86
			'FROM'		=> array(
87
				$this->autogroups_rules_table => 'agr',
88
				$this->autogroups_types_table => 'agt',
89
			),
90
			'WHERE'		=> 'agr.autogroups_type_id = agt.autogroups_type_id' .
91
				($type ? " AND agt.autogroups_type_name = '" . $this->db->sql_escape($type) . "'" : ''),
92
		);
93
		$sql = $this->db->sql_build_query('SELECT', $sql_array);
94
		$result = $this->db->sql_query($sql, 7200);
95
		$rows = $this->db->sql_fetchrowset($result);
96
		$this->db->sql_freeresult($result);
97
98
		return $rows;
99
	}
100
101
	/**
102
	 * {@inheritdoc}
103
	 */
104
	public function add_users_to_group($user_id_ary, $group_rule_data)
105
	{
106
		// Set this variable for readability in the code below
107
		$group_id = $group_rule_data['autogroups_group_id'];
108
109
		// Add user(s) to the group
110
		group_user_add($group_id, $user_id_ary);
111
112
		// Send notification
113
		if ($group_rule_data['autogroups_notify'])
114
		{
115
			$this->helper->send_notifications('group_added', $user_id_ary, $group_id);
116
		}
117
118
		// Set group as default?
119
		if ($group_rule_data['autogroups_default'])
120
		{
121
			// Make sure user_id_ary is an array
122
			$user_id_ary = $this->helper->prepare_users_for_query($user_id_ary);
123
124
			// Get array of users exempt from default group switching
125
			$default_exempt_users = $this->helper->get_default_exempt_users();
126
127
			// Remove any exempt users from our main user array
128
			if (count($default_exempt_users))
129
			{
130
				$user_id_ary = array_diff($user_id_ary, $default_exempt_users);
131
			}
132
133
			// Set the current group as default for non-exempt users
134
			group_user_attributes('default', $group_id, $user_id_ary);
135
		}
136
	}
137
138
	/**
139
	 * {@inheritdoc}
140
	 */
141
	public function remove_users_from_group($user_id_ary, $group_rule_data)
142
	{
143
		// Return if the user_id_array is empty
144
		if (!count($user_id_ary))
145
		{
146
			return;
147
		}
148
149
		// Set this variable for readability in the code below
150
		$group_id = $group_rule_data['autogroups_group_id'];
151
152
		// Delete user(s) from the group
153
		group_user_del($group_id, $user_id_ary);
154
155
		// Send notification
156
		if ($group_rule_data['autogroups_notify'])
157
		{
158
			$this->helper->send_notifications('group_removed', $user_id_ary, $group_id);
159
		}
160
	}
161
162
	/**
163
	 * {@inheritdoc}
164
	 */
165
	public function check($user_row, $options = array())
166
	{
167
		// Get all auto group rule data sets
168
		$group_rules = $this->get_group_rules();
169
170
		// Get an array of users and the groups they belong to
171
		$user_groups = $this->helper->get_users_groups(array_keys($user_row));
172
173
		foreach ($group_rules as $group_rule)
174
		{
175
			// Only check group rules set for this condition type
176
			if ($group_rule['autogroups_type_name'] === $this->get_condition_type())
177
			{
178
				// Initialize some arrays
179
				$add_users_to_group = $remove_users_from_group = array();
180
181
				foreach ($user_row as $user_id => $user_data)
182
				{
183
					// Check for no-group users and initialise corresponding data array
184
					if (!isset($user_groups[$user_id]))
185
					{
186
						$user_groups[$user_id] = array();
187
					}
188
189
					// Skip users of excluded groups
190
					if (!empty($group_rule['autogroups_excluded_groups']) && array_intersect(json_decode($group_rule['autogroups_excluded_groups'], true), $user_groups[$user_id]))
191
					{
192
						continue;
193
					}
194
195
					// Check if a user's data is within the min/max range
196
					if ($this->check_user_data($user_data[$this->get_condition_field()], $group_rule))
197
					{
198
						// Check if a user is already a member of checked group
199
						if (!in_array($group_rule['autogroups_group_id'], $user_groups[$user_id]))
200
						{
201
							// Add user to group
202
							$add_users_to_group[] = $user_id;
203
						}
204
					}
205
					else if (in_array($group_rule['autogroups_group_id'], $user_groups[$user_id]))
206
					{
207
						// Remove user from the group
208
						$remove_users_from_group[] = $user_id;
209
					}
210
				}
211
212
				if (count($add_users_to_group))
213
				{
214
					// Add users to groups
215
					$this->add_users_to_group($add_users_to_group, $group_rule);
216
				}
217
218
				if (count($remove_users_from_group))
219
				{
220
					// Filter users that should not be removed
221
					$remove_users_from_group = $this->filter_users($remove_users_from_group, $group_rule, $group_rules);
222
223
					// Remove users from groups
224
					$this->remove_users_from_group($remove_users_from_group, $group_rule);
225
				}
226
			}
227
		}
228
	}
229
230
	/**
231
	 * Helper function checks if a user's data is within
232
	 * an auto group rule condition's min/max range.
233
	 *
234
	 * @param int   $value      The value of the user's data field to check
235
	 * @param array $group_rule Data array for an auto group rule
236
	 * @return bool True if the user meets the condition, false otherwise
237
	 * @access protected
238
	 */
239
	protected function check_user_data($value, $group_rule)
240
	{
241
		return (null !== $value && $value >= $group_rule['autogroups_min_value']) &&
242
			(empty($group_rule['autogroups_max_value']) || ($value <= $group_rule['autogroups_max_value'])
243
		);
244
	}
245
246
	/**
247
	 * Helper function prevents un-wanted removal of users from
248
	 * the current group in cases where users do not satisfy the
249
	 * conditions of the current rule, but may satisfy conditions
250
	 * for another rule that applies to the current group.
251
	 *
252
	 * @param array $user_id_ary  Array of users marked for removal
253
	 * @param array $current_rule Data array for an auto group rule
254
	 * @param array $group_rules  Data array for all auto group rules
255
	 * @return array Array of users to be removed
256
	 * @access protected
257
	 */
258
	protected function filter_users($user_id_ary, $current_rule, $group_rules)
259
	{
260
		// Iterate through every auto group rule
261
		foreach ($group_rules as $group_rule)
262
		{
263
			// Only look at other auto group rules that apply to this group
264
			if ($group_rule['autogroups_group_id'] == $current_rule['autogroups_group_id'] &&
265
				$group_rule['autogroups_type_id'] != $current_rule['autogroups_type_id'] &&
266
				count($user_id_ary)
267
			)
268
			{
269
				// Load other auto group rule's condition type and get new data for our user(s)
270
				$condition = $this->container->get($group_rule['autogroups_type_name']);
271
				$condition_user_data = $condition->get_users_for_condition(array(
272
					'users' => $user_id_ary,
273
				));
274
				// Filter users out users that satisfy other conditions for this group
275
				$user_id_ary = array_filter($user_id_ary, function ($user_id) use ($condition, $condition_user_data, $group_rule) {
276
					return !$condition->check_user_data($condition_user_data[$user_id][$condition->get_condition_field()], $group_rule);
277
				});
278
			}
279
		}
280
281
		return $user_id_ary;
282
	}
283
284
	/**
285
	 * An array of user types to ignore when querying users
286
	 *
287
	 * @return array Array of user types
288
	 * @access protected
289
	 */
290
	protected function ignore_user_types()
291
	{
292
		return array(USER_INACTIVE, USER_IGNORE);
293
	}
294
295
	/**
296
	 * Helper to convert days into a timestamp
297
	 *
298
	 * @param int $value Number of days
299
	 * @return int Timestamp
300
	 * @access protected
301
	 */
302
	protected function days_to_timestamp($value)
303
	{
304
		return (int) strtotime((int) $value . ' days ago');
305
	}
306
307
	/**
308
	 * Helper to convert a timestamp into days
309
	 *
310
	 * @param int $value Timestamp
311
	 * @return int|null Number of days or null if no value given
312
	 * @throws \Exception
313
	 * @access protected
314
	 */
315
	protected function timestamp_to_days($value)
316
	{
317
		if (!$value)
318
		{
319
			return null;
320
		}
321
322
		$now  = new \DateTime();
323
		$time = new \DateTime('@' . (int) $value);
324
		$diff = $now->diff($time);
325
		return (int) $diff->format('%a');
326
	}
327
}
328