Completed
Push — issues/1038 ( 0b90cb...9d567f )
by Ravinder
17:59
created

Give_Fields_API::set_responsive_field()   D

Complexity

Conditions 10
Paths 10

Size

Total Lines 46
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 23
nc 10
nop 1
dl 0
loc 46
rs 4.983
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
/**
4
 * Fields API
5
 *
6
 * @package     Give
7
 * @subpackage  Classes/Give_Fields_API
8
 * @copyright   Copyright (c) 2016, WordImpress
9
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
10
 * @since       1.9
11
 */
12
class Give_Fields_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  1.9
17
	 * @access private
18
	 * @var Give_Fields_API
19
	 */
20
	static private $instance;
21
22
	/**
23
	 * The defaults for all elements
24
	 *
25
	 * @since  1.9
26
	 * @access static
27
	 */
28
	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...
29
		'type'                 => '',
30
		'name'                 => '',
31
		'data_type'            => '',
32
		'value'                => '',
33
		'required'             => false,
34
35
		// Set default value to field.
36
		'default'              => '',
37
38
		// Add label, before and after field.
39
		'label'                => '',
40
		'label_position'       => 'before',
41
42
		// Add description to field as tooltip.
43
		'tooltip'              => '',
44
45
		// Show multiple fields in same row with in sub section.
46
		'sub_section_start'    => false,
47
		'sub_section_end'      => false,
48
49
		// Add custom attributes.
50
		'attributes'           => array(),
51
		'row_attributes'       => array(),
52
53
		// Params to edit field html.
54
		// @todo: Implement these params.
55
		'before_field'         => '',
56
		'after_field'          => '',
57
		'before_field_wrapper' => '',
58
		'after_field_wrapper'  => '',
59
		'before_label'         => '',
60
		'after_label'          => '',
61
62
		// Manually render field.
63
		'callback'             => '',
64
65
	);
66
67
	/**
68
	 * The defaults for all elements
69
	 *
70
	 * @since  1.9
71
	 * @access static
72
	 */
73
	static $section_defaults = array(
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $section_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...
74
		'label'      => '',
75
		'name'       => '',
76
		'attributes' => array(),
77
78
		// Manually render section.
79
		'callback'   => '',
80
	);
81
82
83
	private function __construct() {
84
	}
85
86
87
	/**
88
	 * Get instance.
89
	 *
90
	 * @return static
91
	 */
92
	public static function get_instance() {
93
		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...
94
			self::$instance = new static();
95
		}
96
97
		return self::$instance;
98
	}
99
100
	/**
101
	 * Initialize this module
102
	 *
103
	 * @since  1.9
104
	 * @access static
105
	 */
106
	public function init() {
107
		add_filter( 'give_form_api_render_form_tags', array( $this, 'render_tags' ), 10, 2 );
108
	}
109
110
111
	/**
112
	 * Render custom field.
113
	 *
114
	 * @since  1.0
115
	 * @access private
116
	 *
117
	 * @param array $field
118
	 *
119
	 * @return bool
120
	 */
121
	private function render_custom_field( $field ) {
122
		$field_html = '';
123
124
		if ( empty( $field['callback'] ) ) {
125
			$callback = $field['callback'];
126
127
			// Process callback to get field html.
128
			if ( is_string( $callback ) && function_exists( "$callback" ) ) {
129
				$field_html = $callback( $field );
130
			} elseif ( is_array( $callback ) && method_exists( $callback[0], "$callback[1]" ) ) {
131
				$field_html = $callback[0]->$callback[1]( $field );
132
			}
133
		}
134
135
		return $field_html;
136
	}
137
138
	/**
139
	 * Render tag
140
	 *
141
	 * @since   1.9
142
	 * @access  public
143
	 *
144
	 * @param $field
145
	 * @param $form
146
	 *
147
	 * @return string
148
	 */
