Completed
Pull Request — 2.x (#4569)
by Scott Kingsley
04:52
created

PodsField_Number::validate()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 25
rs 8.8571
c 0
b 0
f 0
eloc 16
nc 2
nop 7
1
<?php
2
3
/**
4
 * @package Pods\Fields
5
 */
6
class PodsField_Number extends PodsField {
7
8
	/**
9
	 * Field Type Group
10
	 *
11
	 * @var string
12
	 * @since 2.0
13
	 */
14
	public static $group = 'Number';
15
16
	/**
17
	 * Field Type Identifier
18
	 *
19
	 * @var string
20
	 * @since 2.0
21
	 */
22
	public static $type = 'number';
23
24
	/**
25
	 * Field Type Label
26
	 *
27
	 * @var string
28
	 * @since 2.0
29
	 */
30
	public static $label = 'Plain Number';
31
32
	/**
33
	 * Field Type Preparation
34
	 *
35
	 * @var string
36
	 * @since 2.0
37
	 */
38
	public static $prepare = '%d';
39
40
	/**
41
	 * Do things like register/enqueue scripts and stylesheets
42
	 *
43
	 * @since 2.0
44
	 */
45
	public function __construct() {
46
47
		self::$label = __( 'Plain Number', 'pods' );
48
	}
49
50
	/**
51
	 * Add options and set defaults to
52
	 *
53
	 * @return array
54
	 *
55
	 * @since 2.0
56
	 */
57
	public function options() {
58
59
		$options = array(
60
			static::$type . '_repeatable'  => array(
61
				'label'             => __( 'Repeatable Field', 'pods' ),
62
				'default'           => 0,
63
				'type'              => 'boolean',
64
				'help'              => __( 'Making a field repeatable will add controls next to the field which allows users to Add/Remove/Reorder additional values. These values are saved in the database as an array, so searching and filtering by them may require further adjustments".', 'pods' ),
65
				'boolean_yes_label' => '',
66
				'dependency'        => true,
67
				'developer_mode'    => true,
68
			),
69
			static::$type . '_format_type' => array(
70
				'label'      => __( 'Input Type', 'pods' ),
71
				'default'    => 'number',
72
				'type'       => 'pick',
73
				'data'       => array(
74
					'number' => __( 'Freeform Number', 'pods' ),
75
					'slider' => __( 'Slider', 'pods' ),
76
				),
77
				'dependency' => true,
78
			),
79
			static::$type . '_format'      => array(
80
				'label'   => __( 'Format', 'pods' ),
81
				'default' => apply_filters( 'pods_form_ui_field_number_format_default', 'i18n' ),
82
				'type'    => 'pick',
83
				'data'    => array(
84
					'i18n'     => __( 'Localized Default', 'pods' ),
85
					'9,999.99' => '1,234.00',
86
					'9.999,99' => '1.234,00',
87
					'9 999,99' => '1 234,00',
88
					'9999.99'  => '1234.00',
89
					'9999,99'  => '1234,00',
90
				),
91
			),
92
			static::$type . '_decimals'    => array(
93
				'label'      => __( 'Decimals', 'pods' ),
94
				'default'    => 0,
95
				'type'       => 'number',
96
				'dependency' => true,
97
			),
98
			static::$type . '_format_soft' => array(
99
				'label'       => __( 'Soft format?', 'pods' ),
100
				'help'        => __( 'Remove trailing decimals (0)', 'pods' ),
101
				'default'     => 0,
102
				'type'        => 'boolean',
103
				'excludes-on' => array( static::$type . '_decimals' => 0 ),
104
			),
105
			static::$type . '_step'        => array(
106
				'label'      => __( 'Slider Increment (Step)', 'pods' ),
107
				'depends-on' => array( static::$type . '_format_type' => 'slider' ),
108
				'default'    => 1,
109
				'type'       => 'text',
110
			),
111
			static::$type . '_min'         => array(
112
				'label'      => __( 'Minimum Number', 'pods' ),
113
				'depends-on' => array( static::$type . '_format_type' => 'slider' ),
114
				'default'    => 0,
115
				'type'       => 'text',
116
			),
117
			static::$type . '_max'         => array(
118
				'label'      => __( 'Maximum Number', 'pods' ),
119
				'depends-on' => array( static::$type . '_format_type' => 'slider' ),
120
				'default'    => 100,
121
				'type'       => 'text',
122
			),
123
			static::$type . '_max_length'  => array(
124
				'label'   => __( 'Maximum Length', 'pods' ),
125
				'default' => 12,
126
				'type'    => 'number',
127
				'help'    => __( 'Set to -1 for no limit', 'pods' ),
128
			),
129
			static::$type . '_placeholder' => array(
130
				'label'   => __( 'HTML Placeholder', 'pods' ),
131
				'default' => '',
132
				'type'    => 'text',
133
				'help'    => array(
134
					__( 'Placeholders can provide instructions or an example of the required data format for a field. Please note: It is not a replacement for labels or description text, and it is less accessible for people using screen readers.', 'pods' ),
135
					'https://www.w3.org/WAI/tutorials/forms/instructions/#placeholder-text',
136
				),
137
			), /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
52% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
138
		,
139
            static::$type . '_size' => array(
140
                'label' => __( 'Field Size', 'pods' ),
141
                'default' => 'medium',
142
                'type' => 'pick',
143
                'data' => array(
144
                    'small' => __( 'Small', 'pods' ),
145
                    'medium' => __( 'Medium', 'pods' ),
146
                    'large' => __( 'Large', 'pods' )
147
                )
148
            )*/
149
		);
150
151
		return $options;
152
	}
153
154
	/**
155
	 * Define the current field's schema for DB table storage
156
	 *
157
	 * @param array $options
158
	 *
159
	 * @return string
160
	 * @since 2.0
161
	 */
162
	public function schema( $options = null ) {
163
164
		$length = (int) pods_v( static::$type . '_max_length', $options, 12, true );
165
166
		if ( $length < 1 || 64 < $length ) {
167
			$length = 64;
168
		}
169
170
		$decimals = $this->get_max_decimals( $options );
171
172
		$schema = 'DECIMAL(' . $length . ',' . $decimals . ')';
173
174
		return $schema;
175
176
	}
177
178
	/**
179
	 * Define the current field's preparation for sprintf
180
	 *
181
	 * @param array $options
182
	 *
183
	 * @return string
184
	 * @since 2.0
185
	 */
186
	public function prepare( $options = null ) {
187
188
		$format = static::$prepare;
189
190
		$decimals = $this->get_max_decimals( $options );
191
192
		if ( 0 < $decimals ) {
193
			$format = '%F';
194
		}
195
196
		return $format;
197
198
	}
199
200
	/**
201
	 * {@inheritdoc}
202
	 */
203
	public function is_empty( $value = null ) {
204
205
		$is_empty = false;
206
207
		$value += 0;
208
209
		if ( empty( $value ) ) {
210
			$is_empty = true;
211
		}
212
213
		return $is_empty;
214
215
	}
216
217
	/**
218
	 * Change the way the value of the field is displayed with Pods::get
219
	 *
220
	 * @param mixed  $value
221
	 * @param string $name
222
	 * @param array  $options
223
	 * @param array  $pod
224
	 * @param int    $id
225
	 *
226
	 * @return mixed|null|string
227
	 * @since 2.0
228
	 */
229
	public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
230
231
		$value = $this->format( $value, $name, $options, $pod, $id );
232
233
		return $value;
234
	}
235
236
	/**
237
	 * Customize output of the form field
238
	 *
239
	 * @param string $name
240
	 * @param mixed  $value
241
	 * @param array  $options
242
	 * @param array  $pod
243
	 * @param int    $id
244
	 *
245
	 * @since 2.0
246
	 */
247
	public function input( $name, $value = null, $options = null, $pod = null, $id = null ) {
248
249
		$options         = (array) $options;
250
		$form_field_type = PodsForm::$field_type;
251
252
		if ( is_array( $value ) ) {
253
			$value = implode( '', $value );
254
		}
255
256
		if ( 'slider' == pods_v( static::$type . '_format_type', $options, 'number' ) ) {
257
			$field_type = 'slider';
258
		} else {
259
			$field_type = static::$type;
260
		}
261
262
		if ( isset( $options['name'] ) && false === PodsForm::permission( static::$type, $options['name'], $options, null, $pod, $id ) ) {
263 View Code Duplication
			if ( pods_v( 'read_only', $options, false ) ) {
264
				$options['readonly'] = true;
265
266
				$field_type = 'text';
267
268
				$value = $this->format( $value, $name, $options, $pod, $id );
269
			} else {
270
				return;
271
			}
272 View Code Duplication
		} elseif ( ! pods_has_permissions( $options ) && pods_v( 'read_only', $options, false ) ) {
273
			$options['readonly'] = true;
274
275
			$field_type = 'text';
276
277
			$value = $this->format( $value, $name, $options, $pod, $id );
278
		}
279
280
		pods_view( PODS_DIR . 'ui/fields/' . $field_type . '.php', compact( array_keys( get_defined_vars() ) ) );
281
282
	}
283
284
	/**
285
	 * Build regex necessary for JS validation
286
	 *
287
	 * @param mixed  $value
288
	 * @param string $name
289
	 * @param array  $options
290
	 * @param string $pod
291
	 * @param int    $id
292
	 *
293
	 * @return bool|string
294
	 * @since 2.0
295
	 */
296
	public function regex( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
297
298
		$format_args = $this->get_number_format_args( $options );
299
		$thousands   = $format_args['thousands'];
300
		$dot         = $format_args['dot'];
301
302
		return '\-*[0-9\\' . implode( '\\', array_filter( array( $dot, $thousands ) ) ) . ']+';
303
	}
304
305
	/**
306
	 * Validate a value before it's saved
307
	 *
308
	 * @param mixed  $value
309
	 * @param string $name
310
	 * @param array  $options
311
	 * @param array  $fields
312
	 * @param array  $pod
313
	 * @param int    $id
314
	 * @param null   $params
315
	 *
316
	 * @return bool|mixed
317
	 * @since 2.0
318
	 */
319
	public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
320
321
		$format_args = $this->get_number_format_args( $options );
322
		$thousands   = $format_args['thousands'];
323
		$dot         = $format_args['dot'];
324
325
		$check = str_replace(
326
			array( $thousands, $dot, html_entity_decode( $thousands ) ), array(
327
				'',
328
				'.',
329
				'',
330
			), $value
331
		);
332
		$check = trim( $check );
333
334
		$check = preg_replace( '/[0-9\.\-\s]/', '', $check );
335
336
		$label = pods_v( 'label', $options, ucwords( str_replace( '_', ' ', $name ) ) );
337
338
		if ( 0 < strlen( $check ) ) {
339
			return sprintf( __( '%s is not numeric', 'pods' ), $label );
340
		}
341
342
		return true;
343
	}
