Completed
Pull Request — 2.x (#4569)
by Scott Kingsley
04:42
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
	 * {@inheritdoc}
10
	 */
11
	public static $group = 'Number';
12
13
	/**
14
	 * {@inheritdoc}
15
	 */
16
	public static $type = 'number';
17
18
	/**
19
	 * {@inheritdoc}
20
	 */
21
	public static $label = 'Plain Number';
22
23
	/**
24
	 * {@inheritdoc}
25
	 */
26
	public static $prepare = '%d';
27
28
	/**
29
	 * {@inheritdoc}
30
	 */
31
	public function __construct() {
32
33
		self::$label = __( 'Plain Number', 'pods' );
34
	}
35
36
	/**
37
	 * {@inheritdoc}
38
	 */
39
	public function options() {
40
41
		$options = array(
42
			static::$type . '_repeatable'  => array(
43
				'label'             => __( 'Repeatable Field', 'pods' ),
44
				'default'           => 0,
45
				'type'              => 'boolean',
46
				'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' ),
47
				'boolean_yes_label' => '',
48
				'dependency'        => true,
49
				'developer_mode'    => true,
50
			),
51
			static::$type . '_format_type' => array(
52
				'label'      => __( 'Input Type', 'pods' ),
53
				'default'    => 'number',
54
				'type'       => 'pick',
55
				'data'       => array(
56
					'number' => __( 'Freeform Number', 'pods' ),
57
					'slider' => __( 'Slider', 'pods' ),
58
				),
59
				'dependency' => true,
60
			),
61
			static::$type . '_format'      => array(
62
				'label'   => __( 'Format', 'pods' ),
63
				'default' => apply_filters( 'pods_form_ui_field_number_format_default', 'i18n' ),
64
				'type'    => 'pick',
65
				'data'    => array(
66
					'i18n'     => __( 'Localized Default', 'pods' ),
67
					'9,999.99' => '1,234.00',
68
					'9.999,99' => '1.234,00',
69
					'9 999,99' => '1 234,00',
70
					'9999.99'  => '1234.00',
71
					'9999,99'  => '1234,00',
72
				),
73
			),
74
			static::$type . '_decimals'    => array(
75
				'label'      => __( 'Decimals', 'pods' ),
76
				'default'    => 0,
77
				'type'       => 'number',
78
				'dependency' => true,
79
			),
80
			static::$type . '_format_soft' => array(
81
				'label'       => __( 'Soft format?', 'pods' ),
82
				'help'        => __( 'Remove trailing decimals (0)', 'pods' ),
83
				'default'     => 0,
84
				'type'        => 'boolean',
85
				'excludes-on' => array( static::$type . '_decimals' => 0 ),
86
			),
87
			static::$type . '_step'        => array(
88
				'label'      => __( 'Slider Increment (Step)', 'pods' ),
89
				'depends-on' => array( static::$type . '_format_type' => 'slider' ),
90
				'default'    => 1,
91
				'type'       => 'text',
92
			),
93
			static::$type . '_min'         => array(
94
				'label'      => __( 'Minimum Number', 'pods' ),
95
				'depends-on' => array( static::$type . '_format_type' => 'slider' ),
96
				'default'    => 0,
97
				'type'       => 'text',
98
			),
99
			static::$type . '_max'         => array(
100
				'label'      => __( 'Maximum Number', 'pods' ),
101
				'depends-on' => array( static::$type . '_format_type' => 'slider' ),
102
				'default'    => 100,
103
				'type'       => 'text',
104
			),
105
			static::$type . '_max_length'  => array(
106
				'label'   => __( 'Maximum Length', 'pods' ),
107
				'default' => 12,
108
				'type'    => 'number',
109
				'help'    => __( 'Set to -1 for no limit', 'pods' ),
110
			),
111
			static::$type . '_placeholder' => array(
112
				'label'   => __( 'HTML Placeholder', 'pods' ),
113
				'default' => '',
114
				'type'    => 'text',
115
				'help'    => array(
116
					__( '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' ),
117
					'https://www.w3.org/WAI/tutorials/forms/instructions/#placeholder-text',
118
				),
119
			),
120
		);
121
122
		return $options;
123
	}
124
125
	/**
126
	 * {@inheritdoc}
127
	 */
