Completed
Pull Request — master (#54)
by Jamie
03:26
created

FrmField::get_option_in_array()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
if ( ! defined('ABSPATH') ) {
3
	die( 'You are not allowed to call this page directly.' );
4
}
5
6
class FrmField {
7
8
    static $use_cache = true;
9
	static $transient_size = 200;
10
11
	public static function field_selection() {
12
		$fields = apply_filters('frm_available_fields', array(
13
			'text'      => __( 'Single Line Text', 'formidable' ),
14
			'textarea'  => __( 'Paragraph Text', 'formidable' ),
15
			'checkbox'  => __( 'Checkboxes', 'formidable' ),
16
			'radio'     => __( 'Radio Buttons', 'formidable' ),
17
			'select'    => __( 'Dropdown', 'formidable' ),
18
			'email'     => __( 'Email Address', 'formidable' ),
19
			'url'       => __( 'Website/URL', 'formidable' ),
20
			'captcha'   => __( 'reCAPTCHA', 'formidable' ),
21
		));
22
23
		return $fields;
24
	}
25
26
	public static function pro_field_selection() {
27
		return apply_filters('frm_pro_available_fields', array(
28
			'end_divider' => array(
29
				'name'  => __( 'End Section', 'formidable' ),
30
				'switch_from' => 'divider',
31
			),
32
			'divider'   => __( 'Section', 'formidable' ),
33
			'break'     => __( 'Page Break', 'formidable' ),
34
			'file'      => __( 'File Upload', 'formidable' ),
35
			'rte'       => __( 'Rich Text', 'formidable' ),
36
			'number'    => __( 'Number', 'formidable' ),
37
			'phone'     => __( 'Phone Number', 'formidable' ),
38
			'date'      => __( 'Date', 'formidable' ),
39
			'time'      => __( 'Time', 'formidable' ),
40
			'image'     => __( 'Image URL', 'formidable' ),
41
			'scale'     => __( 'Scale', 'formidable' ),
42
			'data'      => __( 'Dynamic Field', 'formidable' ),
43
			'lookup'	=> __( 'Lookup', 'formidable' ),
44
			'form'      => __( 'Embed Form', 'formidable' ),
45
			'hidden'    => __( 'Hidden Field', 'formidable' ),
46
			'user_id'   => __( 'User ID (hidden)', 'formidable' ),
47
			'password'  => __( 'Password', 'formidable' ),
48
			'html'      => __( 'HTML', 'formidable' ),
49
			'tag'       => __( 'Tags', 'formidable' ),
50
			'credit_card' => __( 'Credit Card', 'formidable' ),
51
			'address'   => __( 'Address', 'formidable' ),
52
		));
53
	}
54
55
    public static function create( $values, $return = true ) {
56
        global $wpdb, $frm_duplicate_ids;
57
58
        $new_values = array();
59
        $key = isset($values['field_key']) ? $values['field_key'] : $values['name'];
60
		$new_values['field_key'] = FrmAppHelper::get_unique_key( $key, $wpdb->prefix . 'frm_fields', 'field_key' );
61
62
		foreach ( array( 'name', 'description', 'type', 'default_value' ) as $col ) {
63
			$new_values[ $col ] = $values[ $col ];
64
        }
65
66
        $new_values['options'] = $values['options'];
67
68
        $new_values['field_order'] = isset($values['field_order']) ? (int) $values['field_order'] : null;
69
        $new_values['required'] = isset($values['required']) ? (int) $values['required'] : 0;
70
        $new_values['form_id'] = isset($values['form_id']) ? (int) $values['form_id'] : null;
71
        $new_values['field_options'] = $values['field_options'];
72
        $new_values['created_at'] = current_time('mysql', 1);
73
74
		if ( isset( $values['id'] ) ) {
75
			$frm_duplicate_ids[ $values['field_key'] ] = $new_values['field_key'];
76
            $new_values = apply_filters('frm_duplicated_field', $new_values);
77
        }
78
79
		foreach ( $new_values as $k => $v ) {
80
            if ( is_array( $v ) ) {
81
				$new_values[ $k ] = serialize( $v );
82
			}
83
            unset( $k, $v );
84
        }
85
86
        //if(isset($values['id']) and is_numeric($values['id']))
87
        //    $new_values['id'] = $values['id'];
88
89
		$query_results = $wpdb->insert( $wpdb->prefix . 'frm_fields', $new_values );
90
		$new_id = 0;
91
		if ( $query_results ) {
92
			self::delete_form_transient( $new_values['form_id'] );
93
			$new_id = $wpdb->insert_id;
94
		}
95
96
		if ( ! $return ) {
97
			return false;
98
		}
99
100
		if ( $query_results ) {
101
			if ( isset( $values['id'] ) ) {
102
				$frm_duplicate_ids[ $values['id'] ] = $new_id;
103
			}
104
			return $new_id;
105
		} else {
106
			return false;
107
		}
108
    }
109
110
    public static function duplicate( $old_form_id, $form_id, $copy_keys = false, $blog_id = false ) {
111
        global $frm_duplicate_ids;
112
113
		$where = array( array( 'or' => 1, 'fi.form_id' => $old_form_id, 'fr.parent_form_id' => $old_form_id ) );
114
		$fields = self::getAll( $where, 'field_order', '', $blog_id );
115
116
        foreach ( (array) $fields as $field ) {
117
            $new_key = ($copy_keys) ? $field->field_key : '';
118
            if ( $copy_keys && substr($field->field_key, -1) == 2 ) {
119
                $new_key = rtrim($new_key, 2);
120
            }
121
122
            $values = array();
123
            FrmFieldsHelper::fill_field( $values, $field, $form_id, $new_key );
124
125
			// If this is a repeating section, create new form
126
			if ( self::is_repeating_field( $field ) ) {
127
				// create the repeatable form
128
				$new_repeat_form_id = apply_filters( 'frm_create_repeat_form', 0, array( 'parent_form_id' => $form_id, 'field_name' => $field->name ) );
129
130
				// Save old form_select
131
				$old_repeat_form_id = $field->field_options['form_select'];
132
133
				// Update form_select for repeating field
134
				$values['field_options']['form_select'] = $new_repeat_form_id;
135
			}
136
137
			// If this is a field inside of a repeating section, associate it with the correct form
138
			if ( $field->form_id != $old_form_id && isset( $old_repeat_form_id ) && isset( $new_repeat_form_id ) && $field->form_id == $old_repeat_form_id ) {
139
				$values['form_id'] = $new_repeat_form_id;
140
			}
141
142
            $values = apply_filters('frm_duplicated_field', $values);
143
            $new_id = self::create($values);
144
            $frm_duplicate_ids[ $field->id ] = $new_id;
145
            $frm_duplicate_ids[ $field->field_key ] = $new_id;
146
            unset($field);
147
        }
148
    }
149
150
	public static function update( $id, $values ) {
151
        global $wpdb;
152
153
		$id = absint( $id );
154
155
		if ( isset( $values['field_key'] ) ) {
156
			$values['field_key'] = FrmAppHelper::get_unique_key( $values['field_key'], $wpdb->prefix . 'frm_fields', 'field_key', $id );
157
		}
158
159
        if ( isset($values['required']) ) {
160
            $values['required'] = (int) $values['required'];
161
        }
162
163
		self::preserve_format_option_backslashes( $values );
164
165
		if ( isset( $values['type'] ) ) {
166
			$values = apply_filters( 'frm_clean_' . $values['type'] . '_field_options_before_update', $values );
167
		}
168
169
		// serialize array values
170
		foreach ( array( 'default_value', 'field_options', 'options' ) as $opt ) {
171
			if ( isset( $values[ $opt ] ) && is_array( $values[ $opt ] ) ) {
172
				$values[ $opt ] = serialize( $values[ $opt ] );
173
			}
174
		}
175
176
		$query_results = $wpdb->update( $wpdb->prefix . 'frm_fields', $values, array( 'id' => $id ) );
177
178
        $form_id = 0;
179
		if ( isset( $values['form_id'] ) ) {
180
            $form_id = absint( $values['form_id'] );
181
		} else {
182
            $field = self::getOne($id);
183
            if ( $field ) {
184
                $form_id = $field->form_id;
185
            }
186
            unset($field);
187
        }
188
        unset($values);
189
190
		if ( $query_results ) {
191
            wp_cache_delete( $id, 'frm_field' );
192
            if ( $form_id ) {
193
                self::delete_form_transient( $form_id );
194
            }
195
        }
196
197
        return $query_results;
198
    }
199
200
	/**
201
	* Keep backslashes in the phone format option
202
	*
203
	* @since 2.0.8
204
	* @param $values array - pass by reference
205
	*/
206
	private static function preserve_format_option_backslashes( &$values ) {
207
		if ( isset( $values['field_options']['format'] ) ) {
208
			$values['field_options']['format'] = FrmAppHelper::preserve_backslashes( $values['field_options']['format'] );
209
		}
210
	}
211
212
    public static function destroy( $id ) {
213
		global $wpdb;
214
215
		do_action( 'frm_before_destroy_field', $id );
216
217
		wp_cache_delete( $id, 'frm_field' );
218
		$field = self::getOne( $id );
219
		if ( ! $field ) {
220
			return false;
221
		}
222
223
		self::delete_form_transient( $field->form_id );
224
225
		$wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_item_metas WHERE field_id=%d', $id ) );
226
		return $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_fields WHERE id=%d', $id ) );
227
    }
228
229
	public static function delete_form_transient( $form_id ) {
230
		$form_id = absint( $form_id );
231
		delete_transient( 'frm_form_fields_' . $form_id . 'excludeinclude' );
232
		delete_transient( 'frm_form_fields_' . $form_id . 'includeinclude' );
233
		delete_transient( 'frm_form_fields_' . $form_id . 'includeexclude' );
234
		delete_transient( 'frm_form_fields_' . $form_id . 'excludeexclude' );
235
236
		global $wpdb;
237
		$wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->options . ' WHERE option_name LIKE %s OR option_name LIKE %s OR option_name LIKE %s OR option_name LIKE %s', '_transient_timeout_frm_form_fields_' . $form_id . 'ex%', '_transient_frm_form_fields_' . $form_id . 'ex%', '_transient_timeout_frm_form_fields_' . $form_id . 'in%', '_transient_frm_form_fields_' . $form_id . 'in%' ) );
238
239
		FrmAppHelper::cache_delete_group( 'frm_field' );
240
241
        $form = FrmForm::getOne($form_id);
242
        if ( $form && $form->parent_form_id && $form->parent_form_id != $form_id ) {
243
            self::delete_form_transient( $form->parent_form_id );
244
        }
245
    }
