Completed
Push — issues/1038 ( 82582b...329a72 )
by Ravinder
16:57
created

Give_Form_API::set_default_values()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 31
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 4
nop 1
dl 0
loc 31
rs 8.8571
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 12 and the first side effect is on line 497.

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
/**
4
 * Form API
5
 *
6
 * @package     Give
7
 * @subpackage  Classes/Give_Form_API
8
 * @copyright   Copyright (c) 2016, WordImpress
9
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
10
 * @since       2.0
11
 */
12
class Give_Form_API {
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
13
	/**
14
	 * Instance.
15
	 *
16
	 * @since  2.0
17
	 * @access private
18
	 * @var Give_Form_API
19
	 */
20
	static private $instance;
21
22
	/**
23
	 * Array of forms.
24
	 *
25
	 * @since  2.0
26
	 * @access private
27
	 * @var array
28
	 */
29
	private static $forms = array();
30
31
	/**
32
	 * The defaults for all elements
33
	 *
34
	 * @since  2.0
35
	 * @access static
36
	 */
37
	static $field_defaults = array(
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $field_defaults.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

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

Loading history...
38
		'id'                    => '',
39
		'method'                => 'post',
40
		'action'                => '',
41
		'fields'                => array(),
42
43
		// Sort field by priority.
44
		// If this param set to true then define priority for each field.
45
		'sort_by_priority'      => false,
46
47
		// This param will help to generate w3c validated form otherwise
48
		// Some conflict can occur if you use same form twice or multiple times on same page for example id conflict.
49
		'set_unique_id'         => true,
50
51
52
		// Add custom attributes.
53
		'form_attributes'       => array(),
54
55
		// Supported form layout: simple, stepper, reveal, modal, button.
56
		'display_style'         => 'simple',
57
		'continue_button_html'  => '',
58
		'continue_button_title' => '',
59
60
		// Manually render form.
61
		'callback'              => '',
62
	);
63
64
	/**
65
	 * Display styles.
66
	 *
67
	 * @since  2.0
68
	 * @access private
69
	 * @var array
70
	 */
71
	private $display_styles = array(
72
		'simple'  => 'includes/forms/api/view/simple-form-template.php',
73
		'stepper' => 'includes/forms/api/view/stepper-form-template.php',
74
		'reveal'  => 'includes/forms/api/view/reveal-form-template.php',
75
		'modal'   => 'includes/forms/api/view/modal-form-template.php',
76
		'button'  => 'includes/forms/api/view/button-form-template.php',
77
	);
78
79
80
	private function __construct() {
81
	}
82
83
84
	/**
85
	 * Get instance.
86
	 *
87
	 * @return static
88
	 */
89
	public static function get_instance() {
90
		if ( is_null( static::$instance ) ) {
0 ignored issues
show
Bug introduced by
Since $instance is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $instance to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
91
			self::$instance = new static();
92
		}
93
94
		return self::$instance;
95
	}
96
97
	/**
98
	 * Initialize this module
99
	 *
100
	 * @since  2.0
101
	 * @access static
102
	 */
103
	public function init() {
104
		self::$field_defaults['_template']             = include GIVE_PLUGIN_DIR . self::$instance->display_styles['simple'];
105
		self::$field_defaults['continue_button_title'] = __( 'Show Form', 'give' );
106
		self::$field_defaults['action']                = esc_url( $_SERVER['REQUEST_URI'] );
107
108
		// Load fields API
109
		require_once GIVE_PLUGIN_DIR . 'includes/forms/api/class-give-fields-api.php';
110
		Give_Fields_API::get_instance()->init();
111
112
		// Load form api filters
113
		require_once GIVE_PLUGIN_DIR . 'includes/forms/api/filters.php';
114
115
		// Add give_form_api shortcode.
116
		add_shortcode( 'give_form_api', array( $this, 'render_shortcode' ) );
117
		add_action( 'give_wp_enqueue_scripts', array( $this, 'register_form_api_scripts' ) );
118
		add_action( 'give_admin_enqueue_scripts', array( $this, 'register_form_api_scripts' ) );
119
	}
120
121
122
	/**
123
	 * Register form.
124
	 *
125
	 * @since  2.0
126
	 * @access public
127
	 *
128
	 * @param      $form
129
	 * @param      $form_id
130
	 * @param bool $force
131
	 */
132
	public static function register_form( $form, $form_id, $force = false ) {
133
		if ( ( ! array_key_exists( $form_id, self::$forms ) || $force ) && ! empty( $form_id ) ) {
134
			self::$forms[ $form_id ] = $form;
135
		}
136
	}
137
138
139
	/**
140
	 * Render form by shortcode.
141
	 *
142
	 * @since  2.0
143
	 * @access public
144
	 *
145
	 * @param array $attrs
146
	 *
147
	 * @return string
148
	 */
149
	public function render_shortcode( $attrs ) {
150
		$attrs = shortcode_atts( array( 'id' => '' ), $attrs, 'give_form_api' );
151
152
		return self::$instance->render_form( $attrs['id'] );
153
	}
154
155
156
	/**
157
	 * Render custom form.
158
	 *
159
	 * @since  1.0
160
	 * @access private
161
	 *
162
	 * @param array $form
163
	 *
164
	 * @return bool
165
	 */
166
	private function render_custom_form( $form ) {
167
		$form_html = '';
168
169
		if ( empty( $form['callback'] ) ) {
170
			$callback = $form['callback'];
171
172
			// Process callback to get form html.
173
			if ( is_string( $callback ) && function_exists( "$callback" ) ) {
174
				$form_html = $callback( $form );
175
			} elseif ( is_array( $callback ) && method_exists( $callback[0], "$callback[1]" ) ) {
176
				$form_html = $callback[0]->$callback[1]( $form );
177
			}
178
		}
179
180
		return $form_html;
181
	}
182
183
	/**
184
	 * Render forms.
185
	 *
186
	 * @since  2.0
187
	 * @access static
188
	 *
189
	 * @param string $form_slug Form name.
190
	 *
191
	 * @return string
192
	 */
193
	static function render_form( $form_slug ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
194
		$form_html = '';
195
196
		// Handle exception.
197
		try {
198
			if (
199
				empty( $form_slug )
200
				|| ! is_string( $form_slug )
201
				|| ! ( $form = self::get_form( $form_slug ) )
202
			) {
203
				throw new Exception( __( 'Pass valid form slug to render form.', 'give' ) );
204
			}
205
		} catch ( Exception $e ) {
206
			give_output_error( $e->getMessage(), true, 'error' );
207
208
			return $form_html;
209
		}
210
211
		// Enqueue Form API js.
212
		self::$instance->enqueue_scripts();
213
214
		// Render custom form with callback.
215
		if ( $form_html = self::$instance->render_custom_form( $form ) ) {
216
			return $form_html;
217
		}
218
219
		// Get all form tags from form template.
220
		preg_match_all( '/\{\{form_(.+?)?\}\}/', $form['_template'], $form_tags );
221
222
		// Render form tags.
223
		if ( 0 < count( $form_tags ) && ! empty( $form_tags[0] ) ) {
224
			$form_html = self::render_form_tags( $form_tags[0], $form );
225
		}
226
227
		/**
228
		 * Filter the form html.
229
		 *
230
		 * @since 2.0
231
		 *
232
		 * @param string $form_html
233
		 * @param array  $form
234
		 */
235
		return apply_filters( 'give_form_api_render_form', $form_html, $form );
236
	}
237
238
239
	/**
240
	 * Set default values form form.
241
	 *
242
	 * @since  2.0
243
	 * @access private
244
	 *
245
	 * @param $form
246
	 *
247
	 * @return array
248
	 */
249
	private static function set_default_values( $form ) {
250
		/**
251
		 * Filter the form values before set default values.
252
		 *
253
		 * @since 2.0
254
		 *
255
		 * @param array  $form
256
		 */
257
		$form = apply_filters( 'give_form_api_pre_set_default_values', $form );
258
259
		$form = wp_parse_args( $form, self::$field_defaults );
260
261
		// Set template.
262
		$form['_template'] = array_key_exists( $form['display_style'], self::$instance->display_styles )
263
			? include GIVE_PLUGIN_DIR . self::$instance->display_styles[ $form['display_style'] ]
264
			: $form['_template'];
265
266
		// Set ID.
267
		$form['form_attributes']['id'] = empty( $form['form_attributes']['id'] )
268
			? $form['id']
269
			: $form['form_attributes']['id'];
270
271
		/**
272
		 * Filter the default values after set form default values.
273
		 *
274
		 * @since 2.0
275
		 *
276
		 * @param array  $form
277
		 */
278
		return apply_filters( 'give_form_api_post_set_default_values', $form );
279
	}
280
281
282
	/**
283
	 * Process a form, filling in $values with what's been posted
284
	 *
285
	 * @since  2.0
286
	 * @access static
287
	 */
288
	static function process_form() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
289
	}