128
	public function schema( $options = null ) {
129
130
		$length = (int) pods_v( static::$type . '_max_length', $options, 12, true );
131
132
		if ( $length < 1 || 64 < $length ) {
133
			$length = 64;
134
		}
135
136
		$decimals = $this->get_max_decimals( $options );
137
138
		$schema = 'DECIMAL(' . $length . ',' . $decimals . ')';
139
140
		return $schema;
141
142
	}
143
144
	/**
145
	 * {@inheritdoc}
146
	 */
147
	public function prepare( $options = null ) {
148
149
		$format = static::$prepare;
150
151
		$decimals = $this->get_max_decimals( $options );
152
153
		if ( 0 < $decimals ) {
154
			$format = '%F';
155
		}
156
157
		return $format;
158
159
	}
160
161
	/**
162
	 * {@inheritdoc}
163
	 */
164
	public function is_empty( $value = null ) {
165
166
		$is_empty = false;
167
168
		$value += 0;
169
170
		if ( empty( $value ) ) {
171
			$is_empty = true;
172
		}
173
174
		return $is_empty;
175
176
	}
177
178
	/**
179
	 * {@inheritdoc}
180
	 */
181
	public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
182
183
		$value = $this->format( $value, $name, $options, $pod, $id );
184
185
		return $value;
186
	}
187
188
	/**
189
	 * {@inheritdoc}
190
	 */
191
	public function input( $name, $value = null, $options = null, $pod = null, $id = null ) {
192
193
		$options         = (array) $options;
194
		$form_field_type = PodsForm::$field_type;
195
196
		if ( is_array( $value ) ) {
197
			$value = implode( '', $value );
198
		}
199
200
		if ( 'slider' === pods_v( static::$type . '_format_type', $options, 'number' ) ) {
201
			$field_type = 'slider';
202
		} else {
203
			$field_type = static::$type;
204
		}
205
206
		if ( isset( $options['name'] ) && false === PodsForm::permission( static::$type, $options['name'], $options, null, $pod, $id ) ) {
207 View Code Duplication
			if ( pods_v( 'read_only', $options, false ) ) {
208
				$options['readonly'] = true;
209
210
				$field_type = 'text';
211
212
				$value = $this->format( $value, $name, $options, $pod, $id );
213
			} else {
214
				return;
215
			}
216 View Code Duplication
		} elseif ( ! pods_has_permissions( $options ) && pods_v( 'read_only', $options, false ) ) {
217
			$options['readonly'] = true;
218
219
			$field_type = 'text';
220
221
			$value = $this->format( $value, $name, $options, $pod, $id );
222
		}
223
224
		pods_view( PODS_DIR . 'ui/fields/' . $field_type . '.php', compact( array_keys( get_defined_vars() ) ) );
225
226
	}
227
228
	/**
229
	 * {@inheritdoc}
230
	 */
231
	public function regex( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
232
233
		$format_args = $this->get_number_format_args( $options );
234
		$thousands   = $format_args['thousands'];
235
		$dot         = $format_args['dot'];
236
237
		return '\-*[0-9\\' . implode( '\\', array_filter( array( $dot, $thousands ) ) ) . ']+';
238
	}
239
240
	/**
241
	 * {@inheritdoc}
242
	 */
243
	public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
244
245
		$format_args = $this->get_number_format_args( $options );
246
		$thousands   = $format_args['thousands'];
247
		$dot         = $format_args['dot'];
248
249
		$check = str_replace(
250
			array( $thousands, $dot, html_entity_decode( $thousands ) ), array(
251
				'',
252
				'.',
253
				'',
254
			), $value
255
		);
256
		$check = trim( $check );
257
258
		$check = preg_replace( '/[0-9\.\-\s]/', '', $check );
259
260
		$label = pods_v( 'label', $options, ucwords( str_replace( '_', ' ', $name ) ) );
261
262
		if ( 0 < strlen( $check ) ) {
263
			return sprintf( __( '%s is not numeric', 'pods' ), $label );
264
		}
265
266
		return true;
267
	}
268
269
	/**
270
	 * {@inheritdoc}
271
	 */
272
	public function pre_save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
273
274
		$format_args = $this->get_number_format_args( $options );
275
		$thousands   = $format_args['thousands'];
276
		$dot         = $format_args['dot'];
277
		$decimals    = $format_args['decimals'];
