Completed
Push — develop ( 5c91dc...778b65 )
by Zack
04:09
created

GravityView_Entry_Approval::get_entry_status()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 6
nc 4
nop 2
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
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 23 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
 * @file class-gravityview-entry-approval.php
4
 * @package   GravityView
5
 * @license   GPL2+
6
 * @author    Katz Web Services, Inc.
7
 * @link      https://gravityview.co
8
 * @copyright Copyright 2016, Katz Web Services, Inc.
9
 *
10
 * @since 1.18
11
 */
12
13
/** If this file is called directly, abort. */
14
if ( ! defined( 'ABSPATH' ) ) {
15
	die;
16
}
17
18
/**
19
 * Generate linked list output for a list of entries.
20
 *
21
 * @since 1.18
22
 */
23
class GravityView_Entry_Approval {
24
25
	/**
26
	 * @var string Key used to store approval status in the Gravity Forms entry meta table
27
	 */
28
	const meta_key = 'is_approved';
29
30
	public function __construct() {
31
		$this->add_hooks();
32
	}
33
34
	/**
35
	 * Add actions and filters related to entry approval
36
	 *
37
	 * @return void
38
	 */
39
	private function add_hooks() {
40
41
		// in case entry is edited (on admin or frontend)
42
		add_action( 'gform_after_update_entry', array( $this, 'after_update_entry_update_approved_meta' ), 10, 2);
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
43
44
		// when using the User opt-in field, check on entry submission
45
		add_action( 'gform_after_submission', array( $this, 'after_submission' ), 10, 2 );
46
47
		// process ajax approve entry requests
48
		add_action('wp_ajax_gv_update_approved', array( $this, 'ajax_update_approved'));
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
introduced by
No space before closing parenthesis of array is bad style
Loading history...
49
50
	}
51
52
	/**
53
	 * Get the approval status for an entry
54
	 *
55
	 * @since 1.18
56
	 * @uses GVCommon::get_entry_id() Accepts entry slug or entry ID
57
	 *
58
	 * @param array|int|string $entry Entry array, entry slug, or entry ID
59
	 * @param string $value_or_label "value" or "label" (default: "label")
60
	 *
61
	 * @return bool|string Return the label or value of entry approval
62
	 */
63
	public static function get_entry_status( $entry, $value_or_label = 'label' ) {
64
65
		$entry_id = is_array( $entry ) ? $entry['id'] : GVCommon::get_entry_id( $entry );
66
67
		$status = gform_get_meta( $entry_id, self::meta_key );
68
69
		if( 'value' === $value_or_label ) {
70
			return GravityView_Entry_Approval_Status::maybe_convert_status( $status );
71
		}
72
73
		return GravityView_Entry_Approval_Status::get_label( $value );
0 ignored issues
show
Bug introduced by
The variable $value does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
74
	}
75
76
	/**
77
	 * Approve/Disapprove entries using the × or ✓ icons in the GF Entries screen
78
	 *
79
	 * @uses wp_send_json_error()
80
	 * @uses wp_send_json_success()
81
	 *
82
	 * Expects a $_POST request with the following $_POST keys and values:
83
	 *
84
	 * @global array $_POST {
85
	 * @type int $form_id ID of the form connected to the entry being updated
86
	 * @type string|int $entry_slug The ID or slug of the entry being updated
87
	 * @type string $approved The value of the entry approval status {@see GravityView_Entry_Approval_Status::is_valid() }
88
	 * }
89
	 *
90
	 * @return void Prints result using wp_send_json_success() and wp_send_json_error()
91
	 */
92
	public function ajax_update_approved() {
93
94
		$form_id = intval( rgpost('form_id') );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
95
96
		$entry_id = GVCommon::get_entry_id( rgpost('entry_slug') );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
97
98
		$approval_status = rgpost('approved');
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
99
100
		$nonce = rgpost('nonce');
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
101
102
		// Valid status
103
		if( ! GravityView_Entry_Approval_Status::is_valid( $approval_status ) ) {
104
105
			do_action( 'gravityview_log_error', __METHOD__ . ': Invalid approval status', $_POST );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
106
107
			$result = new WP_Error( 'invalid_status', __( 'The request was invalid. Refresh the page and try again.', 'gravityview' ) );
108
109
		}
110
111
		// Valid values
112
		elseif ( empty( $entry_id ) || empty( $form_id ) ) {
113
114
			do_action( 'gravityview_log_error', __METHOD__ . ' entry_id or form_id are empty.', $_POST );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
115
116
			$result = new WP_Error( 'empty_details', __( 'The request was invalid. Refresh the page and try again.', 'gravityview' ) );
117
118
		}
119
120
		// Valid nonce
121
		else if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'gravityview_entry_approval' ) ) {
122
123
			do_action( 'gravityview_log_error', __METHOD__ . ' Security check failed.', $_POST );
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
124
125
			$result = new WP_Error( 'invalid_nonce', __( 'The request was invalid. Refresh the page and try again.', 'gravityview' ) );
126
127
		}