344
345
	/**
346
	 * Change the value or perform actions after validation but before saving to the DB
347
	 *
348
	 * @param mixed  $value
349
	 * @param int    $id
350
	 * @param string $name
351
	 * @param array  $options
352
	 * @param array  $fields
353
	 * @param array  $pod
354
	 * @param object $params
355
	 *
356
	 * @return mixed|string
357
	 * @since 2.0
358
	 */
359
	public function pre_save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
360
361
		$format_args = $this->get_number_format_args( $options );
362
		$thousands   = $format_args['thousands'];
363
		$dot         = $format_args['dot'];
364
		$decimals    = $format_args['decimals'];
365
366
		$value = str_replace( array( $thousands, $dot ), array( '', '.' ), $value );
367
		$value = trim( $value );
368
369
		$value = preg_replace( '/[^0-9\.\-]/', '', $value );
370
371
		$value = number_format( (float) $value, $decimals, '.', '' );
372
373
		return $value;
374
	}
375
376
	/**
377
	 * Customize the Pods UI manage table column output
378
	 *
379
	 * @param int    $id
380
	 * @param mixed  $value
381
	 * @param string $name
382
	 * @param array  $options
383
	 * @param array  $fields
384
	 * @param array  $pod
385
	 *
386
	 * @return mixed|null|string
387
	 * @since 2.0
388
	 */