246
247
	/**
248
	 * If $field is numeric, get the field object
249
	 */
250
	public static function maybe_get_field( &$field ) {
251
		if ( ! is_object( $field ) ) {
252
			$field = self::getOne( $field );
253
		}
254
	}
255
256
	public static function getOne( $id ) {
0 ignored issues
show
Coding Style introduced by
The function name getOne is in camel caps, but expected get_one instead as per the coding standard.
Loading history...
257
		if ( empty( $id ) ) {
258
			return null;
259
		}
260
261
        global $wpdb;
262
263
        $where = is_numeric($id) ? 'id=%d' : 'field_key=%s';
264
		$query = $wpdb->prepare( 'SELECT * FROM ' . $wpdb->prefix . 'frm_fields WHERE ' . $where, $id );
265
266
        $results = FrmAppHelper::check_cache( $id, 'frm_field', $query, 'get_row', 0 );
267
268
        if ( empty($results) ) {
269
            return $results;
270
        }
271
272 View Code Duplication
        if ( is_numeric($id) ) {
1 ignored issue
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...
273
			FrmAppHelper::set_cache( $results->field_key, $results, 'frm_field' );
274
        } else if ( $results ) {
275
			FrmAppHelper::set_cache( $results->id, $results, 'frm_field' );
276
        }
277
278
		self::prepare_options( $results );
279
280
        return stripslashes_deep($results);
281
    }
