Completed
Pull Request — master (#664)
by Devin
19:01
created

Give_Batch_Export   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 290
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 290
rs 10
wmc 25
lcom 1
cbo 1

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 2
A process_step() 0 21 4
A print_csv_cols() 0 17 3
B print_csv_rows() 0 29 6
A get_percentage_complete() 0 3 1
A get_file() 0 21 3
A stash_step_data() 0 14 3
A export() 0 13 1
A set_properties() 0 1 1
A pre_fetch() 0 1 1
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 22 and the first side effect is on line 15.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Batch Export Class
4
 *
5
 * This is the base class for all batch export methods. Each data export type (customers, payments, etc) extend this class
6
 *
7
 * @package     Give
8
 * @subpackage  Admin/Export
9
 * @copyright   Copyright (c) 2016, WordImpress
10
 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
11
 * @since       1.5
12
 */
13
14
// Exit if accessed directly
15
if ( ! defined( 'ABSPATH' ) ) exit;
16
17
/**
18
 * Give_Batch_Export Class
19
 *
20
 * @since 1.5
21
 */
22
class Give_Batch_Export extends Give_Export {
23
24
	/**
25
	 * The file the data is stored in
26
	 *
27
	 * @since 1.5
28
	 */
29
	private $file;
30
31
	/**
32
	 * The name of the file the data is stored in
33
	 *
34
	 * @since 1.5
35
	 */
36
	public $filename;
37
38
	/**
39
	 * The file type, typically .csv
40
	 *
41
	 * @since 1.5
42
	 */
43
	public $filetype;
44
45
	/**
46
	 * The current step being processed
47
	 *
48
	 * @since 1.5
49
	 */
50
	public $step;
51
52
	/**
53
	 * Start date, Y-m-d H:i:s
54
	 *
55
	 * @since 1.5
56
	 */
57
	public $start;
58
59
	/**
60
	 * End date, Y-m-d H:i:s
61
	 *
62
	 * @since 1.5
63
	 */
64
	public $end;
65
66
	/**
67
	 * Status to export
68
	 *
69
	 * @since 1.5
70
	 */
71
	public $status;
72
73
	/**
74
	 * Form to export data for
75
	 *
76
	 * @since 1.5
77
	 */
78
	public $form = null;
79
80
	/**
81
	 * Form Price ID to export data for
82
	 *
83
	 * @since 1.5
84
	 */
85
	public $price_id = null;
86
87
	/**
88
	 * Is the export file writable
89
	 *
90
	 * @since 1.5
91
	 */
92
	public $is_writable = true;
93
94
	/**
95
	 *  Is the export file empty
96
	 *
97
	 * @since 1.5
98
	 */
99
	public $is_empty = false;
100
101
	/**
102
	 * Get things started
103
	 *
104
	 * @param $_step int The step to process
105
	 * @since 1.5
106
	 */
107
	public function __construct( $_step = 1 ) {
108
109
		$upload_dir       = wp_upload_dir();
110
		$this->filetype   = '.csv';
111
		$this->filename   = 'give-' . $this->export_type . $this->filetype;
112
		$this->file       = trailingslashit( $upload_dir['basedir'] ) . $this->filename;
113
114
		if ( ! is_writeable( $upload_dir['basedir'] ) ) {
115
			$this->is_writable = false;
116
		}
117
118
		$this->step       = $_step;
119
		$this->done       = false;
0 ignored issues
show
Bug introduced by
The property done does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
120
	}
121
122
	/**
123
	 * Process a step
124
	 *
125
	 * @since 1.5
126
	 * @return bool
127
	 */
128
	public function process_step() {
129
130
		if ( ! $this->can_export() ) {
131
			wp_die( __( 'You do not have permission to export data.', 'give' ), __( 'Error', 'give' ), array( 'response' => 403 ) );
132
		}
133
134
		if( $this->step < 2 ) {
135
136
			// Make sure we start with a fresh file on step 1
137
			@unlink( $this->file );
138
			$this->print_csv_cols();
139
		}
140
141
		$rows = $this->print_csv_rows();
142
143
		if( $rows ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $rows 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...
144
			return true;
145
		} else {
146
			return false;
147
		}
148
	}
149
150
	/**
151
	 * Output the CSV columns
152
	 *
153
	 * @access public
154
	 * @since 1.5
155
	 * @uses Give_Export::get_csv_cols()
156
	 * @return string
157
	 */
158
	public function print_csv_cols() {
159
160
		$col_data = '';
161
		$cols = $this->get_csv_cols();
162
		$i = 1;
163
		foreach( $cols as $col_id => $column ) {
164
			$col_data .= '"' . addslashes( $column ) . '"';
165
			$col_data .= $i == count( $cols ) ? '' : ',';
166
			$i++;
167
		}
168
		$col_data .= "\r\n";
169
170
		$this->stash_step_data( $col_data );
171
172
		return $col_data;
173
174
	}
175
176
	/**
177
	 * Print the CSV rows for the current step
178
	 *
179
	 * @access public
180
	 * @since 1.5
181
	 * @return string|false
182
	 */
183
	public function print_csv_rows() {
184
185
		$row_data = '';
186
		$data     = $this->get_data();
187
		$cols     = $this->get_csv_cols();
188
189
		if( $data ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $data 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...
190
191
			// Output each row
192
			foreach ( $data as $row ) {
193
				$i = 1;
194
				foreach ( $row as $col_id => $column ) {
195
					// Make sure the column is valid
196
					if ( array_key_exists( $col_id, $cols ) ) {
197
						$row_data .= '"' . addslashes( preg_replace( "/\"/","'", $column ) ) . '"';
198
						$row_data .= $i == count( $cols ) ? '' : ',';
199
						$i++;
200
					}
201
				}
202
				$row_data .= "\r\n";
203
			}
204
205
			$this->stash_step_data( $row_data );
206
207
			return $row_data;
208
		}
209
210
		return false;
211
	}
212
213
	/**
214
	 * Return the calculated completion percentage
215
	 *
216
	 * @since 1.5
217
	 * @return int
218
	 */
219
	public function get_percentage_complete() {
220
		return 100;
221
	}
222
223
	/**
224
	 * Retrieve the file data is written to
225
	 *
226
	 * @since 1.5
227
	 * @return string
228
	 */
229
	protected function get_file() {
230
231
		$file = '';
232
233
		if ( @file_exists( $this->file ) ) {
234
235
			if ( ! is_writeable( $this->file ) ) {
236
				$this->is_writable = false;
237
			}
238
239
			$file = @file_get_contents( $this->file );
240
241
		} else {
242
243
			@file_put_contents( $this->file, '' );
244
			@chmod( $this->file, 0664 );
245
246
		}
247
248
		return $file;
249
	}
250
251
	/**
252
	 * Append data to export file
253
	 *
254
	 * @since 1.5
255
	 * @param $data string The data to add to the file
256
	 * @return void
257
	 */
258
	protected function stash_step_data( $data = '' ) {
259
260
		$file = $this->get_file();
261
		$file .= $data;
262
		@file_put_contents( $this->file, $file );
263
264
		// If we have no rows after this step, mark it as an empty export
265
		$file_rows    = file( $this->file, FILE_SKIP_EMPTY_LINES);
266
		$default_cols = $this->get_csv_cols();
267
		$default_cols = empty( $default_cols ) ? 0 : 1;
268
269
		$this->is_empty = count( $file_rows ) == $default_cols ? true : false;
270
271
	}
272
273
	/**
274
	 * Perform the export
275
	 *
276
	 * @access public
277
	 * @since 1.5
278
	 * @return void
279
	 */
280
	public function export() {
281
282
		// Set headers
283
		$this->headers();
284
285
		$file = $this->get_file();
286
287
		@unlink( $this->file );
288
289
		echo $file;
290
291
		give_die();
292
	}
293
294
	/*
295
	 * Set the properties specific to the export
296
	 *
297
	 * @since 1.5
298
	 * @param array $request The Form Data passed into the batch processing
299
	 */
300
	public function set_properties( $request ) {}
301
302
	/**
303
	 * Allow for prefetching of data for the remainder of the exporter
304
	 *
305
	 * @access public
306
	 * @since  1.5
307
	 * @return void
308
	 */
309
	public function pre_fetch() {}
310
311
}
312