290
291
	/**
292
	 * Recursively process a meta form element, filling in $values accordingly
293
	 *
294
	 * @since  2.0
295
	 * @access static
296
	 *
297
	 * @param string $form_slug
298
	 *
299
	 * @return array
300
	 */
301
	static function get_form( $form_slug ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
302
		$form = array();
303
304
		if ( ! empty( self::$forms ) && array_key_exists( $form_slug, self::$forms ) ) {
305
			$form       = self::$forms[ $form_slug ];
306
			$form['id'] = empty( $form_args['id'] ) ? $form_slug : $form_args['id'];
0 ignored issues
show
Bug introduced by
The variable $form_args seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
307
			$form       = self::$instance->set_default_values( $form );
308
		}
309
310
		/**
311
		 * Filter the result form.
312
		 *
313
		 * @since 2.0
314
		 *
315
		 * @param array  $form
316
		 * @param string $form_slug
317
		 * @param        array self::$forms
318
		 */
319
		return apply_filters( 'give_form_api_get_form', $form, $form_slug, self::$forms );
320
	}
321
322
323
	/**
324
	 * Get forms.
325
	 *
326
	 * @since  1.0
327
	 * @access public
328
	 *
329
	 * @return array
330
	 */
331
	public static function get_forms() {
332
		return self::$forms;
333
	}