282
283
    /**
284
     * Get the field type by key or id
285
     * @param int|string The field id or key
286
	 * @param mixed $col The name of the column in the fields database table
287
     */
288
    public static function get_type( $id, $col = 'type' ) {
289
        $field = FrmAppHelper::check_cache( $id, 'frm_field' );
290
        if ( $field ) {
291
            $type = $field->{$col};
292
        } else {
293
            $type = FrmDb::get_var( 'frm_fields', array( 'or' => 1, 'id' => $id, 'field_key' => $id ), $col );
294
        }
295
296
        return $type;
297
    }
298
299
	public static function get_all_types_in_form( $form_id, $type, $limit = '', $inc_sub = 'exclude' ) {
300
        if ( ! $form_id ) {
301
            return array();
302
        }
303
304
		$results = self::get_fields_from_transients( $form_id, array( 'inc_embed' => $inc_sub, 'inc_repeat' => $inc_sub ) );
305
		if ( ! empty( $results ) ) {
306
            $fields = array();
307
            $count = 0;
308
            foreach ( $results as $result ) {
309
                if ( $type != $result->type ) {
310
                    continue;
311
                }
312
313
				$fields[ $result->id ] = $result;
314
                $count++;
315
                if ( $limit == 1 ) {
316
                    $fields = $result;
317
                    break;
318
                }
319
320
                if ( ! empty($limit) && $count >= $limit ) {
321
                    break;
322
                }
323
324
                unset($result);
325
            }
326
            return stripslashes_deep($fields);
327
        }
328
329
        self::$use_cache = false;
330
331
		$where = array( 'fi.form_id' => (int) $form_id, 'fi.type' => $type );
332
		self::maybe_include_repeating_fields( $inc_sub, $where );
333
		$results = self::getAll( $where, 'field_order', $limit );
334
        self::$use_cache = true;
335
        self::include_sub_fields($results, $inc_sub, $type);
336
337
        return $results;
338
    }
