Test Failed
Push — issues/2244 ( ba3d1e )
by Ravinder
04:37
created

Give_Donor_List_Table   B

Complexity

Total Complexity 41

Size/Duplication

Total Lines 451
Duplicated Lines 25.5 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 115
loc 451
rs 8.2769
c 0
b 0
f 0
wmc 41
lcom 1
cbo 2

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 10 10 1
A search_box() 0 20 3
B column_default() 10 27 5
A column_cb() 0 7 1
A column_name() 0 8 2
A get_columns() 0 13 1
A get_sortable_columns() 11 11 1
A get_row_actions() 0 11 1
A get_paged() 0 3 2
A get_search() 0 3 2
A get_bulk_actions() 0 6 1
B process_bulk_action() 0 43 6
A display_tablenav() 0 19 3
B donor_data() 28 28 4
A get_donor_count() 10 10 1
B get_donor_query() 26 26 6
A prepare_items() 20 20 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Give_Donor_List_Table 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 Give_Donor_List_Table, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Donor List Table Class.
4
 *
5
 * The list view under WP-Admin > Donations > Donors.
6
 *
7
 * @package     Give
8
 * @subpackage  Admin/Reports
9
 * @copyright   Copyright (c) 2016, WordImpress
10
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
11
 * @since       1.0
12
 */
13
14
// Exit if accessed directly.
15
if ( ! defined( 'ABSPATH' ) ) {
16
	exit;
17
}
18
19
// Load WP_List_Table if not loaded.
20
if ( ! class_exists( 'WP_List_Table' ) ) {
21
	require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
22
}
23
24
/**
25
 * Give_Donor_List_Table Class.
26
 *
27
 * @since 1.0
28
 */