128
129
		// Has capability
130
		elseif ( ! GVCommon::has_cap( 'gravityview_moderate_entries', $entry_id ) ) {
131
132
			do_action( 'gravityview_log_error', __METHOD__ . ' User does not have the `gravityview_moderate_entries` capability.' );
133
134
			$result = new WP_Error( 'Missing Cap: gravityview_moderate_entries', __( 'You do not have permission to edit this entry.', 'gravityview') );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
135
136
		}
137
138
		// All checks passed
139
		else {
140
141
			$result = self::update_approved( $entry_id, $approval_status, $form_id );
142
143
		}
144
145
		if ( is_wp_error( $result ) ) {
146
			do_action( 'gravityview_log_error', __METHOD__ . ' Error updating approval: ' . $result->get_error_message() );
147
148
			wp_send_json_error( $result );
149
		}
150
151
		wp_send_json_success();
152
	}
153
154
	/**
155
	 * Update the is_approved meta whenever the entry is submitted (and it contains a User Opt-in field)
156
	 *
157
	 * @since 1.16.6
158
	 *
159
	 * @param $entry array Gravity Forms entry object
160
	 * @param $form array Gravity Forms form object
161
	 */
162
	public function after_submission( $entry, $form ) {
163
		$this->after_update_entry_update_approved_meta( $form , $entry['id'] );
164
	}
165
166
	/**
167
	 * Update the is_approved meta whenever the entry is updated
168
	 *
169
	 * @since 1.7.6.1 Was previously named `update_approved_meta`
170
	 *
171
	 * @param  array $form     Gravity Forms form array
172
	 * @param  int $entry_id ID of the Gravity Forms entry
173
	 * @return void
174
	 */
175
	public function after_update_entry_update_approved_meta( $form, $entry_id = NULL ) {
0 ignored issues
show
Coding Style introduced by
TRUE, FALSE and NULL must be lowercase; expected null, but found NULL.
Loading history...
176
177
		$approved_column = self::get_approved_column( $form['id'] );
178
179
		/**
180
		 * If the form doesn't contain the approve field, don't assume anything.
181
		 */
182
		if( empty( $approved_column ) ) {
183
			return;
184
		}
185
186
		$entry = GFAPI::get_entry( $entry_id );
187
188
		self::update_approved_meta( $entry_id, $entry[ (string)$approved_column ], $form['id'] );
0 ignored issues
show
introduced by
No space after closing casting parenthesis is prohibited
Loading history...
189
	}
190
191
	/**
192
	 * Process a bulk of entries to update the approve field/property
193
	 *
194
	 * @since 1.18 Moved to GravityView_Entry_Approval
195
	 * @since 1.18 Made public
196
	 *
197
	 * @access public
198
	 * @static
199
	 * @param array|boolean $entries If array, array of entry IDs that are to be updated. If true: update all entries.
200
	 * @param int $approved Approved status. If `0`: unapproved, if not empty, `Approved`
201
	 * @param int $form_id The Gravity Forms Form ID
202
	 * @return boolean|void
203
	 */
204
	public static function update_bulk( $entries = array(), $approved, $form_id ) {
205
206
		if( empty($entries) || ( $entries !== true && !is_array($entries) ) ) {
0 ignored issues
show
introduced by
Found "!== true". Use Yoda Condition checks, you must
Loading history...
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
introduced by
Expected 1 space after "!"; 0 found
Loading history...
207
			do_action( 'gravityview_log_error', __METHOD__ . ' Entries were empty or malformed.', $entries );
208
			return false;
209
		}
210
211
		if( ! GVCommon::has_cap( 'gravityview_moderate_entries' ) ) {
212
			do_action( 'gravityview_log_error', __METHOD__ . ' User does not have the `gravityview_moderate_entries` capability.' );
213
			return false;
214
		}
215
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
216
217
		if ( ! GravityView_Entry_Approval_Status::is_valid( $approved ) ) {
218
			do_action( 'gravityview_log_error', __METHOD__ . ' Invalid approval status', $approved );
219
			return false;
220
		}
221
222
		// calculate approved field id once instead of looping through in the update_approved() method
223
		$approved_column_id = self::get_approved_column( $form_id );
224
225
		foreach( $entries as $entry_id ) {
0 ignored issues
show
Bug introduced by
The expression $entries of type boolean|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...
226
			self::update_approved( (int)$entry_id, $approved, $form_id, $approved_column_id );
0 ignored issues
show
introduced by
No space after closing casting parenthesis is prohibited
Loading history...
227
		}
228
	}
