Test Failed
Push — issues/2980 ( 6931f9 )
by Ravinder
05:32
created

Give_Export_Donations_CSV::set_properties()   C

Complexity

Conditions 12
Paths 1536

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 11
nc 1536
nop 1
dl 0
loc 16
rs 5.3132
c 0
b 0
f 0

How to fix   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
 * Payments Export Class.
4
 *
5
 * This class handles payment export in batches.
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
/**
20
 * Give_Export_Donations_CSV Class
21
 *
22
 * @since 1.0
23
 */
24
class Give_Export_Donations_CSV extends Give_Batch_Export {
25
26
	/**
27
	 * Our export type. Used for export-type specific filters/actions.
28
	 *
29
	 * @var string
30
	 * @since 1.0
31
	 */
32
	public $export_type = 'payments';
33
34
	/**
35
	 * Form submission data.
36
	 *
37
	 * @var array
38
	 * @since 1.0
39
	 */
40
	private $data = array();
41
42
	/**
43
	 * Form submission data.
44
	 *
45
	 * @var array
46
	 * @since 1.0
47
	 */
48
	private $cols = array();
49
50
	/**
51
	 * Form ID.
52
	 *
53
	 * @var string
54
	 * @since 1.0
55
	 */
56
	private $form_id = '';
57
58
	/**
59
	 * Set the properties specific to the export.
60
	 *
61
	 * @since 1.0
62
	 *
63
	 * @param array $request The Form Data passed into the batch processing.
64
	 */
65
	public function set_properties( $request ) {
66
67
		// Set data from form submission
68
		if ( isset( $_POST['form'] ) ) {
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
69
			parse_str( $_POST['form'], $this->data );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
70
		}
71
72
		$this->form       = $this->data['forms'];
73
		$this->form_id    = ! empty( $request['forms'] ) && 0 !== $request['forms'] ? absint( $request['forms'] ) : null;
74
		$this->price_id   = isset( $request['give_price_option'] ) && ( 'all' !== $request['give_price_option'] && '' !== $request['give_price_option'] ) ? absint( $request['give_price_option'] ) : null;
75
		$this->start      = isset( $request['start'] ) ? sanitize_text_field( $request['start'] ) : '';
76
		$this->end        = isset( $request['end'] ) ? sanitize_text_field( $request['end'] ) : '';
77
		$this->status     = isset( $request['status'] ) ? sanitize_text_field( $request['status'] ) : 'complete';
78
		$this->categories = isset( $request['give_forms_categories'] ) ? sanitize_text_field( $request['give_forms_categories'] ) : array();
79
		$this->tags       = isset( $request['give_forms_tags'] ) ? sanitize_text_field( $request['give_forms_tags'] ) : array();
80
	}
81
82
	/**
83
	 * Set the CSV columns.
84
	 *
85
	 * @access public
86
	 * @since  1.0
87
	 * @return array|bool $cols All the columns.
88
	 */
89
	public function csv_cols() {
90
91
		$columns = isset( $this->data['give_give_donations_export_option'] ) ? $this->data['give_give_donations_export_option'] : array();
92
93
		// We need columns.
94
		if ( empty( $columns ) ) {
95
			return false;
96
		}
97
98
		$this->cols = $this->get_cols( $columns );
99
100
		return $this->cols;
101
	}
102
103
104
	/**
105
	 * CSV file columns.
106
	 *
107
	 * @param array $columns
108
	 *
109
	 * @return array
110
	 */
111
	private function get_cols( $columns ) {
112
113
		$cols = array();
114
115
		foreach ( $columns as $key => $value ) {
116
117
			switch ( $key ) {
118
				case 'donation_id' :
119
					$cols['donation_id'] = __( 'Donation ID', 'give' );
120
					break;
121
				case 'first_name' :
122
					$cols['first_name'] = __( 'First Name', 'give' );
123
					break;
124
				case 'last_name' :
125
					$cols['last_name'] = __( 'Last Name', 'give' );
126
					break;
127
				case 'email' :
128
					$cols['email'] = __( 'Email Address', 'give' );
129
					break;
130 View Code Duplication
				case 'address' :
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...
131
					$cols['address_line1']   = __( 'Address 1', 'give' );
132
					$cols['address_line2']   = __( 'Address 2', 'give' );
133
					$cols['address_city']    = __( 'City', 'give' );
134
					$cols['address_state']   = __( 'State', 'give' );
135
					$cols['address_zip']     = __( 'Zip', 'give' );
136
					$cols['address_country'] = __( 'Country', 'give' );
137
					break;
138
				case 'donation_total' :
139
					$cols['donation_total'] = sprintf( __( 'Donation Total (%s)', 'give' ), give_currency_symbol() );
140
					break;
141
				case 'donation_status' :
142
					$cols['donation_status'] = __( 'Donation Status', 'give' );
143
					break;
144
				case 'payment_gateway' :
145
					$cols['payment_gateway'] = __( 'Payment Gateway', 'give' );
146
					break;
147
				case 'form_id' :
148
					$cols['form_id'] = __( 'Form ID', 'give' );
149
					break;
150
				case 'form_title' :
151
					$cols['form_title'] = __( 'Form Title', 'give' );
152
					break;
153
				case 'form_level_id' :
154
					$cols['form_level_id'] = __( 'Level ID', 'give' );
155
					break;
156
				case 'form_level_title' :
157
					$cols['form_level_title'] = __( 'Level Title', 'give' );
158
					break;
159
				case 'donation_date' :
160
					$cols['donation_date'] = __( 'Donation Date', 'give' );
161
					break;
162
				case 'donation_time' :
163
					$cols['donation_time'] = __( 'Donation Time', 'give' );
164
					break;
165
				case 'userid' :
166
					$cols['userid'] = __( 'User ID', 'give' );
167
					break;
168
				case 'donorid' :
169
					$cols['donorid'] = __( 'Donor ID', 'give' );
170
					break;
171
				case 'donor_ip' :
172
					$cols['donor_ip'] = __( 'Donor IP Address', 'give' );
173
					break;
174
				default:
175
					$cols[ $key ] = $key;
176
177
			}
178
		}
179
180
		return $cols;
181
182
	}
183
184
185
	/**
186
	 * Get the Export Data.
187
	 *
188
	 * @access public
189
	 * @since  1.0
190
	 * @global object $wpdb Used to query the database using the WordPress database API.
191
	 * @return array $data The data for the CSV file.
192
	 */
193
	public function get_data() {
194
195
		$data = array();
196
		$i    = 0;
197
198
		$args = array(
199
			'number'     => 30,
200
			'page'       => $this->step,
201
			'status'     => $this->status,
202
		);
203
204
		// Date query.
205
		if ( ! empty( $this->start ) || ! empty( $this->end ) ) {
206
207
			if ( ! empty( $this->start ) ) {
208
				$args['date_query'][0]['after'] = date( 'Y-n-d 00:00:00', strtotime( $this->start ) );
209
			}
210
211
			if ( ! empty( $this->end ) ) {
212
				$args['date_query'][0]['before'] = date( 'Y-n-d 00:00:00', strtotime( $this->end ) );
213
			}
214
		}
215
216
		// Check for price option
217 View Code Duplication
		if ( null !== $this->price_id ) {
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...
218
			$args['meta_query'] = array(
0 ignored issues
show
introduced by
Detected usage of meta_query, possible slow query.
Loading history...
219
				array(
220
					'key'   => '_give_payment_price_id',
221
					'value' => (int) $this->price_id,
222
				),
223
			);
224
		}
225
226
		if ( ! empty( $this->form_id ) ) {
227
			$args['give_forms'] = array( $this->form_id );
228
		}
229
230
		// Payment query.
231
		$payments = give_get_payments( $args );
232
233
		if ( $payments ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $payments of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
234
235
			foreach ( $payments as $payment ) {
236
237
				$columns      = $this->csv_cols();
238
				$payment_meta = give_get_payment_meta( $payment->ID );
239
				$payment      = new Give_Payment( $payment->ID );
240
				$donor     = new Give_Donor( give_get_payment_donor_id( $payment->ID ) );
241
				$address      = '';
242
243
				if ( isset( $donor->user_id ) && $donor->user_id > 0 ) {
244
					$address = give_get_donor_address( $donor->user_id );
245
				}
246
				$name_array = explode( ' ', $donor->name );
247
248
				// Set columns
249
				if ( ! empty( $this->cols['donation_id'] ) ) {
250
					$data[ $i ]['donation_id'] = $payment->ID;
251
				}
252
				if ( ! empty( $this->cols['first_name'] ) ) {
253
					$data[ $i ]['first_name'] = isset( $name_array[0] ) ? $name_array[0] : '';
254
				}
255
				if ( ! empty( $this->cols['last_name'] ) ) {
256
					$data[ $i ]['last_name'] = ( isset( $name_array[1] ) ? $name_array[1] : '' ) . ( isset( $name_array[2] ) ? ' ' . $name_array[2] : '' ) . ( isset( $name_array[3] ) ? ' ' . $name_array[3] : '' );
257
				}
258
				if ( ! empty( $this->cols['email'] ) ) {
259
					$data[ $i ]['email'] = $donor->email;
260
				}
261 View Code Duplication
				if ( ! empty( $this->cols['address_line1'] ) ) {
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...
262
					$data[ $i ]['address_line1']   = isset( $address['line1'] ) ? $address['line1'] : '';
263
					$data[ $i ]['address_line2']   = isset( $address['line2'] ) ? $address['line2'] : '';
264
					$data[ $i ]['address_city']    = isset( $address['city'] ) ? $address['city'] : '';
265
					$data[ $i ]['address_state']   = isset( $address['state'] ) ? $address['state'] : '';
266
					$data[ $i ]['address_zip']     = isset( $address['zip'] ) ? $address['zip'] : '';
267
					$data[ $i ]['address_country'] = isset( $address['country'] ) ? $address['country'] : '';
268
				}
269
270
				if ( ! empty( $this->cols['donation_total'] ) ) {
271
					$data[ $i ]['donation_total'] = give_format_amount( give_get_payment_amount( $payment->ID ) );
272
				}
273
274
				if ( ! empty( $columns['donation_status'] ) ) {
275
					$data[ $i ]['donation_status'] = give_get_payment_status( $payment, true );
276
				}
277
278
				if ( ! empty( $columns['payment_gateway'] ) ) {
279
					$data[ $i ]['payment_gateway'] = $payment->gateway;
280
				}
281
282
				if ( ! empty( $columns['form_id'] ) ) {
283
					$data[ $i ]['form_id'] = $payment->form_id;
284
				}
285
286
				if ( ! empty( $columns['form_title'] ) ) {
287
					$data[ $i ]['form_title'] = get_the_title( $payment->form_id );
288
				}
289
290
				if ( ! empty( $columns['form_level_id'] ) ) {
291
					$data[ $i ]['form_level_id'] = $payment->price_id;
292
				}
293
294
				if ( ! empty( $columns['form_level_title'] ) ) {
295
					$var_prices = give_has_variable_prices( $payment_meta['form_id'] );
296
					if ( empty( $var_prices ) ) {
297
						$data[ $i ]['form_level_title'] = '';
298
					} else {
299
						$prices_atts = '';
300 View Code Duplication
						if ( $variable_prices = give_get_variable_prices( $payment_meta['form_id'] ) ) {
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...
301
							foreach ( $variable_prices as $variable_price ) {
302
								$prices_atts[ $variable_price['_give_id']['level_id'] ] = give_format_amount( $variable_price['_give_amount'] );
303
							}
304
						}
305
						$data[ $i ]['form_level_title'] = give_get_price_option_name( $payment->form_id, $payment->price_id );
306
					}
307
				}
308
309
				if ( ! empty( $columns['donation_date'] ) ) {
310
					$payment_date                = strtotime( $payment->date );
311
					$data[ $i ]['donation_date'] = date( give_date_format(), $payment_date );
312
				}
313
314
				if ( ! empty( $columns['donation_time'] ) ) {
315
					$payment_date                = strtotime( $payment->date );
316
					$data[ $i ]['donation_time'] = date_i18n( 'H', $payment_date ) . ':' . date( 'i', $payment_date );
317
				}
318
319
				if ( ! empty( $columns['userid'] ) ) {
320
					$data[ $i ]['userid'] = $payment->user_id;
321
				}
322
323
				if ( ! empty( $columns['donorid'] ) ) {
324
					$data[ $i ]['donorid'] = $payment->customer_id;
325
				}
326
327
				if ( ! empty( $columns['donor_ip'] ) ) {
328
					$data[ $i ]['donor_ip'] = give_get_payment_user_ip( $payment->ID );
329
				}
330
331
				// Add custom field data.
332
				// First we remove the standard included keys from above.
333
				$remove_keys = array(
334
					'donation_id',
335
					'first_name',
336
					'last_name',
337
					'email',
338
					'address_line1',
339
					'address_line2',
340
					'address_city',
341
					'address_state',
342
					'address_zip',
343
					'address_country',
344
					'donation_total',
345
					'payment_gateway',
346
					'form_id',
347
					'form_title',
348
					'form_level_id',
349
					'form_level_title',
350
					'donation_date',
351
					'donation_time',
352
					'userid',
353
					'donorid',
354
					'donor_ip',
355
				);
356
357
				// Removing above keys...
358
				foreach ( $remove_keys as $key ) {
359
					unset( $columns[ $key ] );
360
				}
361
362
				// Is FFM available? Take care of repeater fields.
363
				if ( class_exists( 'Give_FFM_Render_Form' ) ) {
364
365
					// Get the custom fields for the payment's form.
366
					$ffm = new Give_FFM_Render_Form();
367
					list(
368
						$post_fields,
0 ignored issues
show
Unused Code introduced by
The assignment to $post_fields is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
369
						$taxonomy_fields,
0 ignored issues
show
Unused Code introduced by
The assignment to $taxonomy_fields is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
370
						$custom_fields
371
						) = $ffm->get_input_fields( $payment->form_id );
372
					$parents = isset( $this->data['give_give_donations_export_parent'] ) ? $this->data['give_give_donations_export_parent'] : array();
373
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
374
375
					// Loop through the fields.
376
					foreach ( $custom_fields as $field ) {
377
378
						// Check if this custom field should be exported first.
379
						if ( empty( $parents[ $field['name'] ] ) ) {
380
							continue;
381
						}
382
383
						// Check for Repeater Columns
384
						if ( isset( $field['multiple'] ) ) {
385
386
							$num_columns = count( $field['columns'] );
387
388
							// Loop through columns
389
							for ( $count = 0; $count < $num_columns; $count ++ ) {
390
								$keyname = 'repeater_' . give_export_donations_create_column_key( $field['columns'][ $count ] );
391
								$items   = (array) $ffm->get_meta( $payment->ID, $field['name'], 'post', false );
392
393
								// Reassemble arrays.
394
								if ( $items ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $items of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
395
396
									$final_vals = array();
397
398
									foreach ( $items as $item_val ) {
399
400
										$item_val = explode( $ffm::$separator, $item_val );
401
402
										// Add relevant fields to array.
403
										$final_vals[ $count ][] = $item_val[ $count ];
404
405
									}
406
407
									$data[ $i ][ $keyname ] = implode( '| ', $final_vals[ $count ] );
408
409
								} else {
410
									$data[ $i ][ $keyname ] = '';
411
								}
412
413
								$this->cols[ $keyname ] = '';
414
415
								unset( $columns[ $keyname ] );
416
417
							}
418
419
							unset( $this->cols[ $field['name'] ] );
420
							// Unset this to prevent field from catchall field loop below.
421
							unset( $columns[ $field['name'] ] );
422
						}
423
					}
424
				}
425
426
				// Now loop through remaining meta fields.
427
				foreach ( $columns as $col ) {
0 ignored issues
show
Bug introduced by
The expression $columns of type false|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
428
					$field_data         = get_post_meta( $payment->ID, $col, true );
429
					$data[ $i ][ $col ] = $field_data;
430
					unset( $columns[ $col ] );
431
				}
432
433
				// Increment iterator.
434
				$i ++;
435
436
			}
437
438
			$data = apply_filters( 'give_export_get_data', $data );
439
			$data = apply_filters( "give_export_get_data_{$this->export_type}", $data );
440
441
			return $data;
442
443
		}
444
445
		return array();
446
447
	}
448
449
450
	/**
451
	 * Return the calculated completion percentage.
452
	 *
453
	 * @since 1.0
454
	 * @return int
455
	 */
456
	public function get_percentage_complete() {
457
458
		$status = $this->status;
459
		$args   = array(
460
			'start-date' => date( 'n/d/Y', strtotime( $this->start ) ),
461
			'end-date'   => date( 'n/d/Y', strtotime( $this->end ) ),
462
		);
463
464
		if ( 'any' == $status ) {
465
			$total = array_sum( (array) give_count_payments( $args ) );
466
		} else {
467
			$total = give_count_payments( $args )->$status;
468
		}
469
470
		$percentage = 100;
471
472
		if ( $total > 0 ) {
473
			$percentage = ( ( 30 * $this->step ) / $total ) * 100;
474
		}
475
476
		if ( $percentage > 100 ) {
477
			$percentage = 100;
478
		}
479
480
		return $percentage;
481
	}
482
483
}
484