Passed
Push — master ( 365cfc...8e997c )
by Mr
04:36
created

BitcoinMoneyParser::parse()   B

Complexity

Conditions 9
Paths 11

Size

Total Lines 41
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
cc 9
eloc 25
nc 11
nop 2
dl 0
loc 41
ccs 0
cts 33
cp 0
crap 90
rs 8.0555
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
/**
3
 * This file is part of the ngutech/bitcoin-interop project.
4
 *
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
9
namespace NGUtech\Bitcoin\Service;
10
11
use Money\Currencies;
12
use Money\Currency;
13
use Money\Exception\ParserException;
14
use Money\Money;
15
use Money\MoneyParser;
16
17
final class BitcoinMoneyParser implements MoneyParser
18
{
19
    private Currencies $currencies;
20
21
    public function __construct(Currencies $currencies)
22
    {
23
        $this->currencies = $currencies;
24
    }
25
26
    /** @param null|Currency $forceCurrency */
27
    public function parse($money, $forceCurrency = null)
28
    {
29
        if (is_string($money) === false) {
30
            throw new ParserException('Formatted raw money should be string, e.g. ₿0.1');
31
        }
32
33
        $regex = '/^(?<amount>-?(?<symbol>[₿฿Ƀ])?\d+(?:\.\d+)?)\s?(?<currency>BTC|XBT)?$/u';
34
        if (!preg_match($regex, $money, $matches)) {
35
            throw new ParserException('Value cannot be parsed as Bitcoin.');
36
        }
37
38
        if (!isset($matches['symbol']) && !isset($matches['currency'])) {
39
            throw new ParserException('Value currency cannot be parsed as Bitcoin.');
40
        }
41
42
        $currency = $forceCurrency ?: new Currency($matches['currency'] ?? BitcoinCurrencies::BTC);
43
44
        $amount = preg_replace('/[₿฿Ƀ]/u', '', $matches['amount']);
45
        $subunit = $this->currencies->subunitFor($currency);
46
        $decimalSeparator = strpos($amount, '.');
47
48
        if (false !== $decimalSeparator) {
49
            $amount = rtrim($amount, '0');
50
            $lengthAmount = strlen($amount);
51
            $amount = str_replace('.', '', $amount);
52
            $amount .= str_pad('', ($lengthAmount - $decimalSeparator - $subunit - 1) * -1, '0');
53
        } else {
54
            $amount .= str_pad('', $subunit, '0');
55
        }
56
57
        if (substr($amount, 0, 1) === '-') {
58
            $amount = '-'.ltrim(substr($amount, 1), '0');
59
        } else {
60
            $amount = ltrim($amount, '0');
61
        }
62
63
        if ('' === $amount) {
64
            $amount = '0';
65
        }
66
67
        return new Money($amount, $currency);
68
    }
69
}
70