229
230
	/**
231
	 * update_approved function.
232
	 *
233
	 * @since 1.18 Moved to GravityView_Entry_Approval class
234
	 *
235
	 * @access public
236
	 * @static
237
	 * @param int $entry_id (default: 0)
238
	 * @param int $approved (default: 0)
239
	 * @param int $form_id (default: 0)
240
	 * @param int $approvedcolumn (default: 0)
241
	 *
242
	 * @return boolean True: It worked; False: it failed
243
	 */
244
	public static function update_approved( $entry_id = 0, $approved = 0, $form_id = 0, $approvedcolumn = 0 ) {
245
246
		if( !class_exists( 'GFAPI' ) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
247
			do_action( 'gravityview_log_error', __METHOD__ . 'GFAPI does not exist' );
248
			return false;
249
		}
250
251
		if( ! GravityView_Entry_Approval_Status::is_valid( $approved ) ) {
252
			do_action( 'gravityview_log_error', __METHOD__ . ': Not a valid approval value.' );
253
			return false;
254
		}
255
256
		$result = self::update_approved_column( $entry_id, $approved, $form_id, $approvedcolumn );
257
258
		/**
259
		 * GFAPI::update_entry() doesn't trigger `gform_after_update_entry`, so we trigger updating the meta ourselves.
260
		 */
261
		self::update_approved_meta( $entry_id, $approved, $form_id );
262
263
		// add note to entry if approval field updating worked or there was no approved field
264
		// There's no validation for the meta
265
		if( true === $result ) {
266
267
			switch ( $approved ) {
268
				case GravityView_Entry_Approval_Status::APPROVED:
269
					$note = __( 'Approved the Entry for GravityView', 'gravityview' );
270
					break;
271
				case GravityView_Entry_Approval_Status::UNAPPROVED:
272
					$note = __( 'Reset Entry approval for GravityView', 'gravityview' );
273
					break;
274
				case GravityView_Entry_Approval_Status::DISAPPROVED:
275
					$note = __( 'Disapproved the Entry for GravityView', 'gravityview' );
276
					break;
277
			}
278
279
			/**
280
			 * @filter `gravityview/approve_entries/add-note` Add a note when the entry has been approved or disapproved?
281
			 * @since 1.16.3
282
			 * @param bool $add_note True: Yep, add that note! False: Do not, under any circumstances, add that note!
283
			 */
284
			$add_note = apply_filters( 'gravityview/approve_entries/add-note', true );
285
286
			if( $add_note && class_exists( 'GravityView_Entry_Notes' ) ) {
287
				$current_user = wp_get_current_user();
288
				GravityView_Entry_Notes::add_note( $entry_id, $current_user->ID, $current_user->display_name, $note );
0 ignored issues
show
Bug introduced by
The variable $note does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
289
			}
290
291
			/**
292
			 * Destroy the cache for this form
293
			 * @see class-cache.php
294
			 * @since 1.5.1
295
			 */
296
			do_action( 'gravityview_clear_form_cache', $form_id );
297
298
		} else if( is_wp_error( $result ) ) {
299
300
			do_action( 'gravityview_log_error', __METHOD__ . sprintf( ' - Entry approval not updated: %s', $result->get_error_message() ) );
301
302
			$result = false;
303
		}
304
305
		return $result;
306
	}
307
308
	/**
309
	 * Update the Approve/Disapproved field value
310
	 *
311
	 * @param  int $entry_id ID of the Gravity Forms entry
312
	 * @param  string $status String whether entry is approved or not. `0` for not approved, `Approved` for approved.
313
	 * @param int $form_id ID of the form of the entry being updated. Improves query performance.
314
	 * @param string $approvedcolumn Gravity Forms Field ID
315
	 *
316
	 * @return true|WP_Error
317
	 */
318
	private static function update_approved_column( $entry_id = 0, $status = '0', $form_id = 0, $approvedcolumn = 0 ) {
319
320
		if( empty( $approvedcolumn ) ) {
321
			$approvedcolumn = self::get_approved_column( $form_id );
322
		}
323
324
		if ( empty( $approvedcolumn ) ) {
325
			return true;
326
		}
327
328
		if ( ! GravityView_Entry_Approval_Status::is_valid( $status ) ) {
329
			return new WP_Error( 'invalid_status', 'Invalid entry approval status', $status );
330
		}
331
332
		//get the entry
333
		$entry = GFAPI::get_entry( $entry_id );
334
335
		//update entry
336
		$entry[ (string)$approvedcolumn ] = $status;
0 ignored issues
show
introduced by
No space after closing casting parenthesis is prohibited
Loading history...
337
338
		/** @var bool|WP_Error $result */
339
		$result = GFAPI::update_entry( $entry );
340
341
		return $result;
342
	}