29
class Give_Donor_List_Table extends WP_List_Table {
30
31
	/**
32
	 * Number of items per page.
33
	 *
34
	 * @var int
35
	 * @since 1.0
36
	 */
37
	public $per_page = 30;
38
39
	/**
40
	 * Number of donors found.
41
	 *
42
	 * @var int
43
	 * @since 1.0
44
	 */
45
	public $count = 0;
46
47
	/**
48
	 * Total donors.
49
	 *
50
	 * @var int
51
	 * @since 1.0
52
	 */
53
	public $total = 0;
54
55
	/**
56
	 * Get things started.
57
	 *
58
	 * @since 1.0
59
	 * @see   WP_List_Table::__construct()
60
	 */
61 View Code Duplication
	public function __construct() {
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...
62
63
		// Set parent defaults.
64
		parent::__construct( array(
65
			'singular' => __( 'Donor', 'give' ), // Singular name of the listed records.
66
			'plural'   => __( 'Donors', 'give' ), // Plural name of the listed records.
67
			'ajax'     => false, // Does this table support ajax?.
68
		) );
69
70
	}
71
72
	/**
73
	 * Show the search field.
74
	 *
75
	 * @param string $text     Label for the search box.
76
	 * @param string $input_id ID of the search box.
77
	 *
78
	 * @since  1.0
79
	 * @access public
80
	 *
81
	 * @return void
82
	 */
83
	public function search_box( $text, $input_id ) {
84
		$input_id = $input_id . '-search-input';
85
86
		if ( ! empty( $_REQUEST['orderby'] ) ) {
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
87
			echo sprintf( '<input type="hidden" name="orderby" value="%1$s" />', esc_attr( $_REQUEST['orderby'] ) );
0 ignored issues
show
introduced by
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'sprintf'
Loading history...
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
88
		}
89
90
		if ( ! empty( $_REQUEST['order'] ) ) {
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
91
			echo sprintf( '<input type="hidden" name="order" value="%1$s" />', esc_attr( $_REQUEST['order'] ) );
0 ignored issues
show
introduced by
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw 'sprintf'
Loading history...
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
92
		}
93
		?>
94
		<p class="search-box" role="search">
95
			<label class="screen-reader-text" for="<?php echo $input_id ?>"><?php echo $text; ?>:</label>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$input_id'
Loading history...
introduced by
Expected next thing to be a escaping function, not '$text'
Loading history...
96
			<input type="search" id="<?php echo $input_id ?>" name="s" value="<?php _admin_search_query(); ?>"/>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$input_id'
Loading history...
97
			<?php submit_button( $text, 'button', false, false, array(
98
				'ID' => 'search-submit',
99
			) ); ?>
100
		</p>
101
		<?php
102
	}
103
104
	/**
105
	 * This function renders most of the columns in the list table.
106
	 *
107
	 * @param array  $donor        Contains all the data of the donors.
108
	 * @param string $column_name The name of the column.
109
	 *
110
	 * @access public
111
	 * @since  1.0
112
	 *
113
	 * @return string Column Name.
114
	 */
115
	public function column_default( $donor, $column_name ) {
116
		switch ( $column_name ) {
117
118 View Code Duplication
			case 'num_donations' :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
119
				$value = sprintf(
120
					'<a href="%s">%s</a>',
121
					admin_url( 'edit.php?post_type=give_forms&page=give-payment-history&donor=' . absint( $donor['id'] ) ),
122
					esc_html( $donor['num_donations'] )
123
				);
124
				break;
125
126 View Code Duplication
			case 'amount_spent' :
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
127
				$value = give_currency_filter( give_format_amount( $donor[ $column_name ], array( 'sanitize' => false ) ) );
128
				break;
129
130
			case 'date_created' :
131
				$value = date_i18n( give_date_format(), strtotime( $donor['date_created'] ) );
132
				break;
133
134
			default:
135
				$value = isset( $donor[ $column_name ] ) ? $donor[ $column_name ] : null;
136
				break;
137
		}
138
139
		return apply_filters( "give_donors_column_{$column_name}", $value, $donor['id'] );
140
141
	}
142
143
	/**
144
	 * For CheckBox Column
145
	 *
146
	 * @param array $donor Donor Data.
147
	 *
148
	 * @access public
149
	 * @since  1.8.16
150
	 *
151
	 * @return string
152
	 */
153
	public function column_cb( $donor ){
154
		return sprintf(
155
			'<input type="checkbox" name="%1$s[]" value="%2$s" />',
156
			$this->_args['singular'],
157
			$donor['id']
158
		);
159
	}
160
161
	/**
162
	 * Column name.
163
	 *
164
	 * @param array $donor Donor Data.
165
	 *
166
	 * @access public
167
	 * @since  1.0
168
	 *
169
	 * @return string
170
	 */
171
	public function column_name( $donor ) {
172
		$name     = '#' . $donor['id'] . ' ';
173
		$name     .= ! empty( $donor['name'] ) ? $donor['name'] : '<em>' . __( 'Unnamed Donor', 'give' ) . '</em>';
174
		$view_url = admin_url( 'edit.php?post_type=give_forms&page=give-donors&view=overview&id=' . $donor['id'] );
175
		$actions  = $this->get_row_actions( $donor );
176
177
		return '<a href="' . esc_url( $view_url ) . '">' . $name . '</a>' . $this->row_actions( $actions );
178
	}
179
180
	/**
181
	 * Retrieve the table columns.
182
	 *
183
	 * @access public
184
	 * @since  1.0
185
	 *
186
	 * @return array $columns Array of all the list table columns.
187
	 */
188
	public function get_columns() {
189
		$columns = array(
190
			'cb'            => '<input type="checkbox" />', // Render a checkbox instead of text.
191
			'name'          => __( 'Name', 'give' ),
192
			'email'         => __( 'Email', 'give' ),
193
			'num_donations' => __( 'Donations', 'give' ),
194
			'amount_spent'  => __( 'Total Donated', 'give' ),
195
			'date_created'  => __( 'Date Created', 'give' ),
196
		);
197
198
		return apply_filters( 'give_list_donors_columns', $columns );
199
200
	}
201
202
	/**
203
	 * Get the sortable columns.
204
	 *
205
	 * @access public
206
	 * @since  2.1
207
	 * @return array Array of all the sortable columns.
208
	 */
209 View Code Duplication
	public function get_sortable_columns() {
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...
210
211
		$columns = array(
212
			'date_created'  => array( 'date_created', true ),
213
			'name'          => array( 'name', true ),
214
			'num_donations' => array( 'purchase_count', false ),
215
			'amount_spent'  => array( 'purchase_value', false ),
216
		);
217
218
		return apply_filters( 'give_list_donors_sortable_columns', $columns );
219
	}
220
221
	/**
222
	 * Retrieve row actions.
223
	 *
224
	 * @param array $donor Donor Data.
225
	 *
226
	 * @since  1.7
227
	 * @access public
228
	 *
229
	 * @return array An array of action links.
230
	 */
231
	public function get_row_actions( $donor ) {
232
233
		$actions = array(
234
			'view'   => sprintf( '<a href="%1$s" aria-label="%2$s">%3$s</a>', admin_url( 'edit.php?post_type=give_forms&page=give-donors&view=overview&id=' . $donor['id'] ), sprintf( esc_attr__( 'View "%s"', 'give' ), $donor['name'] ), __( 'View Donor', 'give' ) ),
235
			'notes'  => sprintf( '<a href="%1$s" aria-label="%2$s">%3$s</a>', admin_url( 'edit.php?post_type=give_forms&page=give-donors&view=notes&id=' . $donor['id'] ), sprintf( esc_attr__( 'Notes for "%s"', 'give' ), $donor['name'] ), __( 'Notes', 'give' ) ),
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$donor'
Loading history...
236
			'delete' => sprintf( '<a href="%1$s" aria-label="%2$s">%3$s</a>', admin_url( 'edit.php?post_type=give_forms&page=give-donors&view=delete&id=' . $donor['id'] ), sprintf( esc_attr__( 'Delete "%s"', 'give' ), $donor['name'] ), __( 'Delete', 'give' ) ),
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$donor'
Loading history...
237
		);
238
239
		return apply_filters( 'give_donor_row_actions', $actions, $donor );
240
241
	}
242
243
	/**
244
	 * Retrieve the current page number.
245
	 *
246
	 * @access public
247
	 * @since  1.0
248
	 *
249
	 * @return int Current page number.
250
	 */
251
	public function get_paged() {
252
		return isset( $_GET['paged'] ) ? absint( $_GET['paged'] ) : 1;
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
253
	}
254
255
	/**
256
	 * Retrieves the search query string.
257
	 *
258
	 * @access public
259
	 * @since  1.0
260
	 *
261
	 * @return mixed string If search is present, false otherwise.
262
	 */
263
	public function get_search() {
264
		return ! empty( $_GET['s'] ) ? urldecode( trim( $_GET['s'] ) ) : false;
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
265
	}
266
267
	/**
268
	 * Get the Bulk Actions.
269
	 *
270
	 * @access public
271
	 * @since  1.8.16
272
	 *
273
	 * @return array
274
	 */
275
	public function get_bulk_actions() {
276
		$actions = array(
277
			'delete' => 'Delete',
278
		);
279
		return $actions;
280
	}
281
282
	/**
283
	 * Process the Bulk Actions.
284
	 *
285
	 * @access public
286
	 * @since  1.8.16
287
	 *
288
	 * @return void
289
	 */
290
	public function process_bulk_action() {
291
		$ids    = isset( $_GET['donor'] ) ? $_GET['donor'] : false;
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_GET
Loading history...
292
		$action = $this->current_action();
293
294
		if ( ! is_array( $ids ) ) {
295
			$ids = array( $ids );
296
		}
297
298
		// Bail Out, If Action is not set.
299
		if ( empty( $action ) ) {
300
			return;
301
		}
302
303
		foreach ( $ids as $id ) {
304
305
			// Detect when a bulk action is being triggered.
306
			switch ( $this->current_action() ) {
307
308
				case 'delete':
309
					$args = array(
310
						'_wpnonce'                  => wp_create_nonce( 'delete-donor' ),
311
						'customer_id'               => $id,
312
						'give-donor-delete-confirm' => true,
313
						'give-donor-delete-records' => true,
314
						'redirect'                  => false,
315
					);
316
					give_donor_delete( $args );
317
					break;
318
319
			} // End switch().
320
321
			/**
322
			 * Fires after triggering bulk action on donors table.
323
			 *
324
			 * @param int    $id             The ID of the payment.
325
			 * @param string $current_action The action that is being triggered.
326
			 *
327
			 * @since 1.8.16
328
			 */
329
			do_action( 'give_donors_table_do_bulk_action', $id, $this->current_action() );
330
		} // End foreach().
331
332
	}
333
334
	/**
335
	 * Generate the table navigation above or below the table
336
	 *
337
	 * @param string $which Position to trigger i.e. Top/Bottom.
338
	 *
339
	 * @access protected
340
	 * @since  1.8.16
341
	 */
342
	protected function display_tablenav( $which ) {
343
		if ( 'top' === $which ) {
344
			$this->search_box( __( 'Search Donors', 'give' ), 'give-donors' );
345
			wp_nonce_field( 'bulk-' . $this->_args['plural'] );
346
		}
347
		?>
348
		<div class="tablenav <?php echo esc_attr( $which ); ?>">
349
			<?php if ( $this->has_items() ): ?>
350
				<div class="alignleft actions bulkactions">
351
					<?php $this->bulk_actions( $which ); ?>
352
				</div>
353
			<?php endif;
354
			$this->extra_tablenav( $which );
355
			$this->pagination( $which );
356
			?>
357
			<br class="clear" />
358
		</div>
359
		<?php
360
	}
361
362
	/**
363
	 * Retrieves the donor data from db.
364
	 *
365
	 * @access public
366
	 * @since  1.0
367
	 *
368
	 * @return array $data The Donor data.
369
	 */
370 View Code Duplication
	public function donor_data() {
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...
371
372
		$data = array();
373
374
		// Get donor query.
375
		$args   = $this->get_donor_query();
376
		$donors = Give()->donors->get_donors( $args );
377
378
		if ( $donors ) {
379
380
			foreach ( $donors as $donor ) {
381
382
				$user_id = ! empty( $donor->user_id ) ? intval( $donor->user_id ) : 0;
383
384
				$data[] = array(
385
					'id'            => $donor->id,
386
					'user_id'       => $user_id,
387
					'name'          => $donor->name,
388
					'email'         => $donor->email,
389
					'num_donations' => $donor->purchase_count,
390
					'amount_spent'  => $donor->purchase_value,
391
					'date_created'  => $donor->date_created,
392
				);
393
			}
394
		}
395
396
		return apply_filters( 'give_donors_column_query_data', $data );
397
	}
398
399
	/**
400
	 * Get donor count.
401
	 *
402
	 * @since  1.8.1
403
	 * @access private
404
	 */
405 View Code Duplication
	private function get_donor_count() {
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...
406
		// Get donor query.
407
		$_donor_query = $this->get_donor_query();
408
409
		$_donor_query['number'] = - 1;
410
		$_donor_query['offset'] = 0;
411
		$donors                 = Give()->donors->get_donors( $_donor_query );
412
413
		return count( $donors );
414
	}
415
416
	/**
417
	 * Get donor query.
418
	 *
419
	 * @since  1.8.1
420
	 * @access public
421
	 *
422
	 * @return array
423
	 */
424 View Code Duplication
	public function get_donor_query() {
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...
425
		$paged   = $this->get_paged();
426
		$offset  = $this->per_page * ( $paged - 1 );
427
		$search  = $this->get_search();
428
		$order   = isset( $_GET['order'] ) ? sanitize_text_field( $_GET['order'] ) : 'DESC';
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
429
		$orderby = isset( $_GET['orderby'] ) ? sanitize_text_field( $_GET['orderby'] ) : 'id';
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
430
431
		$args = array(
432
			'number'  => $this->per_page,
433
			'offset'  => $offset,
434
			'order'   => $order,
435
			'orderby' => $orderby,
436
		);
437
438
		if ( $search ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $search of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
439
			if ( is_email( $search ) ) {
440
				$args['email'] = $search;
441
			} elseif ( is_numeric( $search ) ) {
442
				$args['id'] = $search;
443
			} else {
444
				$args['name'] = $search;
445
			}
446
		}
447
448
		return $args;
449
	}
450
451
	/**
452
	 * Setup the final data for the table.
453
	 *
454
	 * @access public
455
	 * @since  1.0
456
	 *
457
	 * @return void
458
	 */
459 View Code Duplication
	public function prepare_items() {
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...
460
461
		$columns  = $this->get_columns();
462
		$hidden   = array(); // No hidden columns.
463
		$sortable = $this->get_sortable_columns();
464
465
		$this->_column_headers = array( $columns, $hidden, $sortable );
466
467
		$this->process_bulk_action();
468
469
		$this->items = $this->donor_data();
470
471
		$this->total = $this->get_donor_count();
472
473
		$this->set_pagination_args( array(
474
			'total_items' => $this->total,
475
			'per_page'    => $this->per_page,
476
			'total_pages' => ceil( $this->total / $this->per_page ),
477
		) );
478
	}
479
}
480