-
Notifications
You must be signed in to change notification settings - Fork 445
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
support for bitcoin parsing and formatting
- Loading branch information
1 parent
d5bb47f
commit 40dd2c7
Showing
4 changed files
with
291 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
<?php | ||
|
||
namespace Money\Formatter; | ||
|
||
use Money\Money; | ||
use Money\MoneyFormatter; | ||
use Money\Parser\BitcoinSupportedMoneyParser; | ||
|
||
class BitcoinSupportedMoneyFormatter implements MoneyFormatter | ||
{ | ||
const CODE = 'XBT'; | ||
|
||
/** | ||
* @var MoneyFormatter | ||
*/ | ||
private $innerFormatter; | ||
/** | ||
* @var int | ||
*/ | ||
private $fractionDigits; | ||
|
||
/** | ||
* @param MoneyFormatter $innerFormatter | ||
* @param $fractionDigits | ||
*/ | ||
public function __construct(MoneyFormatter $innerFormatter, $fractionDigits) | ||
{ | ||
$this->innerFormatter = $innerFormatter; | ||
$this->fractionDigits = $fractionDigits; | ||
} | ||
|
||
/** | ||
* Formats a Money object as string. | ||
* | ||
* @param Money $money | ||
* | ||
* @return string | ||
*/ | ||
public function format(Money $money) | ||
{ | ||
if ($money->getCurrency()->getCode() !== self::CODE) { | ||
return $this->innerFormatter->format($money); | ||
} | ||
|
||
$valueBase = (string) $money->getAmount(); | ||
$negative = false; | ||
|
||
if (substr($valueBase, 0, 1) === '-') { | ||
$negative = true; | ||
$valueBase = substr($valueBase, 1); | ||
} | ||
|
||
$fractionDigits = $this->fractionDigits; | ||
$valueLength = strlen($valueBase); | ||
if ($valueLength > $fractionDigits) { | ||
$subunits = substr($valueBase, 0, $valueLength - $fractionDigits); | ||
if ($fractionDigits) { | ||
$subunits .= '.'; | ||
$subunits .= substr($valueBase, $valueLength - $fractionDigits); | ||
} | ||
} else { | ||
$subunits = '0.'.str_pad('', $fractionDigits - $valueLength, '0').$valueBase; | ||
} | ||
|
||
if ($negative === true) { | ||
$subunits = '-'.BitcoinSupportedMoneyParser::SYMBOL.$subunits; | ||
} else { | ||
$subunits = BitcoinSupportedMoneyParser::SYMBOL.$subunits; | ||
} | ||
|
||
return $subunits; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
<?php | ||
|
||
namespace Money\Parser; | ||
|
||
use Money\Currency; | ||
use Money\Formatter\BitcoinSupportedMoneyFormatter; | ||
use Money\Money; | ||
use Money\MoneyParser; | ||
|
||
class BitcoinSupportedMoneyParser implements MoneyParser | ||
{ | ||
const SYMBOL = "\0xC9\0x83"; | ||
|
||
/** | ||
* @var MoneyParser | ||
*/ | ||
private $innerParser; | ||
/** | ||
* @var int | ||
*/ | ||
private $fractionDigits; | ||
|
||
/** | ||
* @param MoneyParser $innerParser | ||
* @param $fractionDigits | ||
*/ | ||
public function __construct(MoneyParser $innerParser, $fractionDigits) | ||
{ | ||
$this->innerParser = $innerParser; | ||
$this->fractionDigits = $fractionDigits; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function parse($formattedMoney, $forceCurrency = null) | ||
{ | ||
if (strpos($formattedMoney, self::SYMBOL) === false) { | ||
return $this->innerParser->parse($formattedMoney, $forceCurrency); | ||
} | ||
|
||
$decimal = str_replace(self::SYMBOL, '', $formattedMoney); | ||
$decimalSeparator = strpos($decimal, '.'); | ||
if ($decimalSeparator !== false) { | ||
$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, new Currency(BitcoinSupportedMoneyFormatter::CODE)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
<?php | ||
|
||
namespace Tests\Money\Formatter; | ||
|
||
use Money\Formatter\BitcoinSupportedMoneyFormatter; | ||
use Money\Currency; | ||
use Money\Formatter\IntlMoneyFormatter; | ||
use Money\Money; | ||
|
||
final class BitcoinSupportedMoneyFormatterTest extends \PHPUnit_Framework_TestCase | ||
{ | ||
public function testRoundMoney() | ||
{ | ||
$money = new Money(100000, new Currency('XBT')); | ||
|
||
$numberFormatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); | ||
$numberFormatter->setPattern('¤#,##0.00;-¤#,##0.00'); | ||
|
||
$intlFormatter = new IntlMoneyFormatter($numberFormatter); | ||
$formatter = new BitcoinSupportedMoneyFormatter($intlFormatter, 2); | ||
$this->assertEquals("\0xC9\0x831000.00", $formatter->format($money)); | ||
} | ||
|
||
public function testLessThanOneHundred() | ||
{ | ||
$money = new Money(41, new Currency('XBT')); | ||
|
||
$numberFormatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); | ||
$numberFormatter->setPattern('¤#,##0.00;-¤#,##0.00'); | ||
|
||
$intlFormatter = new IntlMoneyFormatter($numberFormatter); | ||
$formatter = new BitcoinSupportedMoneyFormatter($intlFormatter, 2); | ||
$this->assertEquals("\0xC9\0x830.41", $formatter->format($money)); | ||
} | ||
|
||
public function testLessThanTen() | ||
{ | ||
$money = new Money(5, new Currency('XBT')); | ||
|
||
$numberFormatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); | ||
$numberFormatter->setPattern('¤#,##0.00;-¤#,##0.00'); | ||
|
||
$intlFormatter = new IntlMoneyFormatter($numberFormatter); | ||
$formatter = new BitcoinSupportedMoneyFormatter($intlFormatter, 2); | ||
$this->assertEquals("\0xC9\0x830.05", $formatter->format($money)); | ||
} | ||
|
||
public function testZeroFractionDigits() | ||
{ | ||
$money = new Money(5, new Currency('XBT')); | ||
|
||
$numberFormatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); | ||
$numberFormatter->setPattern('¤#,##0.00;-¤#,##0.00'); | ||
|
||
$intlFormatter = new IntlMoneyFormatter($numberFormatter); | ||
$formatter = new BitcoinSupportedMoneyFormatter($intlFormatter, 0); | ||
$this->assertEquals("\0xC9\0x835", $formatter->format($money)); | ||
} | ||
|
||
public function testDifferentFractionDigits() | ||
{ | ||
$money = new Money(5, new Currency('XBT')); | ||
|
||
$numberFormatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); | ||
$numberFormatter->setPattern('¤#,##0.00;-¤#,##0.00'); | ||
|
||
$intlFormatter = new IntlMoneyFormatter($numberFormatter); | ||
$formatter = new BitcoinSupportedMoneyFormatter($intlFormatter, 4); | ||
$this->assertEquals("\0xC9\0x830.0005", $formatter->format($money)); | ||
} | ||
|
||
public function testDifferentCurrency() | ||
{ | ||
$money = new Money(5, new Currency('USD')); | ||
|
||
$numberFormatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); | ||
$numberFormatter->setPattern('¤#,##0.00;-¤#,##0.00'); | ||
|
||
$intlFormatter = new IntlMoneyFormatter($numberFormatter); | ||
$formatter = new BitcoinSupportedMoneyFormatter($intlFormatter, 2); | ||
$this->assertEquals('$0.05', $formatter->format($money)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<?php | ||
|
||
namespace Tests\Money\Parser; | ||
|
||
use Money\Parser\BitcoinSupportedMoneyParser; | ||
use Money\Parser\IntlMoneyParser; | ||
|
||
final class BitcoinSupportedMoneyParserTest extends \PHPUnit_Framework_TestCase | ||
{ | ||
public static function provideFormattedMoney() | ||
{ | ||
return [ | ||
["\0xC9\0x831000.00", 100000], | ||
["\0xC9\0x831000.0", 100000], | ||
["\0xC9\0x831000.00", 100000], | ||
["\0xC9\0x830.01", 1], | ||
["\0xC9\0x831", 100], | ||
["-\0xC9\0x831000", -100000], | ||
["-\0xC9\0x831000.0", -100000], | ||
["-\0xC9\0x831000.00", -100000], | ||
["-\0xC9\0x830.01", -1], | ||
["-\0xC9\0x831", -100], | ||
["\0xC9\0x831000", 100000], | ||
["\0xC9\0x831000.0", 100000], | ||
["\0xC9\0x831000.00", 100000], | ||
["\0xC9\0x830.01", 1], | ||
["\0xC9\0x831", 100], | ||
["\0xC9\0x83.99", 99], | ||
["-\0xC9\0x83.99", -99], | ||
["\0xC9\0x830", '0'], | ||
]; | ||
} | ||
|
||
/** | ||
* @dataProvider provideFormattedMoney | ||
*/ | ||
public function testParse($string, $units) | ||
{ | ||
$formatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); | ||
$formatter->setPattern('¤#,##0.00;-¤#,##0.00'); | ||
|
||
$intlParser = new IntlMoneyParser($formatter); | ||
|
||
$parser = new BitcoinSupportedMoneyParser($intlParser, 2); | ||
$this->assertEquals($units, $parser->parse($string, 'USD')->getAmount()); | ||
} | ||
|
||
public function testParseDifferentCurrency() | ||
{ | ||
$formatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); | ||
$formatter->setPattern('¤#,##0.00;-¤#,##0.00'); | ||
|
||
$intlParser = new IntlMoneyParser($formatter); | ||
|
||
$parser = new BitcoinSupportedMoneyParser($intlParser, 2); | ||
$this->assertEquals('100000', $parser->parse('$1000.00', 'USD')->getAmount()); | ||
} | ||
|
||
public function testForceCurrency() | ||
{ | ||
$formatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); | ||
$formatter->setPattern('¤#,##0.00;-¤#,##0.00'); | ||
|
||
$intlParser = new IntlMoneyParser($formatter); | ||
$parser = new BitcoinSupportedMoneyParser($intlParser, 2); | ||
$parsed = $parser->parse('$1000.00', 'XBT'); | ||
|
||
$this->assertEquals('100000', $parsed->getAmount()); | ||
$this->assertEquals('XBT', $parsed->getCurrency()->getCode()); | ||
} | ||
} |