Passed
Push — develop-3.3.x ( c925a0...2e3aed )
by Mario
02:35
created

core   B

Complexity

Total Complexity 52

Size/Duplication

Total Lines 480
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 1
Metric Value
eloc 102
c 4
b 0
f 1
dl 0
loc 480
rs 7.44
wmc 52

26 Methods

Rating   Name   Duplication   Size   Complexity  
A get_ipn_suffix() 0 3 2
A update_user_stats() 0 8 2
A log_to_db() 0 25 1
A autogroup_is_enabled() 0 3 2
A donors_group_user_add() 0 42 3
A extract_item_number_data() 0 3 1
A set_transaction_data() 0 3 2
A update_donor_stats() 0 5 2
A can_use_autogroup() 0 7 4
A set_ipn_test() 0 3 2
A is_donor_is_member() 0 26 5
A minimum_donation_raised() 0 6 1
A set_ipn_suffix() 0 3 2
A check_donors_status() 0 5 1
A validate_user_id() 0 5 3
A get_ipn_test() 0 3 2
A update_raised_amount() 0 10 2
A get_count_result() 0 8 2
A set_ipn_test_properties() 0 4 1
A get_donor_is_member() 0 3 2
A net_amount() 0 3 1
A get_payer_data() 0 3 2
A is_in_admin() 0 3 4
A payment_status_is_completed() 0 3 1
A update_overview_stats() 0 5 1
A __construct() 0 20 1

How to fix   Complexity   

Complex Class

Complex classes like core often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use core, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 *
4
 * PayPal Donation extension for the phpBB Forum Software package.
5
 *