389
	public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) {
390
391
		return $this->display( $value, $name, $options, $pod, $id );
392
	}
393
394
	/**
395
	 * Reformat a number to the way the value of the field is displayed
396
	 *
397
	 * @param mixed  $value
398
	 * @param string $name
399
	 * @param array  $options
400
	 * @param array  $pod
401
	 * @param int    $id
402
	 *
403
	 * @return string
404
	 * @since 2.0
405
	 */
406
	public function format( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
407
408
		if ( null === $value ) {
409
			// Don't enforce a default value here.
410
			return null;
411
		}
412
413
		$format_args = $this->get_number_format_args( $options );
414
		$thousands   = $format_args['thousands'];
415
		$dot         = $format_args['dot'];
416
		$decimals    = $format_args['decimals'];
417
418 View Code Duplication
		if ( 'i18n' == pods_v( static::$type . '_format', $options ) ) {
419
			$value = number_format_i18n( (float) $value, $decimals );
420
		} else {
421
			$value = number_format( (float) $value, $decimals, $dot, $thousands );
422
		}
423
424
		// Optionally remove trailing decimal zero's.
425
		if ( pods_v( static::$type . '_format_soft', $options, 0 ) ) {
426
			$parts = explode( $dot, $value );
427
			if ( isset( $parts[1] ) ) {
428
				$parts[1] = rtrim( $parts[1], '0' );
429
				$parts    = array_filter( $parts );
430
			}
431
			$value = implode( $dot, $parts );
432
		}
433
434
		return $value;
435
	}
