Skip to content

Commit

Permalink
support for bitcoin parsing and formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
frederikbosch committed Feb 17, 2016
1 parent d5bb47f commit 40dd2c7
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 0 deletions.
73 changes: 73 additions & 0 deletions src/Formatter/BitcoinSupportedMoneyFormatter.php
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;
}
}
64 changes: 64 additions & 0 deletions src/Parser/BitcoinSupportedMoneyParser.php
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));
}
}
83 changes: 83 additions & 0 deletions tests/Formatter/BitcoinSupportedMoneyFormatterTest.php
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));
}
}
71 changes: 71 additions & 0 deletions tests/Parser/BitcoinSupportedMoneyParserTest.php
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());
}
}

0 comments on commit 40dd2c7

Please sign in to comment.