wpdatatables
/
lib
/
phpoffice
/
phpspreadsheet
/
src
/
PhpSpreadsheet
/
Calculation
/
TextData
/
Format.php
Format.php in wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin 6.5.1.7, at lib/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Calculation/TextData/Format.php
| 1 | <?php |
| 2 | |
| 3 | namespace PhpOffice\PhpSpreadsheet\Calculation\TextData; |
| 4 | |
| 5 | use Composer\Pcre\Preg; |
| 6 | use DateTimeInterface; |
| 7 | use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled; |
| 8 | use PhpOffice\PhpSpreadsheet\Calculation\Calculation; |
| 9 | use PhpOffice\PhpSpreadsheet\Calculation\DateTimeExcel; |
| 10 | use PhpOffice\PhpSpreadsheet\Calculation\Exception as CalcExp; |
| 11 | use PhpOffice\PhpSpreadsheet\Calculation\Functions; |
| 12 | use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError; |
| 13 | use PhpOffice\PhpSpreadsheet\Calculation\MathTrig; |
| 14 | use PhpOffice\PhpSpreadsheet\RichText\RichText; |
| 15 | use PhpOffice\PhpSpreadsheet\Shared\Date; |
| 16 | use PhpOffice\PhpSpreadsheet\Shared\StringHelper; |
| 17 | use PhpOffice\PhpSpreadsheet\Style\NumberFormat; |
| 18 | |
| 19 | class Format |
| 20 | { |
| 21 | use ArrayEnabled; |
| 22 | |
| 23 | /** |
| 24 | * DOLLAR. |
| 25 | * |
| 26 | * This function converts a number to text using currency format, with the decimals rounded to the specified place. |
| 27 | * The format used is $#,##0.00_);($#,##0.00).. |
| 28 | * |
| 29 | * @param mixed $value The value to format |
| 30 | * Or can be an array of values |
| 31 | * @param mixed $decimals The number of digits to display to the right of the decimal point (as an integer). |
| 32 | * If decimals is negative, number is rounded to the left of the decimal point. |
| 33 | * If you omit decimals, it is assumed to be 2 |
| 34 | * Or can be an array of values |
| 35 | * |
| 36 | * @return array|string |
| 37 | * If an array of values is passed for either of the arguments, then the returned result |
| 38 | * will also be an array with matching dimensions |
| 39 | */ |
| 40 | public static function DOLLAR($value = 0, $decimals = 2) |
| 41 | { |
| 42 | if (is_array($value) || is_array($decimals)) { |
| 43 | return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $decimals); |
| 44 | } |
| 45 | |
| 46 | try { |
| 47 | $value = Helpers::extractFloat($value); |
| 48 | $decimals = Helpers::extractInt($decimals, -100, 0, true); |
| 49 | } catch (CalcExp $e) { |
| 50 | return $e->getMessage(); |
| 51 | } |
| 52 | |
| 53 | $mask = '$#,##0'; |
| 54 | if ($decimals > 0) { |
| 55 | $mask .= '.' . str_repeat('0', $decimals); |
| 56 | } else { |
| 57 | $round = 10 ** abs($decimals); |
| 58 | if ($value < 0) { |
| 59 | $round = 0 - $round; |
| 60 | } |
| 61 | $value = MathTrig\Round::multiple($value, $round); |
| 62 | } |
| 63 | $mask = "{$mask};-{$mask}"; |
| 64 | |
| 65 | return NumberFormat::toFormattedString($value, $mask); |
| 66 | } |
| 67 | |
| 68 | /** |
| 69 | * FIXED. |
| 70 | * |
| 71 | * @param mixed $value The value to format |
| 72 | * Or can be an array of values |
| 73 | * @param mixed $decimals Integer value for the number of decimal places that should be formatted |
| 74 | * Or can be an array of values |
| 75 | * @param mixed $noCommas Boolean value indicating whether the value should have thousands separators or not |
| 76 | * Or can be an array of values |
| 77 | * |
| 78 | * @return array|string |
| 79 | * If an array of values is passed for either of the arguments, then the returned result |
| 80 | * will also be an array with matching dimensions |
| 81 | */ |
| 82 | public static function FIXEDFORMAT($value, $decimals = 2, $noCommas = false) |
| 83 | { |
| 84 | if (is_array($value) || is_array($decimals) || is_array($noCommas)) { |
| 85 | return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $decimals, $noCommas); |
| 86 | } |
| 87 | |
| 88 | try { |
| 89 | $value = Helpers::extractFloat($value); |
| 90 | $decimals = Helpers::extractInt($decimals, -100, 0, true); |
| 91 | } catch (CalcExp $e) { |
| 92 | return $e->getMessage(); |
| 93 | } |
| 94 | |
| 95 | $valueResult = round($value, $decimals); |
| 96 | if ($decimals < 0) { |
| 97 | $decimals = 0; |
| 98 | } |
| 99 | if ($noCommas === false) { |
| 100 | $valueResult = number_format( |
| 101 | $valueResult, |
| 102 | $decimals, |
| 103 | StringHelper::getDecimalSeparator(), |
| 104 | StringHelper::getThousandsSeparator() |
| 105 | ); |
| 106 | } |
| 107 | |
| 108 | return (string) $valueResult; |
| 109 | } |
| 110 | |
| 111 | /** |
| 112 | * TEXT. |
| 113 | * |
| 114 | * @param mixed $value The value to format |
| 115 | * Or can be an array of values |
| 116 | * @param mixed $format A string with the Format mask that should be used |
| 117 | * Or can be an array of values |
| 118 | * |
| 119 | * @return array|string |
| 120 | * If an array of values is passed for either of the arguments, then the returned result |
| 121 | * will also be an array with matching dimensions |
| 122 | */ |
| 123 | public static function TEXTFORMAT($value, $format) |
| 124 | { |
| 125 | if (is_array($value) || is_array($format)) { |
| 126 | return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $format); |
| 127 | } |
| 128 | |
| 129 | $value = Helpers::extractString($value); |
| 130 | $format = Helpers::extractString($format); |
| 131 | |
| 132 | if (!is_numeric($value) && Date::isDateTimeFormatCode($format) && !Preg::isMatch('/^\s*\d+(\s+\d+)+\s*$/', $value)) { |
| 133 | $value1 = DateTimeExcel\DateValue::fromString($value); |
| 134 | $value2 = DateTimeExcel\TimeValue::fromString($value); |
| 135 | /** @var float|int|string */ |
| 136 | $value = (is_numeric($value1) && is_numeric($value2)) ? ($value1 + $value2) : (is_numeric($value1) ? $value1 : (is_numeric($value2) ? $value2 : $value)); |
| 137 | } |
| 138 | |
| 139 | return (string) NumberFormat::toFormattedString($value, $format); |
| 140 | } |
| 141 | |
| 142 | /** |
| 143 | * @param mixed $value Value to check |
| 144 | * |
| 145 | * @return mixed |
| 146 | */ |
| 147 | private static function convertValue($value, bool $spacesMeanZero = false) |
| 148 | { |
| 149 | $value = $value ?? 0; |
| 150 | if (is_bool($value)) { |
| 151 | if (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE) { |
| 152 | $value = (int) $value; |
| 153 | } else { |
| 154 | throw new CalcExp(ExcelError::VALUE()); |
| 155 | } |
| 156 | } |
| 157 | if (is_string($value)) { |
| 158 | $value = trim($value); |
| 159 | if ($spacesMeanZero && $value === '') { |
| 160 | $value = 0; |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | return $value; |
| 165 | } |
| 166 | |
| 167 | /** |
| 168 | * VALUE. |
| 169 | * |
| 170 | * @param mixed $value Value to check |
| 171 | * Or can be an array of values |
| 172 | * |
| 173 | * @return array|DateTimeInterface|float|int|string A string if arguments are invalid |
| 174 | * If an array of values is passed for the argument, then the returned result |
| 175 | * will also be an array with matching dimensions |
| 176 | */ |
| 177 | public static function VALUE($value = '') |
| 178 | { |
| 179 | if (is_array($value)) { |
| 180 | return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $value); |
| 181 | } |
| 182 | |
| 183 | try { |
| 184 | $value = self::convertValue($value); |
| 185 | } catch (CalcExp $e) { |
| 186 | return $e->getMessage(); |
| 187 | } |
| 188 | if (!is_numeric($value)) { |
| 189 | $numberValue = str_replace( |
| 190 | StringHelper::getThousandsSeparator(), |
| 191 | '', |
| 192 | trim($value, " \t\n\r\0\x0B" . StringHelper::getCurrencyCode()) |
| 193 | ); |
| 194 | if ($numberValue === '') { |
| 195 | return ExcelError::VALUE(); |
| 196 | } |
| 197 | if (is_numeric($numberValue)) { |
| 198 | return (float) $numberValue; |
| 199 | } |
| 200 | |
| 201 | $dateSetting = Functions::getReturnDateType(); |
| 202 | Functions::setReturnDateType(Functions::RETURNDATE_EXCEL); |
| 203 | |
| 204 | if (strpos($value, ':') !== false) { |
| 205 | $timeValue = Functions::scalar(DateTimeExcel\TimeValue::fromString($value)); |
| 206 | if ($timeValue !== ExcelError::VALUE()) { |
| 207 | Functions::setReturnDateType($dateSetting); |
| 208 | |
| 209 | return $timeValue; |
| 210 | } |
| 211 | } |
| 212 | $dateValue = Functions::scalar(DateTimeExcel\DateValue::fromString($value)); |
| 213 | if ($dateValue !== ExcelError::VALUE()) { |
| 214 | Functions::setReturnDateType($dateSetting); |
| 215 | |
| 216 | return $dateValue; |
| 217 | } |
| 218 | Functions::setReturnDateType($dateSetting); |
| 219 | |
| 220 | return ExcelError::VALUE(); |
| 221 | } |
| 222 | |
| 223 | return (float) $value; |
| 224 | } |
| 225 | |
| 226 | /** |
| 227 | * TEXT. |
| 228 | * |
| 229 | * @param mixed $value The value to format |
| 230 | * Or can be an array of values |
| 231 | * @param mixed $format |
| 232 | * |
| 233 | * @return array|string |
| 234 | * If an array of values is passed for either of the arguments, then the returned result |
| 235 | * will also be an array with matching dimensions |
| 236 | */ |
| 237 | public static function valueToText($value, $format = false) |
| 238 | { |
| 239 | if (is_array($value) || is_array($format)) { |
| 240 | return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $format); |
| 241 | } |
| 242 | |
| 243 | $format = (bool) $format; |
| 244 | |
| 245 | if (is_object($value) && $value instanceof RichText) { |
| 246 | $value = $value->getPlainText(); |
| 247 | } |
| 248 | if (is_string($value)) { |
| 249 | $value = ($format === true) ? Calculation::wrapResult($value) : $value; |
| 250 | $value = str_replace("\n", '', $value); |
| 251 | } elseif (is_bool($value)) { |
| 252 | $value = Calculation::getLocaleBoolean($value ? 'TRUE' : 'FALSE'); |
| 253 | } |
| 254 | |
| 255 | return (string) $value; |
| 256 | } |
| 257 | |
| 258 | /** |
| 259 | * @param mixed $decimalSeparator |
| 260 | */ |
| 261 | private static function getDecimalSeparator($decimalSeparator): string |
| 262 | { |
| 263 | return empty($decimalSeparator) ? StringHelper::getDecimalSeparator() : (string) $decimalSeparator; |
| 264 | } |
| 265 | |
| 266 | /** |
| 267 | * @param mixed $groupSeparator |
| 268 | */ |
| 269 | private static function getGroupSeparator($groupSeparator): string |
| 270 | { |
| 271 | return empty($groupSeparator) ? StringHelper::getThousandsSeparator() : (string) $groupSeparator; |
| 272 | } |
| 273 | |
| 274 | /** |
| 275 | * NUMBERVALUE. |
| 276 | * |
| 277 | * @param mixed $value The value to format |
| 278 | * Or can be an array of values |
| 279 | * @param mixed $decimalSeparator A string with the decimal separator to use, defaults to locale defined value |
| 280 | * Or can be an array of values |
| 281 | * @param mixed $groupSeparator A string with the group/thousands separator to use, defaults to locale defined value |
| 282 | * Or can be an array of values |
| 283 | * |
| 284 | * @return array|float|string |
| 285 | */ |
| 286 | public static function NUMBERVALUE($value = '', $decimalSeparator = null, $groupSeparator = null) |
| 287 | { |
| 288 | if (is_array($value) || is_array($decimalSeparator) || is_array($groupSeparator)) { |
| 289 | return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $decimalSeparator, $groupSeparator); |
| 290 | } |
| 291 | |
| 292 | try { |
| 293 | $value = self::convertValue($value, true); |
| 294 | $decimalSeparator = self::getDecimalSeparator($decimalSeparator); |
| 295 | $groupSeparator = self::getGroupSeparator($groupSeparator); |
| 296 | } catch (CalcExp $e) { |
| 297 | return $e->getMessage(); |
| 298 | } |
| 299 | |
| 300 | if (!is_numeric($value)) { |
| 301 | $decimalPositions = preg_match_all('/' . preg_quote($decimalSeparator, '/') . '/', $value, $matches, PREG_OFFSET_CAPTURE); |
| 302 | if ($decimalPositions > 1) { |
| 303 | return ExcelError::VALUE(); |
| 304 | } |
| 305 | $decimalOffset = array_pop($matches[0])[1] ?? null; |
| 306 | if ($decimalOffset === null || strpos($value, $groupSeparator, $decimalOffset) !== false) { |
| 307 | return ExcelError::VALUE(); |
| 308 | } |
| 309 | |
| 310 | $value = str_replace([$groupSeparator, $decimalSeparator], ['', '.'], $value); |
| 311 | |
| 312 | // Handle the special case of trailing % signs |
| 313 | $percentageString = rtrim($value, '%'); |
| 314 | if (!is_numeric($percentageString)) { |
| 315 | return ExcelError::VALUE(); |
| 316 | } |
| 317 | |
| 318 | $percentageAdjustment = strlen($value) - strlen($percentageString); |
| 319 | if ($percentageAdjustment) { |
| 320 | $value = (float) $percentageString; |
| 321 | $value /= 10 ** ($percentageAdjustment * 2); |
| 322 | } |
| 323 | } |
| 324 | |
| 325 | return is_array($value) ? ExcelError::VALUE() : (float) $value; |
| 326 | } |
| 327 | } |
| 328 |