278
279
		$value = str_replace( array( $thousands, $dot ), array( '', '.' ), $value );
280
		$value = trim( $value );
281
282
		$value = preg_replace( '/[^0-9\.\-]/', '', $value );
283
284
		$value = number_format( (float) $value, $decimals, '.', '' );
285
286
		return $value;
287
	}
288
289
	/**
290
	 * {@inheritdoc}
291
	 */
292
	public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) {
293
294
		return $this->display( $value, $name, $options, $pod, $id );
295
	}
296
297
	/**
298
	 * {@inheritdoc}
299
	 */
300
	public function format( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
301
302
		if ( null === $value ) {
303
			// Don't enforce a default value here.
304
			return null;
305
		}
306
307
		$format_args = $this->get_number_format_args( $options );
308
		$thousands   = $format_args['thousands'];
309
		$dot         = $format_args['dot'];
310
		$decimals    = $format_args['decimals'];
311
312 View Code Duplication
		if ( 'i18n' === pods_v( static::$type . '_format', $options ) ) {
313
			$value = number_format_i18n( (float) $value, $decimals );
314
		} else {
315
			$value = number_format( (float) $value, $decimals, $dot, $thousands );
316
		}
317
318
		// Optionally remove trailing decimal zero's.
319
		if ( pods_v( static::$type . '_format_soft', $options, 0 ) ) {
320
			$parts = explode( $dot, $value );
321
			if ( isset( $parts[1] ) ) {
322
				$parts[1] = rtrim( $parts[1], '0' );
323
				$parts    = array_filter( $parts );
324
			}
325
			$value = implode( $dot, $parts );
326
		}
327
328
		return $value;
329
	}
330
331
	/**
332
	 * Get the formatting arguments for numbers.
333
	 *
334
	 * @since 2.7
335
	 *
336
	 * @param array $options Field options.
337
	 *
338
	 * @return array {
339
	 * @type string $thousands
340
	 * @type string $dot
341
	 * @type int    $decimals
342
	 * }
343
	 */
344
	public function get_number_format_args( $options ) {
345
346
		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...
347
348
		if ( '9.999,99' === pods_v( static::$type . '_format', $options ) ) {
349
			$thousands = '.';
350
			$dot       = ',';
351 View Code Duplication
		} elseif ( '9,999.99' === pods_v( static::$type . '_format', $options ) ) {
352
			$thousands = ',';
353
			$dot       = '.';
354
		} elseif ( '9\'999.99' === pods_v( static::$type . '_format', $options ) ) {
355
			$thousands = '\'';
356
			$dot       = '.';
357 View Code Duplication
		} elseif ( '9 999,99' === pods_v( static::$type . '_format', $options ) ) {
358
			$thousands = ' ';
359
			$dot       = ',';
360
		} elseif ( '9999.99' === pods_v( static::$type . '_format', $options ) ) {
361
			$thousands = '';
362
			$dot       = '.';
363 View Code Duplication
		} elseif ( '9999,99' === pods_v( static::$type . '_format', $options ) ) {
364
			$thousands = '';
365
			$dot       = ',';
366
		} else {
367
			$thousands = $wp_locale->number_format['thousands_sep'];
368
			$dot       = $wp_locale->number_format['decimal_point'];
369
		}//end if
370
371
		$decimals = $this->get_max_decimals( $options );
372
373
		return array(
374
			'thousands' => $thousands,
375
			'dot'       => $dot,
376
			'decimals'  => $decimals,
377
		);
378
	}
379
380
	/**
381
	 * Get the max allowed decimals.
382
	 *
383
	 * @since 2.7
384
	 *
385
	 * @param array $options
386
	 *
387
	 * @return int
388
	 */
389 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...
390
391
		$length = (int) pods_v( static::$type . '_max_length', $options, 12, true );
392
393
		if ( $length < 1 || 64 < $length ) {
394
			$length = 64;
395
		}
396
397
		$decimals = (int) pods_v( static::$type . '_decimals', $options, 0 );
398
399
		if ( $decimals < 1 ) {
400
			$decimals = 0;
401
		} elseif ( 30 < $decimals ) {
402
			$decimals = 30;
403
		}
404
405
		if ( $length < $decimals ) {
406
			$decimals = $length;
407
		}
408
409
		return $decimals;
410
	}
411
}
412