149
	public static function render_tag( $field, $form = null ) {
150
		$field_html     = '';
151
		$functions_name = "render_{$field['type']}_field";
152
153
		if ( method_exists( self::$instance, $functions_name ) ) {
154
			$field_html .= self::$instance->{$functions_name}( $field );
155
		} else {
156
			$field_html .= apply_filters( "give_fields_api_render_{$field['type']}_field", '', $field, $form );
157
		}
158
159
		return $field_html;
160
	}
161
162
163
	/**
164
	 * Render `{{form_fields}}` tag.
165
	 *
166
	 * @since  1.9
167
	 * @access private
168
	 *
169
	 * @param  string $form_html
170
	 * @param  array  $form
171
	 *
172
	 * @return string
173
	 */
174
	public function render_tags( $form_html, $form ) {
175
		// Bailout: If form does not contain any field.
176
		if ( empty( $form['fields'] ) ) {
177
			str_replace( '{{form_fields}}', '', $form_html );
178
179
			return $form_html;
180
		}
181
182
		$fields_html = '';
183
184
		// Set responsive fields.
185
		self::$instance->set_responsive_field( $form );
186
187
		// Render fields.
188
		foreach ( $form['fields'] as $key => $field ) {
189
			// Set default value.
190
			$field['name'] = empty( $field['name'] ) ? $key : $field['name'];
191
			$field         = self::$instance->set_default_values( $field );
192
193
194
			// Render custom form with callback.
195
			if ( $field_html = self::$instance->render_custom_field( $field ) ) {
196
				$fields_html .= $field_html;
197
			}
198
199
			switch ( true ) {
200
				// Section.
201
				case array_key_exists( 'fields', $field ):
202
					// Set default values.
203
					foreach ( $field['fields'] as $section_field_index => $section_field ){
204
						$section_field['name'] = empty( $section_field['name'] )
205
							? $section_field_index
206
							: $section_field['name'];
207
208
						$field['fields'][$section_field_index]= self::$instance->set_default_values( $section_field );
209
					}
210
211
					$fields_html .= self::$instance->render_section( $field, $form );
212
213
					break;
214
215
				// Field
216
				default:
217
					$fields_html .= self::render_tag( $field, $form );
218
			}
219
		}
220
221
		$form_html = str_replace( '{{form_fields}}', $fields_html, $form_html );
222
223
		return $form_html;
224
	}
225
226
227
	/**
228
	 * Render section.
229
	 *
230
	 * @since  1.9
231
	 * @access public
232
	 *
233
	 * @param array $section
234
	 * @param array $form
235
	 *
236
	 * @return string
237
	 */
238
	public static function render_section( $section, $form = null ) {
239
		ob_start();
240
		?>
241
		<fieldset <?php echo self::$instance->get_field_attributes( $section ); ?>>
242
			<?php
243
			// Legend.
244
			if ( ! empty( $section['label'] ) ) {
245
				echo "<legend>{$section['label']}</legend>";
246
			};
247
248
			// Fields.
249
			foreach ( $section['fields'] as $key => $field ) {
250
				$field['name'] = empty( $field['name'] ) ? $key : $field['name'];
251
				echo self::render_tag( $field, $form );
252
			}
253
			?>
254
		</fieldset>
255
		<?php
256
		return ob_get_clean();
257
	}
258
259
260
	/**
261
	 * Render text field.
262
	 *
263
	 * @since  1.9
264
	 * @access private
265
	 *
266
	 * @param  array $field
267
	 *
268
	 * @return string
269
	 */
270
	public static function render_text_field( $field ) {
271
		ob_start();
272
		echo $field['before_field_wrapper'];
273
		?>
274
		<p <?php echo self::$instance->get_row_attributes( $field ); ?>>
275
			<?php
276
			// Label: before field.
277
			if ( 'before' === $field['label_position'] ) {
278
				echo self::$instance->render_label( $field );
279
			}
280
			?>
281
282
			<input
283
					type="<?php echo $field['type']; ?>"
284
					name="<?php echo $field['name']; ?>"
285
					value="<?php echo $field ['value']; ?>"
286
				<?php echo( $field['required'] ? 'required=""' : '' ); ?>
287
				<?php echo self::$instance->get_field_attributes( $field ); ?>
288
			>
289
290
			<?php
291
			// Label: before field.
292
			if ( 'after' === $field['label_position'] ) {
293
				echo self::$instance->render_label( $field );
294
			}
295
			?>
296
		</p>
297
		<?php
298
		echo $field['after_field_wrapper'];
299
300
		return ob_get_clean();
301
	}