339
340
	public static function get_all_for_form( $form_id, $limit = '', $inc_embed = 'exclude', $inc_repeat = 'include' ) {
341
        if ( ! (int) $form_id ) {
342
            return array();
343
        }
344
345
		$results = self::get_fields_from_transients( $form_id, array( 'inc_embed' => $inc_embed, 'inc_repeat' => $inc_repeat ) );
346
		if ( ! empty( $results ) ) {
347
            if ( empty($limit) ) {
348
				return $results;
349
            }
350
351
            $fields = array();
352
            $count = 0;
353
            foreach ( $results as $result ) {
354
				$fields[ $result->id ] = $result;
355
                if ( ! empty($limit) && $count >= $limit ) {
356
                    break;
357
                }
358
            }
359
360
			return $fields;
361
        }
362
363
        self::$use_cache = false;
364
365
		$where = array( 'fi.form_id' => absint( $form_id ) );
366
		self::maybe_include_repeating_fields( $inc_repeat, $where );
367
		$results = self::getAll( $where, 'field_order', $limit );
368
369
        self::$use_cache = true;
370
371
		self::include_sub_fields( $results, $inc_embed, 'all' );
372
373
        if ( empty($limit) ) {
374
			self::set_field_transient( $results, $form_id, 0, array( 'inc_embed' => $inc_embed, 'inc_repeat' => $inc_repeat ) );
375
        }
376
377
		return $results;
378
    }
379
380
	/**
381
	* If repeating fields should be included, adjust $where accordingly
382
	*
383
	* @param string $inc_repeat
384
	* @param array $where - pass by reference
385
	*/
386
	private static function maybe_include_repeating_fields( $inc_repeat, &$where ) {
387
		if ( $inc_repeat == 'include' ) {
388
			$form_id = $where['fi.form_id'];
389
			$where[] = array( 'or' => 1, 'fi.form_id' => $form_id, 'fr.parent_form_id' => $form_id );
390
			unset( $where['fi.form_id'] );
391
		}
392
	}
393
394
	public static function include_sub_fields( &$results, $inc_embed, $type = 'all' ) {
395
		if ( 'include' != $inc_embed || empty( $results ) ) {
396
            return;
397
        }
398
399
        $form_fields = $results;
400
		$index_offset = 1;
401
        foreach ( $form_fields as $k => $field ) {
402
            if ( 'form' != $field->type || ! isset($field->field_options['form_select']) ) {
403
                continue;
404
            }
405
406
            if ( $type == 'all' ) {
407
                $sub_fields = self::get_all_for_form( $field->field_options['form_select'] );
408
            } else {
409
                $sub_fields = self::get_all_types_in_form($field->form_id, $type);
410
            }
411
412
            if ( ! empty($sub_fields) ) {
413
				$index = $k + $index_offset;
414
				$index_offset += count( $sub_fields );
415
				array_splice($results, $index, 0, $sub_fields);
416
            }
417
            unset($field, $sub_fields);
418
        }
419
    }