436
437
	/**
438
	 * Get the formatting arguments for numbers.
439
	 *
440
	 * @since 2.7
441
	 *
442
	 * @param array $options Field options.
443
	 *
444
	 * @return array {
445
	 * @type string $thousands
446
	 * @type string $dot
447
	 * @type int    $decimals
448
	 * }
449
	 */
450
	public function get_number_format_args( $options ) {
451
452
		global $wp_locale;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
453
454
		if ( '9.999,99' == pods_v( static::$type . '_format', $options ) ) {
455
			$thousands = '.';
456
			$dot       = ',';
457 View Code Duplication
		} elseif ( '9,999.99' == pods_v( static::$type . '_format', $options ) ) {
458
			$thousands = ',';
459
			$dot       = '.';
460
		} elseif ( '9\'999.99' == pods_v( static::$type . '_format', $options ) ) {
461
			$thousands = '\'';
462
			$dot       = '.';
463 View Code Duplication
		} elseif ( '9 999,99' == pods_v( static::$type . '_format', $options ) ) {
464
			$thousands = ' ';
465
			$dot       = ',';
466
		} elseif ( '9999.99' == pods_v( static::$type . '_format', $options ) ) {
467
			$thousands = '';
468
			$dot       = '.';
469 View Code Duplication
		} elseif ( '9999,99' == pods_v( static::$type . '_format', $options ) ) {
470
			$thousands = '';
471
			$dot       = ',';
472
		} else {
473
			$thousands = $wp_locale->number_format['thousands_sep'];
474
			$dot       = $wp_locale->number_format['decimal_point'];
475
		}//end if
476
477
		$decimals = $this->get_max_decimals( $options );
478
479
		return array(
480
			'thousands' => $thousands,
481
			'dot'       => $dot,
482
			'decimals'  => $decimals,
483
		);
484
	}
485
486
	/**
487
	 * Get the max allowed decimals.
488
	 *
489
	 * @since 2.7
490
	 *
491
	 * @param array $options
492
	 *
493
	 * @return int
494
	 */
495 View Code Duplication
	public function get_max_decimals( $options ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
496
497
		$length = (int) pods_v( static::$type . '_max_length', $options, 12, true );
498
499
		if ( $length < 1 || 64 < $length ) {
500
			$length = 64;
501
		}
502
503
		$decimals = (int) pods_v( static::$type . '_decimals', $options, 0 );
504
505
		if ( $decimals < 1 ) {
506
			$decimals = 0;
507
		} elseif ( 30 < $decimals ) {
508
			$decimals = 30;
509
		}
510
511
		if ( $length < $decimals ) {
512
			$decimals = $length;
513
		}
514
515
		return $decimals;
516
	}
517
}
518