302
303
	/**
304
	 * Render text field.
305
	 *
306
	 * @since  1.9
307
	 * @access private
308
	 *
309
	 * @param  array $field
310
	 *
311
	 * @return string
312
	 */
313
	public static function render_submit_field( $field ) {
314
		return self::$instance->render_text_field( $field );
315
	}
316
317
	/**
318
	 * Render text field.
319
	 *
320
	 * @since  1.9
321
	 * @access private
322
	 *
323
	 * @param  array $field
324
	 *
325
	 * @return string
326
	 */
327
	public static function render_checkbox_field( $field ) {
328
		return self::$instance->render_text_field( $field );
329
	}
330
331
	/**
332
	 * Render label
333
	 *
334
	 * @since  1.9
335
	 * @access public
336
	 *
337
	 * @param $field
338
	 *
339
	 * @return string
340
	 */
341
	public static function render_label( $field ) {
342
		ob_start();
343
		?>
344
		<?php if ( ! empty( $field['label'] ) ) : ?>
345
			<label class="give-label" for="<?php echo $field['attributes']['id']; ?>">
346
347
				<?php echo $field['label']; ?>
348
349
				<?php if ( $field['required'] ) : ?>
350
					<span class="give-required-indicator">*</span>
351
				<?php endif; ?>
352
353
				<?php if ( $field['tooltip'] ) : ?>
354
					<span class="give-tooltip give-icon give-icon-question" data-tooltip="<?php echo $field['tooltip'] ?>"></span>
355
				<?php endif; ?>
356
			</label>
357
		<?php endif; ?>
358
		<?php
359
		return ob_get_clean();
360
	}
361
362
	/**
363
	 * Get field attribute string from field arguments.
364
	 *
365
	 * @since  1.9
366
	 * @access private
367
	 *
368
	 * @param array $attributes
369
	 *
370
	 * @return array|string
371
	 */
372
	private function get_attributes( $attributes ) {
373
		$field_attributes_val = '';
374
375
		if ( ! empty( $attributes ) ) {
376
			foreach ( $attributes as $attribute_name => $attribute_val ) {
377
				$field_attributes_val[] = "{$attribute_name}=\"{$attribute_val}\"";
378
			}
379
		}
380
381
		if ( ! empty( $field_attributes_val ) ) {
382
			$field_attributes_val = implode( ' ', $field_attributes_val );
383
		}
384
385
		return $field_attributes_val;
386
	}
387
388
	/**
389
	 * Get field attribute string from field arguments.
390
	 *
391
	 * @since  1.9
392
	 * @access private
393
	 *
394
	 * @param $field
395
	 *
396
	 * @return array|string
397
	 */
398
	private function get_field_attributes( $field ) {
399
		return self::$instance->get_attributes( $field['attributes'] );
400
	}
401
402
	/**
403
	 * Get row attribute string from field arguments.
404
	 *
405
	 * @since  1.9
406
	 * @access private
407
	 *
408
	 * @param $field
409
	 *
410
	 * @return array|string
411
	 */
412
	private function get_row_attributes( $field ) {
413
		return self::$instance->get_attributes( $field['row_attributes'] );;
414
	}
415
416
	/**
417
	 * Set default values for fields
418
	 *
419
	 * @since  1.0
420
	 * @access private
421
	 *
422
	 * @param array $field
423
	 *
424
	 * @return array
425
	 */
