Create New Item
Item Type
File
Folder
Item Name
Search file in folder and subfolders...
Are you sure want to rename?
File Manager
/
wp-content
/
plugins
/
the-events-calendar
/
common
/
src
/
Tribe
/
Values
:
Abstract_Value.php
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
<?php namespace Tribe\Values; abstract class Abstract_Value implements Value_Interface { use Value_Calculation; use Value_Update; /** * Holds the initial value passed to the constructor. This variable does not change. * * @since 4.14.9 * * @var mixed */ private $initial_value; /** * Holds the value normalized value calculated when instantiating an object or setting new values. * * @since 4.14.9 * * @var float */ private $normalized_amount; /** * The integer representation of the amount. By default, this is the float value, rounded to the object precision * places and multiplied by (10^precision). * * @since 4.14.9 * * @var int */ private $integer = 0; /** * The float representation of the amount. By default, this is the same as $normalized_amount * * @since 4.14.9 * * @var float */ private $float = 0.0; /** * The decimal precision to use in calculations. * * @since 4.14.9 * * @var int */ private $precision = 2; /** * The class type representation to use when firing scoped filters * * @since 4.14.9 * * @var string */ public $value_type; /** * Initialize object * * @since 4.14.9 * * @param mixed $amount the value to set initially */ public function __construct( $amount = 0 ) { $this->set_initial_representation( $amount ); $this->set_normalized_amount( $amount ); $this->update(); } /** * @inheritDoc */ public static function create( $value = 0 ) { $class = get_called_class(); return new $class( $value ); } /** * @inheritDoc */ public function set_value( $amount ) { $this->set_normalized_amount( $amount ); $this->update(); } /** * @inheritDoc */ public function set_precision( $amount ) { $this->precision = $amount; } /** * @inheritDoc */ public function get_integer() { /** * Filter the value returned for get_integer() when implemented in a specific class name * * @since 4.14.9 * * @param int $integer the integer representation of the value * @param Abstract_Value the object instance * * @return int */ $integer = apply_filters( "tec_common_value_{$this->get_value_type()}_get_integer", $this->integer, $this ); /** * Filter the value returned for get_integer() when implemented in any class * * @since 4.14.9 * * @param int $integer the integer representation of the value * @param Abstract_Value the object instance * * @return int */ return apply_filters( 'tec_common_value_get_integer', $integer, $this ); } /** * @inheritDoc */ public function get_float() { /** * Filter the value returned for get_float() when implemented in a specific class name * * @since 4.14.9 * * @param float $float the float representation of the value * @param Abstract_Value the object instance * * @return float */ $float = apply_filters( "tec_common_value_{$this->get_value_type()}_get_float", $this->float, $this ); /** * Filter the value returned for get_float() when implemented in any class * * @since 4.14.9 * * @param float $float the float representation of the value * @param Abstract_Value the object instance * * @return float */ return apply_filters( 'tec_common_value_get_float', $float, $this ); } /** * @inheritDoc */ public function get_precision() { /** * Filter the value returned for get_precision() when implemented in a specific class name * * @since 4.14.9 * * @param int $precision the precision to which values will be calculated * @param Abstract_Value the object instance * * @return int */ $precision = apply_filters( "tec_common_value_{$this->get_value_type()}_get_precision", $this->precision, $this ); /** * Filter the value returned for get_precision() when implemented in any class * * @since 4.14.9 * * @param int $precision the precision to which values will be calculated * @param Abstract_Value the object instance * * @return int */ return (int) apply_filters( 'tec_common_value_get_precision', $precision, $this ); } /** * @inheritDoc */ public function get_normalized_value() { return $this->normalized_amount; } /** * @inheritDoc */ public function get_initial_representation() { return $this->initial_value; } /** * @inheritDoc */ public function get_value_type() { return $this->value_type; } /** * @inheritDoc */ public function normalize( $value ) { if ( is_numeric( $value ) ) { return (float) $value; } if ( $this->is_character_block( $value ) ) { return (float) 0; } $value = $this->remove_character_blocks( $value ); $value = $this->remove_html( $value ); // Get all non-digits from the amount preg_match_all( '/[^\d]/', $value, $non_digits ); // if the string is all digits, it is numeric if ( empty( $non_digits[0] ) ) { return (float) $value; } $pieces = $this->remove_non_digits( $value, $non_digits ); return (float) $this->assemble_normalized_value( $pieces ); } /** * Removes any blocks composed of all non-digit characters from the numeric string. These will usually represent * the currency code and any other pieces of text that may have been sent with the value. * * This is specially important in case the currency unit contains the same characters as the decimal/thousands * separators such as in Moroccan Dirham (1,234.56 .د.م.) or Danish Krone (kr. 1.234,56) * * @since 4.14.9 * * @param string $value the numeric string being normalized * * @return string */ private function remove_character_blocks( $value ) { foreach ( explode( ' ', $value ) as $block ) { if ( ! $this->is_character_block( $block ) ) { continue; } $value = str_replace( $block, '', $value ); } return $value; } /** * Removes all html tags and html entities from the value string * * @since 4.14.9 * * @param string $value the value being normalized * * @return string */ private function remove_html( $value ) { return wp_strip_all_tags( preg_replace( '/&[^;]+;/', '', trim( $value ) ) ); } /** * Takes the value string and a list of non-digit characters and removes any of those characters. If the character * is found to be a decimal separator, normalize it to a dot, so the number translates to a float. * * @since 4.14.9 * * @param string $value the value being normalized * @param string[] $non_digits a list of non-digit characters present in $value * @param string $separator a default separator to use when splitting the string * * @return string[] */ private function remove_non_digits( $value, $non_digits, $separator = '>>>' ) { $tokens = array_unique( $non_digits[0] ); foreach ( $tokens as $token ) { if ( $this->is_decimal_separator( $token, $value ) ) { $separator = $token; continue; } $value = str_replace( $token, '', $value ); } return explode( $separator, $value ); } /** * Re-assemble the normalized value to store. * * @since 4.14.9 * * @param int[] $pieces the normalized value split in an array. * * @return float */ private function assemble_normalized_value( $pieces ) { // If the initial amount did not have decimals specified, $pieces will be an array of a single // numeric value, so we just return it as a float. if ( 1 === count( $pieces ) && is_numeric( reset( $pieces ) ) ) { return (float) reset( $pieces ); } $decimal = array_pop( $pieces ); return (float) implode( '', array_merge( $pieces, [ '.', $decimal ] ) ); } /** * Private setter for the initial value the object was created with. This value cannot be changed during the object * lifecycle. * * @since 4.14.9 * * To set a new value discard the original object and create a new one. */ private function set_initial_representation( $amount ) { if ( empty( $this->initial_value ) ) { $this->initial_value = $amount; } } /** * Private setter for the normalized amount extracted from the initial value. * * @since 4.14.9 * * To set a new value use the public setter `$obj->set_value( $amount )` */ private function set_normalized_amount( $amount ) { $normalized_value = $this->normalize( $amount ); /** * Filter the value to be set as $normalized_amount for a specific implementation. * * @since 4.14.9 * * @param float $normalized_value the normalized value * @param Abstract_Value the object instance * * @return float */ $normalized_value = (float) apply_filters( "tec_common_{$this->get_value_type()}_value_normalized", $normalized_value, $this ); /** * Filter the value to be set as $normalized_amount for all implementations. * * @since 4.14.9 * * @param float $normalized_value the normalized value * @param Abstract_Value the object instance * * @return float */ $normalized_value = (float) apply_filters( "tec_common_value_normalized", $normalized_value, $this ); /** * Fire action right before setting the normalized value * * @since 4.14.9 * * @param float $normalized_value the normalized value * @param Abstract_Value the object instance */ do_action( 'tec_common_value_normalized', $normalized_value, $this ); $this->normalized_amount = $normalized_value; } /** * Private setter for the integer representation of the object amount. * * @since 4.14.9 * * To set a new value use the public setter `$obj->set_value( $amount )` */ protected function set_integer_value() { $this->integer = $this->to_integer( $this->normalized_amount ); } /** * Private setter for the floating point representation of the object amount. * * @since 4.14.9 * * To set a new value use the public setter `$obj->set_value( $amount )` */ protected function set_float_value() { $this->float = $this->normalized_amount; } /** * Tries to determine if a token is serving as a decimal separator or something else * in a string; * * The rule to determine a decimal is straightforward. It needs to exist only once * in the string and the piece of the string after the separator cannot be longer * than 2 digits. Anything else is serving another purpose. * * @since 4.14.9 * * @param $separator string a separator token, like . or , * @param $value string a number formatted as a string * * @return bool */ private function is_decimal_separator( $separator, $value ) { $pieces = array_filter( explode( $separator, $value ) ); foreach ( $pieces as $i => $block ) { if ( $this->is_character_block( $block ) ) { unset( $pieces[ $i ] ); } } if ( 2 === count( $pieces ) ) { return strlen( array_pop( $pieces ) ) < 3; } return false; } /** * Tests if a string is composed entirely of non-digit characters * * @since 4.14.9 * @since 6.4.1 Cast $block to string to avoid PHP 8.0 deprecation notice. * * @param string $block the string to check * * @return bool */ private function is_character_block( $block ) { return empty( preg_replace( '/\D/', '', (string) $block ) ); } }