Skip to content
Closed
25 changes: 3 additions & 22 deletions src/Parser/BitcoinMoneyParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use Money\Currencies\BitcoinCurrencies;
use Money\Currency;
use Money\Exception\ParserException;
use Money\Money;
use Money\MoneyParser;

/**
Expand All @@ -15,6 +14,8 @@
*/
final class BitcoinMoneyParser implements MoneyParser
{
use DecimalParser;

/**
* @var int
*/
Expand Down Expand Up @@ -56,27 +57,7 @@ public function parse($money, $forceCurrency = null)
}

$decimal = str_replace(BitcoinCurrencies::SYMBOL, '', $money);
$decimalSeparator = strpos($decimal, '.');

if (false !== $decimalSeparator) {
$decimal = rtrim($decimal, '0');
$lengthDecimal = strlen($decimal);
$decimal = str_replace('.', '', $decimal);
$decimal .= str_pad('', ($lengthDecimal - $decimalSeparator - $this->fractionDigits - 1) * -1, '0');
} else {
$decimal .= str_pad('', $this->fractionDigits, '0');
}

if (substr($decimal, 0, 1) === '-') {
$decimal = '-'.ltrim(substr($decimal, 1), '0');
} else {
$decimal = ltrim($decimal, '0');
}

if ('' === $decimal) {
$decimal = '0';
}

return new Money($decimal, $currency);
return $this->parseDecimal($decimal, $this->fractionDigits, $currency);
}
}
54 changes: 6 additions & 48 deletions src/Parser/DecimalMoneyParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
use Money\Currencies;
use Money\Currency;
use Money\Exception\ParserException;
use Money\Money;
use Money\MoneyParser;
use Money\Number;

/**
* Parses a decimal string into a Money object.
Expand All @@ -16,8 +14,13 @@
*/
final class DecimalMoneyParser implements MoneyParser
{
/**
* @deprecated This is here for BC reasons. Should not rely on this constant and will be removed on version 4.x
*/
const DECIMAL_PATTERN = '/^(?P<sign>-)?(?P<digits>0|[1-9]\d*)?\.?(?P<fraction>\d+)?$/';
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that removing this constant is probably a BC break.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reverted


use DecimalParser;

/**
* @var Currencies
*/
Expand Down Expand Up @@ -56,53 +59,8 @@ public function parse($money, $forceCurrency = null)
$currency = new Currency($currency);
}

$decimal = trim($money);

if ($decimal === '') {
return new Money(0, $currency);
}

$subunit = $this->currencies->subunitFor($currency);

if (!preg_match(self::DECIMAL_PATTERN, $decimal, $matches) || !isset($matches['digits'])) {
throw new ParserException(sprintf(
'Cannot parse "%s" to Money.',
$decimal
));
}

$negative = isset($matches['sign']) && $matches['sign'] === '-';

$decimal = $matches['digits'];

if ($negative) {
$decimal = '-'.$decimal;
}

if (isset($matches['fraction'])) {
$fractionDigits = strlen($matches['fraction']);
$decimal .= $matches['fraction'];
$decimal = Number::roundMoneyValue($decimal, $subunit, $fractionDigits);

if ($fractionDigits > $subunit) {
$decimal = substr($decimal, 0, $subunit - $fractionDigits);
} elseif ($fractionDigits < $subunit) {
$decimal .= str_pad('', $subunit - $fractionDigits, '0');
}
} else {
$decimal .= str_pad('', $subunit, '0');
}

if ($negative) {
$decimal = '-'.ltrim(substr($decimal, 1), '0');
} else {
$decimal = ltrim($decimal, '0');
}

if ($decimal === '' || $decimal === '-') {
$decimal = '0';
}

return new Money($decimal, $currency);
return $this->parseDecimal($money, $subunit, $currency);
}
}
76 changes: 76 additions & 0 deletions src/Parser/DecimalParser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

namespace Money\Parser;

use Money\Currency;
use Money\Exception\ParserException;
use Money\Money;
use Money\Number;