426
	private function set_default_values( $field ) {
427
		$is_field = array_key_exists( 'fields', $field ) ? false : true;
428
429
		// Get default values for section or field.
430
		$default_values = ! $is_field
431
			? self::$section_defaults
432
			: self::$field_defaults;
433
434
		// Default field classes.
435
		$default_class = ! $is_field ? 'give-form-section give-form-section-js give-clearfix' : 'give-field give-field-js';
436
437
		// Set default values for field or section.
438
		$field = wp_parse_args( $field, $default_values );
439
440
		// Set ID.
441
		$field['attributes']['id'] = empty( $field['attributes']['id'] )
442
			? ( $is_field ? "give-{$field['name']}-field" : "give-{$field['name']}-section" )
443
			: $field['attributes']['id'];
444
445
		// Set class.
446
		$field['attributes']['class'] = empty( $field['attributes']['class'] )
447
			? $default_class
448
			: "{$default_class} {$field['attributes']['class']}";
449
450
		// Set wrapper class.
451
		$field['row_attributes']['class'] = empty( $field['row_attributes']['class'] )
452
			? 'give-field-row'
453
			: ( self::$instance->is_sub_section( $field ) ? $field['row_attributes']['class'] : "give-field-row {$field['row_attributes']['class']}" );
454
455
		return $field;
456
	}
457
458
459
	/**
460
	 * Set responsive fields.
461
	 *
462
	 * @since  1.9
463
	 * @access private
464
	 *
465
	 * @param $form
466
	 *
467
	 * @return mixed
468
	 */
469
	private function set_responsive_field( &$form ) {
470
471
		foreach ( $form['fields'] as $key => $field ) {
472
			switch ( true ) {
473
				case array_key_exists( 'fields', $field ):
474
					foreach ( $field['fields'] as $section_field_index => $section_field ) {
475
						if ( ! self::$instance->is_sub_section( $section_field ) ) {
476
							continue;
477
						}
478
479
						$form['fields'][ $key ]['fields'][$section_field_index]['row_attributes']['class'] = 'give-form-col';
480
481
						if ( array_key_exists( 'sub_section_end', $section_field ) ) {
482
							$form['fields'][ $key ]['fields'][$section_field_index]['row_attributes']['class'] = 'give-form-col give-form-col-end';
483
484
							// Clear float left for next field.
485
							$fields_keys = array_keys( $form['fields'][ $key ]['fields'] );
486
487
							if ( $next_field_key = array_search( $key, $fields_keys ) ) {
488
								$form['fields'][$key][ $fields_keys[ $next_field_key + 1 ] ]['row_attributes']['class'] = 'give-clearfix';
489
							}
490
						}
491
					}
492
493
					break;
494
495
				default:
496
					if ( ! self::$instance->is_sub_section( $field ) ) {
497
						continue;
498
					}
499
500
					$form['fields'][ $key ]['row_attributes']['class'] = 'give-form-col';
501
502
					if ( array_key_exists( 'sub_section_end', $field ) ) {
503
						$form['fields'][ $key ]['row_attributes']['class'] = 'give-form-col give-form-col-end';
504
505
						// Clear float left for next field.
506
						$fields_keys = array_keys( $form['fields'] );
507
508
						if ( $next_field_key = array_search( $key, $fields_keys ) ) {
509
							$form['fields'][ $fields_keys[ $next_field_key + 1 ] ]['row_attributes']['class'] = 'give-clearfix';
510
						}
511
					}
512
			}
513
		}
514
	}
515
516
517
	/**
518
	 * Check if current feld is part of sub section or not.
519
	 *
520
	 * @since  1.9
521
	 * @access private
522
	 *
523
	 * @param $field
524
	 *
525
	 * @return bool
526
	 */
527
	private function is_sub_section( $field ) {
528
		$is_sub_section = false;
529
		if (
530
			array_key_exists( 'sub_section_start', $field )
531
			|| array_key_exists( 'sub_section_end', $field )
532
		) {
533
			$is_sub_section = true;
534
		}
535
536
		return $is_sub_section;
537
	}
538
539
	/**
540
	 * Is the element a button?
541
	 *
542
	 * @since  1.9
543
	 * @access static
544
	 *
545
	 * @param array $element
546
	 *
547
	 * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be integer?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
548
	 */
549
	static function is_button( $element ) {
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...
550
		return preg_match( '/^button|submit$/', $element['#type'] );
551
	}
552
}
553