334
335
	/**
336
	 * Get forms.
337
	 *
338
	 * @since  1.0
339
	 * @access public
340
	 *
341
	 * @param array $form_tags
342
	 * @param array $form
343
	 *
344
	 * @return string
345
	 */
346
	private function render_form_tags( $form_tags, $form ) {
347
		$form_html = $form['_template'];
348
349
		/**
350
		 *  Filter the for tags which you want to handle manually.
351
		 *
352
		 * @since 2.0
353
		 *
354
		 * @param       array
355
		 * @param array $form
356
		 * @param array $form_tag
357
		 */
358
		$custom_handler_for_form_tags = apply_filters(
359
			'give_form_api_manually_render_form_tags',
360
			array( '{{form_attributes}}', '{{form_fields}}' ),
361
			$form,
362
			$form_tags
363
		);
364
365
		// Replace form tags.
366
		foreach ( $form_tags as $form_tag ) {
367
			$form_param = str_replace( array( '{{form_', '}}' ), '', $form_tag );
368
369
			// Process form tags which:
370
			// 1. Has a value in form arguments.
371
			// 2. Only has scalar value.
372
			// 3. Developer do not want to handle them manually.
373
			if (
374
				! isset( $form[ $form_param ] )
375
				|| ! is_scalar( $form[ $form_param ] )
376
				|| in_array( $form_tag, $custom_handler_for_form_tags )
377
			) {
378
				continue;
379
			}
380
381
			$form_html = str_replace( $form_tag, $form[ $form_param ], $form_html );
382
		}
383
384
		/**
385
		 *  Filters the form tags.
386
		 *
387
		 * @since 2.0
388
		 *
389
		 * @param string $form_html
390
		 * @param array  $form
391
		 * @param array  $form_tags
392
		 */
393
		$form_html = apply_filters(
394
			'give_form_api_render_form_tags',
395
			$form_html,
396
			$form,
397
			$form_tags
398
		);
399
400
		return $form_html;
401
	}