/**
* Common decimal parsing logic extracted from DecimalMoneyParser for reuse.
*
* @internal
*/
trait DecimalParser
{
/**
* @var string
*/
protected static $decimalPattern = '/^(?P<sign>-)?(?P<digits>0|[1-9]\d*)?\.?(?P<fraction>\d+)?$/';

/**
* @param string $decimal
* @param int $subunit
* @param Currency $currency
* @return Money
*/
protected function parseDecimal($decimal, $subunit, Currency $currency)
{
$decimal = trim($decimal);
if ($decimal === '') {
return new Money(0, $currency);
}

if (!preg_match(self::$decimalPattern, $decimal, $matches) || !isset($matches['digits'])) {
throw new ParserException(sprintf(
'Cannot parse "%s" to Money.',
$decimal
));
}

$negative = isset($matches['sign']) && $matches['sign'] === '-';

$decimal = $matches['digits'];

if ($negative) {
$decimal = '-'.$decimal;
}

if (isset($matches['fraction'])) {
$fractionDigits = strlen($matches['fraction']);
$decimal .= $matches['fraction'];
$decimal = Number::roundMoneyValue($decimal, $subunit, $fractionDigits);

if ($fractionDigits > $subunit) {
$decimal = substr($decimal, 0, $subunit - $fractionDigits);
} elseif ($fractionDigits < $subunit) {
$decimal .= str_pad('', $subunit - $fractionDigits, '0');
}
} else {
$decimal .= str_pad('', $subunit, '0');
}

if ($negative) {
$decimal = '-'.ltrim(substr($decimal, 1), '0');
} else {
$decimal = ltrim($decimal, '0');
}

if ($decimal === '' || $decimal === '-') {
$decimal = '0';
}

return new Money($decimal, $currency);
}
}
32 changes: 3 additions & 29 deletions src/Parser/IntlLocalizedDecimalParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
use Money\Currencies;
use Money\Currency;
use Money\Exception\ParserException;
use Money\Money;
use Money\MoneyParser;
use Money\Number;

/**
* Parses a string into a Money object using intl extension.
Expand All @@ -16,6 +14,8 @@
*/
final class IntlLocalizedDecimalParser implements MoneyParser
{
use DecimalParser;

/**
* @var \NumberFormatter
*/
Expand Down Expand Up @@ -70,33 +70,7 @@ public function parse($money, $forceCurrency = null)

$decimal = (string) $decimal;
$subunit = $this->currencies->subunitFor($forceCurrency);
$decimalPosition = strpos($decimal, '.');

if (false !== $decimalPosition) {
$decimalLength = strlen($decimal);
$fractionDigits = $decimalLength - $decimalPosition - 1;
$decimal = str_replace('.', '', $decimal);
$decimal = Number::roundMoneyValue($decimal, $subunit, $fractionDigits);

if ($fractionDigits > $subunit) {
$decimal = substr($decimal, 0, $decimalPosition + $subunit);
} elseif ($fractionDigits < $subunit) {
$decimal .= str_pad('', $subunit - $fractionDigits, '0');
}
} else {
$decimal .= str_pad('', $subunit, '0');
}

if ('-' === $decimal[0]) {
$decimal = '-'.ltrim(substr($decimal, 1), '0');
} else {
$decimal = ltrim($decimal, '0');
}

if ('' === $decimal) {
$decimal = '0';
}

return new Money($decimal, $forceCurrency);
return $this->parseDecimal($decimal, $subunit, $forceCurrency);
}
}
32 changes: 3 additions & 29 deletions src/Parser/IntlMoneyParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
use Money\Currencies;
use Money\Currency;
use Money\Exception\ParserException;
use Money\Money;
use Money\MoneyParser;
use Money\Number;

/**
* Parses a string into a Money object using intl extension.
Expand All @@ -16,6 +14,8 @@
*/
final class IntlMoneyParser implements MoneyParser
{
use DecimalParser;

/**
* @var \NumberFormatter
*/
Expand Down Expand Up @@ -71,33 +71,7 @@ public function parse($money, $forceCurrency = null)

$decimal = (string) $decimal;
$subunit = $this->currencies->subunitFor($currency);
$decimalPosition = strpos($decimal, '.');

if (false !== $decimalPosition) {
$decimalLength = strlen($decimal);
$fractionDigits = $decimalLength - $decimalPosition - 1;
$decimal = str_replace('.', '', $decimal);
$decimal = Number::roundMoneyValue($decimal, $subunit, $fractionDigits);

if ($fractionDigits > $subunit) {
$decimal = substr($decimal, 0, $decimalPosition + $subunit);
} elseif ($fractionDigits < $subunit) {
$decimal .= str_pad('', $subunit - $fractionDigits, '0');
}
} else {
$decimal .= str_pad('', $subunit, '0');
}

if ('-' === $decimal[0]) {
$decimal = '-'.ltrim(substr($decimal, 1), '0');
} else {
$decimal = ltrim($decimal, '0');
}

if ('' === $decimal) {
$decimal = '0';
}

return new Money($decimal, $currency);
return $this->parseDecimal($decimal, $subunit, $currency);
}
}