343
344
	/**
345
	 * Update the `is_approved` entry meta value
346
	 *
347
	 * @since 1.7.6.1 `after_update_entry_update_approved_meta` was previously to be named `update_approved_meta`
348
	 * @since 1.17.1 Added $form_id parameter
349
	 *
350
	 * @param  int $entry_id ID of the Gravity Forms entry
351
	 * @param  string $status String whether entry is approved or not. `0` for not approved, `Approved` for approved.
352
	 * @param int $form_id ID of the form of the entry being updated. Improves query performance.
353
	 *
354
	 * @return void
355
	 */
356
	private static function update_approved_meta( $entry_id, $status, $form_id = 0 ) {
357
358
		if ( ! GravityView_Entry_Approval_Status::is_valid( $status ) ) {
359
			do_action('gravityview_log_error', __METHOD__ . ': $is_approved not valid value', $status );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
360
			return;
361
		}
362
363
		// update entry meta
364
		if( function_exists('gform_update_meta') ) {
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
365
366
			if( GravityView_Entry_Approval_Status::is_unapproved( $status ) ) {
367
				gform_delete_meta( $entry_id, self::meta_key );
368
			} else {
369
				gform_update_meta( $entry_id, self::meta_key, $status, $form_id );
370
			}
371
372
			/**
373
			 * @action `gravityview/approve_entries/updated` Triggered when an entry approval is updated
374
			 * @since 1.7.6.1
375
			 * @param  int $entry_id ID of the Gravity Forms entry
376
			 * @param  string|int $status String whether entry is approved or not. See GravityView_Entry_Approval_Status for valid statuses.
377
			 */
378
			do_action( 'gravityview/approve_entries/updated', $entry_id, $status );
379
380
			switch ( $status ) {
381
				case GravityView_Entry_Approval_Status::APPROVED:
382
					$action = 'approved';
383
					break;
384
				case GravityView_Entry_Approval_Status::UNAPPROVED:
385
					$action = 'unapproved';
386
					break;
387
				case GravityView_Entry_Approval_Status::DISAPPROVED:
388
				default:
389
					$action = 'disapproved';
390
					break;
391
			}
392
393
			/**
394
			 * @action `gravityview/approve_entries/{$action}` Triggered when an entry approval is reset.
395
			 * $action can be 'approved', 'unapproved', or 'disapproved'
396
			 * @since 1.7.6.1
397
			 * @since 1.18 Added "unapproved"
398
			 * @param  int $entry_id ID of the Gravity Forms entry
399
			 */
400
			do_action( 'gravityview/approve_entries/' . $action , $entry_id );
401
402
		} else {
403
404
			do_action('gravityview_log_error', __METHOD__ . ' - `gform_update_meta` does not exist.' );
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
405
406
		}
407
	}
408
409
	/**
410
	 * Calculate the approve field.input id
411
	 *
412
	 * @access public
413
	 * @static
414
	 * @param mixed $form GF Form or Form ID
415
	 * @return false|null|string Returns the input ID of the approved field. Returns NULL if no approved fields were found. Returns false if $form_id wasn't set.
416
	 */
417
	static public function get_approved_column( $form ) {
0 ignored issues
show
Coding Style introduced by
As per PSR2, the static declaration should come after the visibility declaration.
Loading history...
418
419
		if( empty( $form ) ) {
420
			return null;
421
		}
422
423
		if( !is_array( $form ) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
424
			$form = GVCommon::get_form( $form );
425
		}
426
427
		foreach( $form['fields'] as $key => $field ) {
428
429
			$field = (array) $field;
430
431
			if( !empty( $field['gravityview_approved'] ) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
432
				if( !empty($field['inputs'][0]['id']) ) {
0 ignored issues
show
introduced by
Expected 1 space after "!"; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
433
					return $field['inputs'][0]['id'];
434
				}
435
			}
436
437
			// Note: This is just for backward compatibility from GF Directory plugin and old GV versions - when using i18n it may not work..
438
			if( 'checkbox' == $field['type'] && isset( $field['inputs'] ) && is_array( $field['inputs'] ) ) {
439
				foreach ( $field['inputs'] as $key2 => $input ) {
440
					if ( strtolower( $input['label'] ) == 'approved' ) {
0 ignored issues
show
introduced by
Found "== '". Use Yoda Condition checks, you must
Loading history...
441
						return $input['id'];
442
					}
443
				}
444
			}
445
		}
446
447
		return null;
448
	}
449
450
}
451
452
new GravityView_Entry_Approval;