6
 * @copyright (c) 2015-2020 Skouat
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace skouat\ppde\actions;
12
13
use phpbb\config\config;
14
use phpbb\event\dispatcher_interface;
15
use phpbb\language\language;
16
use phpbb\path_helper;
17
use phpbb\user;
18
19
class core
20
{
21
	const ASCII_RANGE = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
22
23
	/**
24
	 * Services properties declaration
25
	 */
26
	public $notification;
27
	protected $config;
28
	protected $dispatcher;
29
	protected $language;
30
	protected $php_ext;
31
	protected $ppde_entity_transaction;
32
	protected $ppde_operator_transaction;
33
	protected $transaction_data;
34
	protected $user;
35
36
	/**
37
	 * @var boolean
38
	 */
39
	private $donor_is_member = false;
40
	/**
41
	 * @var boolean
42
	 */
43
	private $is_ipn_test = false;
44
	/**
45
	 * @var array
46
	 */
47
	private $payer_data = array();
48
	/**
49
	 * phpBB root path
50
	 *
51
	 * @var string
52
	 */
53
	private $root_path;
54
	/**
55
	 * @var string
56
	 */
57
	private $ipn_suffix;
58
59
	/**
60
	 * Constructor
61
	 *
62
	 * @param config                              $config                    Config object
63
	 * @param language                            $language                  Language user object
64
	 * @param \skouat\ppde\notification\core      $notification              PPDE Notification object
65
	 * @param path_helper                         $path_helper               Path helper object
66
	 * @param \skouat\ppde\entity\transactions    $ppde_entity_transaction   Transaction entity object
67
	 * @param \skouat\ppde\operators\transactions $ppde_operator_transaction Transaction operator object
68
	 * @param dispatcher_interface                $dispatcher                Dispatcher object
69
	 * @param user                                $user                      User object
70
	 * @param string                              $php_ext                   phpEx
71
	 *
72
	 * @access public
73
	 */
74
	public function __construct(
75
		config $config,
76
		language $language,
77
		\skouat\ppde\notification\core $notification,
78
		path_helper $path_helper,
79
		\skouat\ppde\entity\transactions $ppde_entity_transaction,
80
		\skouat\ppde\operators\transactions $ppde_operator_transaction,
81
		dispatcher_interface $dispatcher,
82
		user $user,
83
		$php_ext)
84
	{
85
		$this->config = $config;
86
		$this->dispatcher = $dispatcher;
87
		$this->language = $language;
88
		$this->notification = $notification;
89
		$this->ppde_entity_transaction = $ppde_entity_transaction;
90
		$this->ppde_operator_transaction = $ppde_operator_transaction;
91
		$this->php_ext = $php_ext;
92
		$this->root_path = $path_helper->get_phpbb_root_path();
93
		$this->user = $user;
94
	}
95
96
	/**
97
	 * Sets properties related to ipn tests
98
	 *
99
	 * @param bool $ipn_test
100
	 *
101
	 * @return void
102
	 * @access public
103
	 */
104
	public function set_ipn_test_properties($ipn_test)
105
	{
106
		$this->set_ipn_test($ipn_test);
107
		$this->set_ipn_suffix();
108
	}
109
110
	/**
111
	 * Sets the property $this->is_ipn_test
112
	 *
113
	 * @param bool $ipn_test
114
	 *
115
	 * @return void
116
	 * @access private
117
	 */
118
	private function set_ipn_test($ipn_test)
119
	{
120
		$this->is_ipn_test = $ipn_test ? (bool) $ipn_test : false;
121
	}
122
123
	/**
124
	 * Sets the property $this->ipn_suffix
125
	 *
126
	 * @return void
127
	 * @access private
128
	 */
129
	private function set_ipn_suffix()
130
	{
131
		$this->ipn_suffix = $this->is_ipn_test ? '_ipn' : '';
132
	}
133
134
	/**
135
	 * Gets the property $this->ipn_suffix
136
	 *
137
	 * @return string
138
	 * @access private
139
	 */
140
	public function get_ipn_suffix()
141
	{
142
		return ($this->get_ipn_test()) ? $this->ipn_suffix : '';
143
	}
144
145
	/**
146
	 * @return boolean
147
	 * @access private
148
	 */
149
	public function get_ipn_test()
150
	{
151
		return $this->is_ipn_test ? (bool) $this->is_ipn_test : false;
152
	}
153
154
	/**
155
	 * Updates the amount of donation raised
156
	 *
157
	 * @return void
158
	 * @access public
159
	 */
160
	public function update_raised_amount()
161
	{
162
		$net_amount = (float) $this->net_amount($this->transaction_data['mc_gross'], $this->transaction_data['mc_fee']);
163
164
		if (!empty($this->transaction_data['settle_amount']))
165
		{
166
			$net_amount = $this->transaction_data['settle_amount'];
167
		}
168
169
		$this->config->set('ppde_raised' . $this->ipn_suffix, (float) $this->config['ppde_raised' . $this->ipn_suffix] + $net_amount, true);
170
	}
171
172
	/**
173
	 * Returns the net amount of a donation
174
	 *
175
	 * @param float  $amount
176
	 * @param float  $fee
177
	 * @param string $dec_point
178
	 * @param string $thousands_sep
179
	 *
180
	 * @return string
181
	 * @access public
182
	 */
183
	public function net_amount($amount, $fee, $dec_point = '.', $thousands_sep = '')
184
	{
185
		return number_format((float) $amount - (float) $fee, 2, $dec_point, $thousands_sep);
186
	}
187
188
	/**
189
	 * Updates the Overview module statistics
190
	 *
191
	 * @return void
192
	 * @access public
193
	 */
194
	public function update_overview_stats()
195
	{
196
		$this->config->set('ppde_anonymous_donors_count' . $this->ipn_suffix, $this->get_count_result('ppde_anonymous_donors_count' . $this->ipn_suffix));
197
		$this->config->set('ppde_known_donors_count' . $this->ipn_suffix, $this->get_count_result('ppde_known_donors_count' . $this->ipn_suffix), true);
198
		$this->config->set('ppde_transactions_count' . $this->ipn_suffix, $this->get_count_result('ppde_transactions_count' . $this->ipn_suffix), true);
199
	}
200
201
	/**
202
	 * Returns count result for updating stats
203
	 *
204
	 * @param string $config_name
205
	 *
206
	 * @return int
207
	 * @access private
208
	 */
209
	private function get_count_result($config_name)
210
	{
211
		if (!$this->config->offsetExists($config_name))
212
		{
213
			trigger_error($this->language->lang('EXCEPTION_INVALID_CONFIG_NAME', $config_name), E_USER_WARNING);
214
		}
215
216
		return $this->ppde_operator_transaction->sql_query_count_result($config_name, $this->is_ipn_test);
217
	}
218
219
	/**
220
	 * Checks if the donor is a member then gets payer_data values
221
	 *
222
	 * @return void
223
	 * @access public
224
	 */
225
226
	public function is_donor_is_member()
227
	{
228
		$anonymous_user = false;
229
230
		// If the user_id is not anonymous
231
		if ($this->transaction_data['user_id'] != ANONYMOUS)
232
		{
233
			$this->donor_is_member = $this->check_donors_status('user', $this->transaction_data['user_id']);
234
235
			if (!$this->donor_is_member)
236
			{
237
				// No results, therefore the user is anonymous...
238
				$anonymous_user = true;
239
			}
240
		}
241
		else
242
		{
243
			// The user is anonymous by default
244
			$anonymous_user = true;
245
		}
246
247
		if ($anonymous_user && !empty($this->transaction_data['payer_email']))
248
		{
249
			// If the user is anonymous, check their PayPal email address with all known email hashes
250
			// to determine if the user exists in the database with that email
251
			$this->donor_is_member = $this->check_donors_status('email', $this->transaction_data['payer_email']);
252
		}
253
	}
254
255
	/**
256
	 * @return boolean
257
	 */
258
	public function get_donor_is_member()
259
	{
260
		return ($this->donor_is_member) ? (bool) $this->donor_is_member : false;
261
	}
262
263
	/**
264
	 * Gets donor informations (user id, username, amount donated) and returns if exists
265
	 *
266
	 * @param string     $type Allowed value : 'user' or 'email'
267
	 * @param string|int $args If $type is set to 'user', $args must be a user id.
268
	 *                         If $type is set to 'email', $args must be an email address
269
	 *
270
	 * @return bool
271
	 * @access private
272
	 */
273
	private function check_donors_status($type, $args)
274
	{
275
		$this->payer_data = $this->ppde_operator_transaction->query_donor_user_data($type, $args);
276
277
		return (bool) count((array) $this->payer_data);
278
	}
279
280
	/**
281
	 * @return array
282
	 */
283
	public function get_payer_data()
284
	{
285
		return (count($this->payer_data) != 0) ? $this->payer_data : [];
286
	}
287
288
	/**
289
	 * Updates donor member stats
290
	 *
291
	 * @return void
292
	 * @access public
293
	 */
294
	public function update_donor_stats()
295
	{
296
		if ($this->donor_is_member)
297
		{
298
			$this->update_user_stats((int) $this->payer_data['user_id'], (float) $this->payer_data['user_ppde_donated_amount'] + (float) $this->transaction_data['mc_gross']);
299
		}
300
	}
301
302
	/**
303
	 * @param int   $user_id
304
	 * @param float $amount
305
	 */
306
	public function update_user_stats($user_id, $amount)
307
	{
308
		if (!$user_id)
309
		{
310
			trigger_error($this->language->lang('EXCEPTION_INVALID_USER_ID', $user_id), E_USER_WARNING);
311
		}
312
313
		$this->ppde_operator_transaction->sql_update_user_stats($user_id, $amount);
314
	}
315
316
	/**
317
	 * Add donor to the donors group
318
	 *
319
	 * @return void
320
	 * @access public
321
	 */
322
	public function donors_group_user_add()
323
	{
324
		// We add the user to the donors group
325
		$can_use_autogroup = $this->can_use_autogroup();
326
		$group_id = (int) $this->config['ppde_ipn_group_id'];
327
		$payer_id = (int) $this->payer_data['user_id'];
328
		$payer_username = $this->payer_data['username'];
329
		$default_group = $this->config['ppde_ipn_group_as_default'];
330
		$payer_donated_amount = $this->payer_data['user_ppde_donated_amount'];
331
332
		/**
333
		 * Event to modify data before a user is added to the donors group
334
		 *
335
		 * @event skouat.ppde.donors_group_user_add_before
336
		 * @var bool    can_use_autogroup      Whether or not to add the user to the group
337
		 * @var int     group_id               The ID of the group to which the user will be added
338
		 * @var int     payer_id               The ID of the user who will we added to the group
339
		 * @var string  payer_username         The user name
340
		 * @var bool    default_group          Whether or not the group should be made default for the user
341
		 * @var float   payer_donated_amount   The user donated amount
342
		 * @since 1.0.3
343
		 * @changed 2.1.2 Added var $payer_donated_amount
344
		 */
345
		$vars = [
346
			'can_use_autogroup',
347
			'group_id',
348
			'payer_id',
349
			'payer_username',
350
			'default_group',
351
			'payer_donated_amount',
352
		];
353
		extract($this->dispatcher->trigger_event('skouat.ppde.donors_group_user_add_before', compact($vars)));
354
355
		if ($can_use_autogroup)
356
		{
357
			if (!function_exists('group_user_add'))
358
			{
359
				include($this->root_path . 'includes/functions_user.' . $this->php_ext);
360
			}
361
362
			// Adds the user to the donors group and set as default.
363
			group_user_add($group_id, [$payer_id], [$payer_username], get_group_name($group_id), $default_group);
364
		}
365
	}
366
367
	/**
368
	 * Checks if all required settings are meet for adding the donor to the group of donors
369
	 *
370
	 * @return bool
371
	 * @access private
372
	 */
373
	private function can_use_autogroup()
374
	{
375
		return
376
			$this->autogroup_is_enabled() &&
377
			$this->donor_is_member &&
378
			$this->payment_status_is_completed() &&
379
			$this->minimum_donation_raised();
380
	}
381
382
	/**
383
	 * Checks if Autogroup could be used
384
	 *
385
	 * @return bool
386
	 * @access private
387
	 */
388
	private function autogroup_is_enabled()
389
	{
390
		return $this->config['ppde_ipn_enable'] && $this->config['ppde_ipn_autogroup_enable'];
391
	}
392
393
	/**
394
	 * Checks if payment_status is completed
395
	 *
396
	 * @return bool
397
	 * @access public
398
	 */
399
	public function payment_status_is_completed()
400
	{
401
		return $this->transaction_data['payment_status'] === 'Completed';
402
	}
403
404
	/**
405
	 * Checks if member's donation is upper or equal to the minimum defined
406
	 *
407
	 * @return bool
408
	 * @access public
409
	 */
410
	public function minimum_donation_raised()
411
	{
412
		// Updates payer_data info before checking values
413
		$this->check_donors_status('user', $this->payer_data['user_id']);
414
415
		return (float) $this->payer_data['user_ppde_donated_amount'] >= (float) $this->config['ppde_ipn_min_before_group'];
416
	}
417
418
	/**
419
	 * Log the transaction to the database
420
	 *
421
	 * @param array $data Transaction data array
422
	 *
423
	 * @access public
424
	 */
425
	public function log_to_db($data)
426
	{
427
		// Set the property $this->transaction_data
428
		$this->set_transaction_data($data);
429
430
		// The item number contains the user_id
431
		$this->extract_item_number_data();
432
		$this->validate_user_id();
433
434
		// Set username in extra_data property in $entity
435
		$user_ary = $this->ppde_operator_transaction->query_donor_user_data('user', $this->transaction_data['user_id']);
436
		$this->ppde_entity_transaction->set_username($user_ary['username']);
437
438
		// Set 'net_amount' in $this->transaction_data
439
		$this->transaction_data['net_amount'] = $this->net_amount($this->transaction_data['mc_gross'], $this->transaction_data['mc_fee']);
440
441
		// List the data to be thrown into the database
442
		$data = $this->ppde_operator_transaction->build_data_ary($this->transaction_data);
443
444
		// Load data in the entity
445
		$this->ppde_entity_transaction->set_entity_data($data);
446
		$this->ppde_entity_transaction->set_id($this->ppde_entity_transaction->transaction_exists());
447
448
		// Add or edit transaction data
449
		$this->ppde_entity_transaction->add_edit_data();
450
	}
451
452
	/**
453
	 * Set Transaction Data array
454
	 *
455
	 * @param array $transaction_data Array of the donation transaction.
456
	 *
457
	 * @return void
458
	 * @access public
459
	 */
460
	public function set_transaction_data($transaction_data)
461
	{
462
		$this->transaction_data = !empty($this->transaction_data) ? array_merge($this->transaction_data, $transaction_data) : $transaction_data;
463
	}
464
465
	/**
466
	 * Retrieve user_id from item_number args
467
	 *
468
	 * @return void
469
	 * @access private
470
	 */
471
	private function extract_item_number_data()
472
	{
473
		list($this->transaction_data['user_id']) = explode('_', substr($this->transaction_data['item_number'], 4), -1);
474
	}
475
476
	/**
477
	 * Avoid the user_id to be set to 0
478
	 *
479
	 * @return void
480
	 * @access private
481
	 */
482
	private function validate_user_id()
483
	{
484
		if (empty($this->transaction_data['user_id']) || !is_numeric($this->transaction_data['user_id']))
485
		{
486
			$this->transaction_data['user_id'] = ANONYMOUS;
487
		}
488
	}
489
490
	/**
491
	 * Check we are in the ACP
492
	 *
493
	 * @return bool
494
	 * @access public
495
	 */
496
	public function is_in_admin()
497
	{
498
		return (defined('IN_ADMIN') && isset($this->user->data['session_admin']) && $this->user->data['session_admin']) ? IN_ADMIN : false;
499
	}
500
}
501