420
421
	public static function getAll( $where = array(), $order_by = '', $limit = '', $blog_id = false ) {
0 ignored issues
show
Coding Style introduced by
The function name getAll is in camel caps, but expected get_all instead as per the coding standard.
Loading history...
422
		$cache_key = maybe_serialize( $where ) . $order_by . 'l' . $limit . 'b' . $blog_id;
423
        if ( self::$use_cache ) {
424
            // make sure old cache doesn't get saved as a transient
425
            $results = wp_cache_get($cache_key, 'frm_field');
426
            if ( false !== $results ) {
427
                return stripslashes_deep($results);
428
            }
429
        }
430
431
        global $wpdb;
432
433
        if ( $blog_id && is_multisite() ) {
434
            global $wpmuBaseTablePrefix;
435
            if ( $wpmuBaseTablePrefix ) {
436
				$prefix = $wpmuBaseTablePrefix . $blog_id . '_';
437
            } else {
438
                $prefix = $wpdb->get_blog_prefix( $blog_id );
439
            }
440
441
			$table_name = $prefix . 'frm_fields';
442
			$form_table_name = $prefix . 'frm_forms';
443
		} else {
444
			$table_name = $wpdb->prefix . 'frm_fields';
445
			$form_table_name = $wpdb->prefix . 'frm_forms';
446
        }
447
448
		if ( ! empty( $order_by ) && strpos( $order_by, 'ORDER BY' ) === false ) {
449
			$order_by = ' ORDER BY ' . $order_by;
450
		}
451
452
        $limit = FrmAppHelper::esc_limit($limit);
453
454
        $query = "SELECT fi.*, fr.name as form_name  FROM {$table_name} fi LEFT OUTER JOIN {$form_table_name} fr ON fi.form_id=fr.id";
455
        $query_type = ( $limit == ' LIMIT 1' || $limit == 1 ) ? 'row' : 'results';
456
457
        if ( is_array($where) ) {
458
            $results = FrmDb::get_var( $table_name . ' fi LEFT OUTER JOIN ' . $form_table_name . ' fr ON fi.form_id=fr.id', $where, 'fi.*, fr.name as form_name', array( 'order_by' => $order_by, 'limit' => $limit ), '', $query_type );
459
		} else {
460
			// if the query is not an array, then it has already been prepared
461
            $query .= FrmAppHelper::prepend_and_or_where(' WHERE ', $where) . $order_by . $limit;
462
463
			$function_name = ( $query_type == 'row' ) ? 'get_row' : 'get_results';
464
			$results = $wpdb->$function_name( $query );
465
        }
466
        unset( $where );
467
468
		self::format_field_results( $results );
469
470
		FrmAppHelper::set_cache( $cache_key, $results, 'frm_field' );
471
472
		return stripslashes_deep( $results );
473
	}
474
475
	/**
476
	 * @since 2.0.8
477
	 */
478
	private static function format_field_results( &$results ) {
479
		if ( is_array( $results ) ) {
480
			foreach ( $results as $r_key => $result ) {
481
				FrmAppHelper::set_cache( $result->id, $result, 'frm_field' );
482
				FrmAppHelper::set_cache( $result->field_key, $result, 'frm_field' );
483
484
				$results[ $r_key ]->field_options = maybe_unserialize( $result->field_options );
485
				$results[ $r_key ]->options = maybe_unserialize( $result->options );
486
				$results[ $r_key ]->default_value = maybe_unserialize( $result->default_value );
487
488
				unset( $r_key, $result );
489
			}
490 View Code Duplication
		} else if ( $results ) {
1 ignored issue
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...
491
			FrmAppHelper::set_cache( $results->id, $results, 'frm_field' );
492
			FrmAppHelper::set_cache( $results->field_key, $results, 'frm_field' );
493
494
			self::prepare_options( $results );
495
		}
496
	}
497
498
	/**
499
	 * Unserialize all the serialized field data
500
	 * @since 2.0
501
	 */