402
403
	/**
404
	 * Enqueue form api scripts.
405
	 *
406
	 * @since  2.0
407
	 * @access public
408
	 */
409
	public function register_form_api_scripts() {
410
		$js_plugins     = GIVE_PLUGIN_URL . 'assets/js/plugins/';
411
412
		// Use minified libraries if SCRIPT_DEBUG is turned off.
413
		$suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
414
415
		wp_register_script( 'give-repeatable-fields', $js_plugins . 'repeatable-fields' . $suffix . '.js', array( 'jquery' ), GIVE_VERSION, false );
416
		wp_register_script( 'give-form-api-js', $js_plugins . "give-form-api{$suffix}.js", array( 'jquery', 'give-repeatable-fields', 'jquery-ui-sortable' ), GIVE_VERSION, false );
417
418
		/**
419
		 * Filter the js var.
420
		 *
421
		 * @since 2.0
422
		 */
423
		$give_form_api_var = apply_filters( 'give_form_api_js_vars', array(
424
			'metabox_fields' => array(
425
				'media' => array(
426
					'button_title' => esc_html__( 'Choose Attachment', 'give' ),
427
				)
428
			),
429
			/* translators : %s: Donation form options metabox */
430
			'confirm_before_remove_row_text' => __( 'Do you want to delete this level?', 'give' ),
431
		));
432
433
434
		if ( is_admin() || ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ) {
435
			wp_localize_script( 'give-form-api-js', 'give_form_api_var', $give_form_api_var );
436
		} else {
437
			wp_localize_script( 'give', 'give_form_api_var', $give_form_api_var );
438
		}
439
440
	}
441
442
	/**
443
	 * Load Form API js var.
444
	 *
445
	 * @since  2.0
446
	 * @access public
447
	 */
448
	public static function enqueue_scripts() {
449
		if ( is_admin() || ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ) {
450
			wp_enqueue_script('give-repeatable-fields');
451
			wp_enqueue_script('give-form-api-js');
452
		}
453
	}
454
455
456
	/**
457
	 * Get unique form/field id
458
	 *
459
	 * @since  2.0
460
	 * @access public
461
	 *
462
	 * @param array $form
463
	 * @param array $field
464
	 *
465
	 * @return string
466
	 */
467
	public static function get_unique_id( $form, $field = array() ) {
468
		$field = empty( $field ) ? $form : $field;
469
		$field_id = $field['id'];
470
471
		if ( ( ! is_null( $form ) && ! empty( $form['set_unique_id'] ) ) || ! empty( $field['set_unique_id'] ) ) {
472
			$field_id = empty( $field['unique_id'] )
473
				? $field['id'] . '-' . uniqid()
474
				: $field['unique_id'];
475
		}
476
477
		return $field_id;
478
	}
479
}
480
481
/**
482
 * Initialize field API.
483
 *
484
 * @since 2.0
485
 */
486
function give_init_forms_api() {
487
	Give_Form_API::get_instance()->init();
488
489
	/**
490
	 * Fire the action when form api loaded.
491
	 *
492
	 * @since 2.0
493
	 */
494
	do_action( 'give_forms_api_loaded' );
495
}
496
497
add_action( 'init', 'give_init_forms_api', 99 );