mirror of
https://github.com/processwire/processwire.git
synced 2025-08-15 03:05:26 +02:00
Additional updates, additions and fixes to $sanitizer->float(), InputfieldFloat and FieldtypeFloat per processwire/processwire-issues#1502
This commit is contained in:
@@ -3880,6 +3880,15 @@ class Sanitizer extends Wire {
|
||||
/**
|
||||
* Sanitize to floating point value
|
||||
*
|
||||
* Values for `getString` argument:
|
||||
*
|
||||
* - `false` (bool): do not return string value (default). 3.0.171+
|
||||
* - `true` (bool): locale aware floating point number string. 3.0.171+
|
||||
* - `f` (string): locale aware floating point number string (same as true). 3.0.193+
|
||||
* - `F` (string): non-locale aware floating point number string. 3.0.193+
|
||||
* - `e` (string): lowercase scientific notation (e.g. 1.2e+2). 3.0.193+
|
||||
* - `E` (string): uppercase scientific notation (e.g. 1.2E+2). 3.0.193+
|
||||
*
|
||||
* #pw-group-numbers
|
||||
*
|
||||
* @param float|string|int $value
|
||||
@@ -3889,8 +3898,8 @@ class Sanitizer extends Wire {
|
||||
* - `blankValue` (null|int|string|float): Value to return (whether float or non-float) if provided $value is an empty non-float (default=0.0)
|
||||
* - `min` (float|null): Minimum allowed value, excluding blankValue (default=null)
|
||||
* - `max` (float|null): Maximum allowed value, excluding blankValue (default=null)
|
||||
* - `getString (bool): Return a string rather than float value? (default=false) added 3.0.171
|
||||
* @return float
|
||||
* - `getString (bool|string): Return a string rather than float value? 3.0.171+ (default=false). See value options in method description.
|
||||
* @return float|string
|
||||
*
|
||||
*/
|
||||
public function float($value, array $options = array()) {
|
||||
@@ -3901,7 +3910,7 @@ class Sanitizer extends Wire {
|
||||
'blankValue' => 0.0, // Value to return (whether float or non-float) if provided $value is an empty non-float (default=0.0)
|
||||
'min' => null, // Minimum allowed value (excluding blankValue)
|
||||
'max' => null, // Maximum allowed value (excluding blankValue)
|
||||
'getString' => false, // Return a string rather than float value?
|
||||
'getString' => false, // Return a string rather than float value? bool or f, F, e, E
|
||||
);
|
||||
|
||||
$options = array_merge($defaults, $options);
|
||||
@@ -3926,10 +3935,11 @@ class Sanitizer extends Wire {
|
||||
$prepend = '-';
|
||||
$str = ltrim($str, '-');
|
||||
}
|
||||
|
||||
if((stripos($str, 'E-') || stripos($str, 'E+')) && preg_match('/^([0-9., ]+\d)(E[-+]\d+)/i', $str, $m)) {
|
||||
|
||||
if(stripos($str, 'E') && preg_match('/^([0-9., ]*\d)(E[-+]?\d+)/i', $str, $m)) {
|
||||
$str = $m[1];
|
||||
$append = $m[2];
|
||||
if($options['precision'] === null) $options['precision'] = ((int) ltrim($append, '-+eE'));
|
||||
}
|
||||
|
||||
if(!strlen($str)) return $options['blankValue'];
|
||||
@@ -3975,7 +3985,13 @@ class Sanitizer extends Wire {
|
||||
|
||||
$value = $prepend . $value . $append;
|
||||
if(!$options['getString']) $value = floatval($value);
|
||||
}
|
||||
|
||||
} else if(is_float($value)) {
|
||||
if($options['precision'] === null) {
|
||||
$str = strtoupper("$value");
|
||||
if(strpos($str, 'E')) $options['precision'] = (int) ltrim(stristr("$value", 'E'), 'E-+');
|
||||
}
|
||||
}
|
||||
|
||||
if(!$options['getString'] && !is_float($value)) $value = (float) $value;
|
||||
if(!is_null($options['min']) && ((float) $value) < ((float) $options['min'])) $value = $options['min'];
|
||||
@@ -3983,11 +3999,14 @@ class Sanitizer extends Wire {
|
||||
if(!is_null($options['precision'])) $value = round((float) $value, (int) $options['precision'], (int) $options['mode']);
|
||||
|
||||
if($options['getString']) {
|
||||
$f = $options['getString'];
|
||||
$f = is_string($f) && in_array($f, array('f', 'F', 'e', 'E')) ? $f : 'f';
|
||||
if($options['precision'] === null) {
|
||||
$value = strpos($value, 'E-') || strpos($value, 'E+') ? rtrim(sprintf('%.20f', (float) $value), '0') : "$value";
|
||||
$value = stripos("$value", 'E') ? rtrim(sprintf("%.15$f", (float) $value), '0') : "$value";
|
||||
} else {
|
||||
$value = sprintf('%.' . $options['precision'] . 'f', (float) $value);
|
||||
$value = sprintf("%.$options[precision]$f", (float) $value);
|
||||
}
|
||||
$value = rtrim($value, '.');
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
@@ -8,7 +8,7 @@
|
||||
* For documentation about the fields used in this class, please see:
|
||||
* /wire/core/Fieldtype.php
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2020 by Ryan Cramer
|
||||
* ProcessWire 3.x, Copyright 2022 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
*/
|
||||
@@ -19,7 +19,7 @@ class FieldtypeFloat extends Fieldtype {
|
||||
return array(
|
||||
'title' => __('Float', __FILE__),
|
||||
'summary' => __('Field that stores a floating point number', __FILE__),
|
||||
'version' => 106,
|
||||
'version' => 107,
|
||||
'permanent' => true,
|
||||
);
|
||||
}
|
||||
@@ -86,7 +86,7 @@ class FieldtypeFloat extends Fieldtype {
|
||||
$value = $this->wire()->sanitizer->float((string) $value, array('blankValue' => ''));
|
||||
}
|
||||
$precision = $field->get('precision');
|
||||
if($precision === null || $precision === '') {
|
||||
if($precision === null || $precision === '' || $precision < 0) {
|
||||
$value = (float) $value;
|
||||
} else {
|
||||
$value = round((float) $value, $precision);
|
||||
@@ -121,9 +121,13 @@ class FieldtypeFloat extends Fieldtype {
|
||||
*/
|
||||
public function ___sleepValue(Page $page, Field $field, $value) {
|
||||
$precision = $field->get('precision');
|
||||
if(is_null($precision) || $precision === '') $precision = self::getPrecision($value);
|
||||
if(!is_string($value)) $value = number_format($value, $precision, '.', '');
|
||||
return $value;
|
||||
if(is_null($precision) || $precision === '' || $precision < 0) {
|
||||
$precision = self::getPrecision($value);
|
||||
}
|
||||
if(!is_string($value)) {
|
||||
$value = number_format($value, $precision, '.', '');
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,8 +139,13 @@ class FieldtypeFloat extends Fieldtype {
|
||||
*/
|
||||
public static function getPrecision($value) {
|
||||
$value = (float) $value;
|
||||
$remainder = ceil($value) - $value;
|
||||
$precision = strlen(ltrim($remainder, '0., '));
|
||||
if(stripos("$value", 'E')) {
|
||||
list(,$precision) = explode('E', strtoupper("$value"), 2);
|
||||
$precision = (int) ltrim($precision, '+-');
|
||||
} else {
|
||||
$remainder = ceil($value) - $value;
|
||||
$precision = strlen(ltrim("$remainder", '0., '));
|
||||
}
|
||||
if(!$precision) $precision = 1;
|
||||
return $precision;
|
||||
}
|
||||
@@ -170,6 +179,7 @@ class FieldtypeFloat extends Fieldtype {
|
||||
$f = $this->wire()->modules->get('InputfieldInteger');
|
||||
$f->attr('name', 'precision');
|
||||
$f->label = $this->_('Number of decimal digits to round to');
|
||||
$f->description = $this->_('Or use a negative number like `-1` to disable rounding.');
|
||||
if($precision !== '') $f->val($precision);
|
||||
$f->attr('size', 8);
|
||||
$inputfields->append($f);
|
||||
|
@@ -6,7 +6,7 @@
|
||||
* ProcessWire 3.x, Copyright 2022 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
* @property int $precision Decimals precision
|
||||
* @property int $precision Decimals precision (or -1 to disable rounding in 3.0.193+)
|
||||
* @property int $digits Total digits, for when used in decimal mode (default=0)
|
||||
* @property string $inputType Input type to use, one of "text" or "number"
|
||||
* @property int|float $min
|
||||
@@ -25,7 +25,7 @@ class InputfieldFloat extends InputfieldInteger {
|
||||
return array(
|
||||
'title' => __('Float', __FILE__), // Module Title
|
||||
'summary' => __('Floating point number with precision', __FILE__), // Module Summary
|
||||
'version' => 104,
|
||||
'version' => 105,
|
||||
'permanent' => true,
|
||||
);
|
||||
}
|
||||
@@ -59,7 +59,7 @@ class InputfieldFloat extends InputfieldInteger {
|
||||
protected function getPrecision($value = null) {
|
||||
if($value !== null) return FieldtypeFloat::getPrecision($value);
|
||||
$precision = $this->precision;
|
||||
return $precision === null || $precision === '' ? '' : (int) $precision;
|
||||
return $precision === null || $precision === '' || $precision < 0 ? '' : (int) $precision;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,10 +78,8 @@ class InputfieldFloat extends InputfieldInteger {
|
||||
if(!strlen("$value")) return '';
|
||||
}
|
||||
$precision = $this->precision;
|
||||
if($precision === null || $precision === '') {
|
||||
$precision = FieldtypeFloat::getPrecision($value);
|
||||
}
|
||||
return round((float) $value, $precision);
|
||||
if($precision === null || $precision === '') $precision = $this->getPrecision($value);
|
||||
return is_int($precision) && $precision > 0 ? round((float) $value, $precision) : $value;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,6 +93,23 @@ class InputfieldFloat extends InputfieldInteger {
|
||||
return (float) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is value in scientific notation?
|
||||
*
|
||||
* @param string $value
|
||||
* @return bool
|
||||
* @since 3.0.193
|
||||
*
|
||||
*/
|
||||
public function isScientific($value) {
|
||||
$value = strtoupper((string) $value);
|
||||
if(strpos($value, 'E') === false) return false;
|
||||
$value = str_replace('.', '', $value);
|
||||
list($a, $b) = explode('E', $value, 2);
|
||||
$b = trim($b, '+-');
|
||||
return ctype_digit("$a$b");
|
||||
}
|
||||
|
||||
/**
|
||||
* Override method from Inputfield to convert locale specific decimals for input[type=number]
|
||||
*
|
||||
@@ -105,8 +120,8 @@ class InputfieldFloat extends InputfieldInteger {
|
||||
public function getAttributesString(array $attributes = null) {
|
||||
if($attributes && $attributes['type'] === 'number') {
|
||||
$value = isset($attributes['value']) ? $attributes['value'] : null;
|
||||
if(is_float($value) || is_string($value)) {
|
||||
if(strlen("$value") && !ctype_digit(str_replace('.', '', ltrim($value, '-')))) {
|
||||
if(is_float($value) || (is_string($value) && strlen($value))) {
|
||||
if(!$this->isScientific($value) && !ctype_digit(str_replace('.', '', ltrim($value, '-')))) {
|
||||
// float value is using a non "." as decimal point, needs conversion because
|
||||
// the HTML5 number input type requires "." as the decimal
|
||||
$attributes['value'] = $this->localeConvertValue($value);
|
||||
@@ -117,10 +132,8 @@ class InputfieldFloat extends InputfieldInteger {
|
||||
$attributes['step'] = '.' . ($precision > 1 ? str_repeat('0', $precision - 1) : '') . '1';
|
||||
}
|
||||
}
|
||||
if($attributes && isset($attributes['value']) && stripos($attributes['value'], 'E')) {
|
||||
$attributes['value'] = $this->wire()->sanitizer->float($attributes['value'], array(
|
||||
'getString' => true,
|
||||
));
|
||||
if($attributes && isset($attributes['value']) && $this->isScientific($attributes['value'])) {
|
||||
$attributes['value'] = $this->wire()->sanitizer->float($attributes['value']);
|
||||
}
|
||||
return parent::getAttributesString($attributes);
|
||||
}
|
||||
@@ -152,10 +165,12 @@ class InputfieldFloat extends InputfieldInteger {
|
||||
public function getConfigInputfields() {
|
||||
$inputfields = parent::getConfigInputfields();
|
||||
if($this->hasFieldtype === false) {
|
||||
// when used without FieldtypeFloat
|
||||
/** @var InputfieldInteger $f */
|
||||
$f = $this->wire()->modules->get('InputfieldInteger');
|
||||
$f->attr('name', 'precision');
|
||||
$f->label = $this->_('Number of decimal digits to round to');
|
||||
$f->description = $this->_('Or use a negative number like `-1` to disable rounding.');
|
||||
$f->attr('value', $this->precision);
|
||||
$f->attr('size', 8);
|
||||
$inputfields->add($f);
|
||||
|
Reference in New Issue
Block a user