502
	private static function prepare_options( &$results ) {
503
		$results->field_options = maybe_unserialize( $results->field_options );
504
505
		$results->options = maybe_unserialize($results->options);
506
		$results->default_value = maybe_unserialize($results->default_value);
507
	}
508
509
	/**
510
	 * If a form has too many fields, thay won't all save into a single transient.
511
	 * We'll break them into groups of 200
512
	 * @since 2.0.1
513
	 */
514
	private static function get_fields_from_transients( $form_id, $args ) {
515
		$fields = array();
516
		self::get_next_transient( $fields, 'frm_form_fields_' . $form_id . $args['inc_embed'] . $args['inc_repeat'] );
517
		return $fields;
518
	}
519
520
	/**
521
	 * Called by get_fields_from_transients
522
	 * @since 2.0.1
523
	 */
524
	private static function get_next_transient( &$fields, $base_name, $next = 0 ) {
525
		$name = $next ? $base_name . $next : $base_name;
526
		$next_fields = get_transient( $name );
527
528
		if ( $next_fields ) {
529
			$fields = array_merge( $fields, $next_fields );
530
531
			if ( count( $next_fields ) >= self::$transient_size ) {
532
				// if this transient is full, check for another
533
				$next++;
534
				self::get_next_transient( $fields, $base_name, $next );
535
			}
536
		}
537
	}
538
539
	/**
540
	 * Save the transients in chunks for large forms
541
	 * @since 2.0.1
542
	 */
543
	private static function set_field_transient( &$fields, $form_id, $next = 0, $args = array() ) {
544
		$base_name = 'frm_form_fields_' . $form_id . $args['inc_embed'] . $args['inc_repeat'];
545
		$field_chunks = array_chunk( $fields, self::$transient_size );
546
547
		foreach ( $field_chunks as $field ) {
548
			$name = $next ? $base_name . $next : $base_name;
549
			$set = set_transient( $name, $field, 60 * 60 * 6 );
550
			if ( ! $set ) {
551
				// the transient didn't save
552
				if ( $name != $base_name ) {
553
					// if the first saved an others fail, this will show an incmoplete form
554
					self::delete_form_transient( $form_id );
555
				}
556
				return;
557
			}
558
559
			$next++;
560
		}
561
	}
562
563
	public static function is_no_save_field( $type ) {
564
		return in_array( $type, self::no_save_fields() );
565
	}
566
567
	public static function no_save_fields() {
568
		return array( 'divider', 'end_divider', 'captcha', 'break', 'html', 'form' );
569
	}
570
571
	/**
572
	 * Check if this field can hold an array of values
573
	 *
574
	 * @since 2.0.9
575
	 *
576
	 * @param array|object $field
577
	 * @return boolean
578
	 */
579
	public static function is_field_with_multiple_values( $field ) {
580
		if ( ! $field ) {
581
			return false;
582
		}
583
584
		if ( is_array( $field ) ) {
585
586
			$is_multi_value_field = (
587
				$field['type'] == 'checkbox' ||
588
				$field['type'] == 'address' ||
589
				( $field['type'] == 'data' && isset($field['data_type']) && $field['data_type'] == 'checkbox' ) ||
590
				( $field['type'] == 'lookup' && isset($field['data_type']) && $field['data_type'] == 'checkbox' ) ||
591
				self::is_multiple_select( $field )
592
			);
593
594
		} else {
595
			$is_multi_value_field = (
596
				$field->type == 'checkbox' ||
597
				$field->type == 'address' ||
598
				( $field->type == 'data' && isset( $field->field_options['data_type'] ) && $field->field_options['data_type'] == 'checkbox' ) ||
599
				( $field->type == 'lookup' && isset( $field->field_options['data_type'] ) && $field->field_options['data_type'] == 'checkbox' ) ||
600
				self::is_multiple_select( $field )
601
			);
602
		}
603
604
		return $is_multi_value_field;
605
	}
606
607
	/**
608
	 * Check if this is a multiselect dropdown field
609
	 *
610
	 * @since 2.0.9
611
	 * @return boolean
612
	 */
613
	public static function is_multiple_select( $field ) {
614
		if ( is_array( $field ) ) {
615
			return self::is_option_true( $field, 'multiple' ) && ( ( $field['type'] == 'select' || ( $field['type'] == 'data' && isset( $field['data_type'] ) && $field['data_type'] == 'select') ) );
616
		} else {
617
			return self::is_option_true( $field, 'multiple' ) && ( ( $field->type == 'select' || ( $field->type == 'data' && isset($field->field_options['data_type'] ) && $field->field_options['data_type'] == 'select') ) );
618
		}
619
	}
620
621
	/**
622
	 * Check if a field is read only. Read only can be set in the field options,
623
	 * but disabled with the shortcode options
624
	 *
625
	 * @since 2.0.9
626
	 */
627
	public static function is_read_only( $field ) {
628
		global $frm_vars;
629
		return ( self::is_option_true( $field, 'read_only' ) && ( ! isset( $frm_vars['readonly'] ) || $frm_vars['readonly'] != 'disabled' ) );
630
	}
631
632
	/**
633
	 * @since 2.0.9
634
	 */
635
	public static function is_required( $field ) {
636
		$required = ( $field['required'] != '0' );
637
		$required = apply_filters( 'frm_is_field_required', $required, $field );
638
		return $required;
639
	}
640
641
	/**
642
	 * @since 2.0.9
643
	 */
644
	public static function is_option_true( $field, $option ) {
645
		if ( is_array( $field ) ) {
646
			return self::is_option_true_in_array( $field, $option );
647
		} else {
648
			return self::is_option_true_in_object( $field, $option );
649
		}
650
	}
651
652
	/**
653
	 * @since 2.0.9
654
	 */
655
	public static function is_option_empty( $field, $option ) {
656
		if ( is_array( $field ) ) {
657
			return self::is_option_empty_in_array( $field, $option );
658
		} else {
659
			return self::is_option_empty_in_object( $field, $option );
660
		}
661
	}
662
663
	public static function is_option_true_in_array( $field, $option ) {
664
		return isset( $field[ $option ] ) && $field[ $option ];
665
	}
666
667
	public static function is_option_true_in_object( $field, $option ) {
668
		return isset( $field->field_options[ $option ] ) && $field->field_options[ $option ];
669
	}
670
671
	public static function is_option_empty_in_array( $field, $option ) {
672
		return ! isset( $field[ $option ] ) || empty( $field[ $option ] );
673
	}
674
675
	public static function is_option_empty_in_object( $field, $option ) {
676
		return ! isset( $field->field_options[ $option ] ) || empty( $field->field_options[ $option ] );
677
	}
678
679
	public static function is_option_value_in_object( $field, $option ) {
680
		return isset( $field->field_options[ $option ] ) && $field->field_options[ $option ] != '';
681
	}
682
683
	/**
684
	 * @since 2.0.18
685
	 */
686
	public static function get_option( $field, $option ) {
687
		if ( is_array( $field ) ) {
688
			$option = self::get_option_in_array( $field, $option );
689
		} else {
690
			$option = self::get_option_in_object( $field, $option );
691
		}
692
		return $option;
693
	}
694
695
	public static function get_option_in_array( $field, $option ) {
696
		return $field[ $option ];
697
	}
698
699
	public static function get_option_in_object( $field, $option ) {
700
		return isset( $field->field_options[ $option ] ) ? $field->field_options[ $option ] : '';
701
	}
702
703
	/**
704
	* @since 2.0.09
705
	*/
706
	public static function is_repeating_field( $field ) {
707
		if ( is_array( $field ) ) {
708
			$is_repeating_field = ( 'divider' == $field['type'] );
709
		} else {
710
			$is_repeating_field = ( 'divider' == $field->type );
711
		}
712
		return ( $is_repeating_field && self::is_option_true( $field, 'repeat' ) );
713
	}
714
715
    /**
716
     * @param string $key
717
     * @return int field id
718
     */
719
	public static function get_id_by_key( $key ) {
720
        $id = FrmDb::get_var( 'frm_fields', array( 'field_key' => sanitize_title( $key ) ) );
721
        return $id;
722
    }
723
724
	/**
725
	 * @param string $id
726
	 * @return string
727
	 */
728
	public static function get_key_by_id( $id ) {
729
		return FrmDb::get_var( 'frm_fields', array( 'id' => $id ), 'field_key' );
730
	}
731
}
732