File manager - Edit - /home/premiey/www/wp-includes/images/media/money.tar
Back
README.md 0000666 00000007232 15165570755 0006053 0 ustar 00 # Money [](https://github.com/moneyphp/money/releases)  [](https://packagist.org/packages/moneyphp/money) [](mailto:team@moneyphp.org)  PHP library to make working with money safer, easier, and fun! > "If I had a dime for every time I've seen someone use FLOAT to store currency, I'd have $999.997634" -- [Bill Karwin](https://twitter.com/billkarwin/status/347561901460447232) In short: You shouldn't represent monetary values by a float. Wherever you need to represent money, use this Money value object. Since version 3.0 this library uses [strings internally](https://github.com/moneyphp/money/pull/136) in order to support unlimited integers. ```php <?php use Money\Money; $fiveEur = Money::EUR(500); $tenEur = $fiveEur->add($fiveEur); list($part1, $part2, $part3) = $tenEur->allocate([1, 1, 1]); assert($part1->equals(Money::EUR(334))); assert($part2->equals(Money::EUR(333))); assert($part3->equals(Money::EUR(333))); ``` The documentation is available at http://moneyphp.org ## Requirements PHP 5.6+. Other than that, this library has no external requirements. MoneyPHP will not provide any support to PHP versions that are [not supported by the language itself](http://php.net/supported-versions.php). There might be additional dependencies for specific feature, e.g. the Swap exchange implementation, check the documentation for more information. ## Install Via Composer ```bash $ composer require moneyphp/money ``` ## Features - JSON Serialization - Big integer support utilizing different, transparent calculation logic upon availability (bcmath, gmp, plain php) - Money formatting (including intl formatter) - Currency repositories (ISO currencies included) - Money exchange (including [Swap](http://swap.voutzinos.org) implementation) ## Documentation Please see the [official documentation](http://moneyphp.org). ## Testing We try to follow BDD and TDD, as such we use both [phpspec](http://www.phpspec.net) and [phpunit](https://phpunit.de) to test this library. ```bash $ composer test ``` ### Running the tests in Docker Money requires a set of dependencies, so you might want to run it in Docker. First, build the image locally: ```bash $ docker build -t moneyphp . ``` Then run the tests: ```bash $ docker run --rm -it -v $PWD:/app -w /app moneyphp vendor/bin/phpunit --exclude-group segmentation ``` ## Contributing We would love to see you helping us to make this library better and better. Please keep in mind we do not use suffixes and prefixes in class names, so not `CurrenciesInterface`, but `Currencies`. Other than that, Style CI will help you using the same code style as we are using. Please provide tests when creating a PR and clear descriptions of bugs when filing issues. ## Security If you discover any security related issues, please contact us at [team@moneyphp.org](mailto:team@moneyphp.org). ## License The MIT License (MIT). Please see [License File](LICENSE) for more information. ## Acknowledgements This library is heavily inspired by [Martin Fowler's Money pattern](http://martinfowler.com/eaaCatalog/money.html). A special remark goes to [Mathias Verraes](https://github.com/mathiasverraes), without his contributions, in code and via his [blog](http://verraes.net/#blog), this library would not be where it stands now. src/MoneyFactory.php 0000666 00000021710 15165570755 0010510 0 ustar 00 <?php namespace Money; /** * This is a generated file. Do not edit it manually! * * @method static Money AED(string|int $amount) * @method static Money ALL(string|int $amount) * @method static Money AMD(string|int $amount) * @method static Money ANG(string|int $amount) * @method static Money AOA(string|int $amount) * @method static Money ARS(string|int $amount) * @method static Money AUD(string|int $amount) * @method static Money AWG(string|int $amount) * @method static Money AZN(string|int $amount) * @method static Money BAM(string|int $amount) * @method static Money BBD(string|int $amount) * @method static Money BDT(string|int $amount) * @method static Money BGN(string|int $amount) * @method static Money BHD(string|int $amount) * @method static Money BIF(string|int $amount) * @method static Money BMD(string|int $amount) * @method static Money BND(string|int $amount) * @method static Money BOB(string|int $amount) * @method static Money BOV(string|int $amount) * @method static Money BRL(string|int $amount) * @method static Money BSD(string|int $amount) * @method static Money BTN(string|int $amount) * @method static Money BWP(string|int $amount) * @method static Money BYN(string|int $amount) * @method static Money BZD(string|int $amount) * @method static Money CAD(string|int $amount) * @method static Money CDF(string|int $amount) * @method static Money CHE(string|int $amount) * @method static Money CHF(string|int $amount) * @method static Money CHW(string|int $amount) * @method static Money CLF(string|int $amount) * @method static Money CLP(string|int $amount) * @method static Money CNY(string|int $amount) * @method static Money COP(string|int $amount) * @method static Money COU(string|int $amount) * @method static Money CRC(string|int $amount) * @method static Money CUC(string|int $amount) * @method static Money CUP(string|int $amount) * @method static Money CVE(string|int $amount) * @method static Money CZK(string|int $amount) * @method static Money DJF(string|int $amount) * @method static Money DKK(string|int $amount) * @method static Money DOP(string|int $amount) * @method static Money DZD(string|int $amount) * @method static Money EGP(string|int $amount) * @method static Money ERN(string|int $amount) * @method static Money ETB(string|int $amount) * @method static Money EUR(string|int $amount) * @method static Money FJD(string|int $amount) * @method static Money FKP(string|int $amount) * @method static Money GBP(string|int $amount) * @method static Money GEL(string|int $amount) * @method static Money GHS(string|int $amount) * @method static Money GIP(string|int $amount) * @method static Money GMD(string|int $amount) * @method static Money GNF(string|int $amount) * @method static Money GTQ(string|int $amount) * @method static Money GYD(string|int $amount) * @method static Money HKD(string|int $amount) * @method static Money HNL(string|int $amount) * @method static Money HRK(string|int $amount) * @method static Money HTG(string|int $amount) * @method static Money HUF(string|int $amount) * @method static Money IDR(string|int $amount) * @method static Money ILS(string|int $amount) * @method static Money INR(string|int $amount) * @method static Money IQD(string|int $amount) * @method static Money IRR(string|int $amount) * @method static Money ISK(string|int $amount) * @method static Money JMD(string|int $amount) * @method static Money JOD(string|int $amount) * @method static Money JPY(string|int $amount) * @method static Money KES(string|int $amount) * @method static Money KGS(string|int $amount) * @method static Money KHR(string|int $amount) * @method static Money KMF(string|int $amount) * @method static Money KPW(string|int $amount) * @method static Money KRW(string|int $amount) * @method static Money KWD(string|int $amount) * @method static Money KYD(string|int $amount) * @method static Money KZT(string|int $amount) * @method static Money LAK(string|int $amount) * @method static Money LBP(string|int $amount) * @method static Money LKR(string|int $amount) * @method static Money LRD(string|int $amount) * @method static Money LSL(string|int $amount) * @method static Money LYD(string|int $amount) * @method static Money MAD(string|int $amount) * @method static Money MDL(string|int $amount) * @method static Money MGA(string|int $amount) * @method static Money MKD(string|int $amount) * @method static Money MMK(string|int $amount) * @method static Money MNT(string|int $amount) * @method static Money MOP(string|int $amount) * @method static Money MRU(string|int $amount) * @method static Money MUR(string|int $amount) * @method static Money MVR(string|int $amount) * @method static Money MWK(string|int $amount) * @method static Money MXN(string|int $amount) * @method static Money MXV(string|int $amount) * @method static Money MYR(string|int $amount) * @method static Money MZN(string|int $amount) * @method static Money NAD(string|int $amount) * @method static Money NGN(string|int $amount) * @method static Money NIO(string|int $amount) * @method static Money NOK(string|int $amount) * @method static Money NPR(string|int $amount) * @method static Money NZD(string|int $amount) * @method static Money OMR(string|int $amount) * @method static Money PAB(string|int $amount) * @method static Money PEN(string|int $amount) * @method static Money PGK(string|int $amount) * @method static Money PHP(string|int $amount) * @method static Money PKR(string|int $amount) * @method static Money PLN(string|int $amount) * @method static Money PYG(string|int $amount) * @method static Money QAR(string|int $amount) * @method static Money RON(string|int $amount) * @method static Money RSD(string|int $amount) * @method static Money RUB(string|int $amount) * @method static Money RWF(string|int $amount) * @method static Money SAR(string|int $amount) * @method static Money SBD(string|int $amount) * @method static Money SCR(string|int $amount) * @method static Money SDG(string|int $amount) * @method static Money SEK(string|int $amount) * @method static Money SGD(string|int $amount) * @method static Money SHP(string|int $amount) * @method static Money SLL(string|int $amount) * @method static Money SOS(string|int $amount) * @method static Money SRD(string|int $amount) * @method static Money SSP(string|int $amount) * @method static Money STN(string|int $amount) * @method static Money SVC(string|int $amount) * @method static Money SYP(string|int $amount) * @method static Money SZL(string|int $amount) * @method static Money THB(string|int $amount) * @method static Money TJS(string|int $amount) * @method static Money TMT(string|int $amount) * @method static Money TND(string|int $amount) * @method static Money TOP(string|int $amount) * @method static Money TRY(string|int $amount) * @method static Money TTD(string|int $amount) * @method static Money TWD(string|int $amount) * @method static Money TZS(string|int $amount) * @method static Money UAH(string|int $amount) * @method static Money UGX(string|int $amount) * @method static Money USD(string|int $amount) * @method static Money USN(string|int $amount) * @method static Money UYI(string|int $amount) * @method static Money UYU(string|int $amount) * @method static Money UYW(string|int $amount) * @method static Money UZS(string|int $amount) * @method static Money VES(string|int $amount) * @method static Money VND(string|int $amount) * @method static Money VUV(string|int $amount) * @method static Money WST(string|int $amount) * @method static Money XAF(string|int $amount) * @method static Money XAG(string|int $amount) * @method static Money XAU(string|int $amount) * @method static Money XBA(string|int $amount) * @method static Money XBB(string|int $amount) * @method static Money XBC(string|int $amount) * @method static Money XBD(string|int $amount) * @method static Money XBT(string|int $amount) * @method static Money XCD(string|int $amount) * @method static Money XDR(string|int $amount) * @method static Money XOF(string|int $amount) * @method static Money XPD(string|int $amount) * @method static Money XPF(string|int $amount) * @method static Money XPT(string|int $amount) * @method static Money XSU(string|int $amount) * @method static Money XTS(string|int $amount) * @method static Money XUA(string|int $amount) * @method static Money XXX(string|int $amount) * @method static Money YER(string|int $amount) * @method static Money ZAR(string|int $amount) * @method static Money ZMW(string|int $amount) * @method static Money ZWL(string|int $amount) */ trait MoneyFactory { /** * Convenience factory method for a Money object. * * <code> * $fiveDollar = Money::USD(500); * </code> * * @param string $method * @param array $arguments * * @return Money * * @throws \InvalidArgumentException If amount is not integer(ish) */ public static function __callStatic($method, $arguments) { return new Money($arguments[0], new Currency($method)); } } src/Calculator/PhpCalculator.php 0000666 00000010421 15165570755 0012720 0 ustar 00 <?php namespace Money\Calculator; use Money\Calculator; use Money\Money; use Money\Number; /** * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class PhpCalculator implements Calculator { /** * {@inheritdoc} */ public static function supported() { return true; } /** * {@inheritdoc} */ public function compare($a, $b) { return ($a < $b) ? -1 : (($a > $b) ? 1 : 0); } /** * {@inheritdoc} */ public function add($amount, $addend) { $result = $amount + $addend; $this->assertInteger($result); return (string) $result; } /** * {@inheritdoc} */ public function subtract($amount, $subtrahend) { $result = $amount - $subtrahend; $this->assertInteger($result); return (string) $result; } /** * {@inheritdoc} */ public function multiply($amount, $multiplier) { $result = $amount * $multiplier; $this->assertIntegerBounds($result); return (string) Number::fromNumber($result); } /** * {@inheritdoc} */ public function divide($amount, $divisor) { $result = $amount / $divisor; $this->assertIntegerBounds($result); return (string) Number::fromNumber($result); } /** * {@inheritdoc} */ public function ceil($number) { return $this->castInteger(ceil($number)); } /** * {@inheritdoc} */ public function floor($number) { return $this->castInteger(floor($number)); } /** * {@inheritdoc} */ public function absolute($number) { $result = ltrim($number, '-'); $this->assertIntegerBounds($result); return (string) $result; } /** * {@inheritdoc} */ public function round($number, $roundingMode) { if (Money::ROUND_HALF_POSITIVE_INFINITY === $roundingMode) { $number = Number::fromNumber($number); if ($number->isHalf()) { return $this->castInteger(ceil((string) $number)); } return $this->castInteger(round((string) $number, 0, Money::ROUND_HALF_UP)); } if (Money::ROUND_HALF_NEGATIVE_INFINITY === $roundingMode) { $number = Number::fromNumber($number); if ($number->isHalf()) { return $this->castInteger(floor((string) $number)); } return $this->castInteger(round((string) $number, 0, Money::ROUND_HALF_DOWN)); } return $this->castInteger(round($number, 0, $roundingMode)); } /** * {@inheritdoc} */ public function share($amount, $ratio, $total) { return $this->castInteger(floor($amount * $ratio / $total)); } /** * {@inheritdoc} */ public function mod($amount, $divisor) { $result = $amount % $divisor; $this->assertIntegerBounds($result); return (string) $result; } /** * Asserts that an integer value didn't become something else * (after some arithmetic operation). * * @param int $amount * * @throws \OverflowException If integer overflow occured * @throws \UnderflowException If integer underflow occured */ private function assertIntegerBounds($amount) { if ($amount > PHP_INT_MAX) { throw new \OverflowException('You overflowed the maximum allowed integer (PHP_INT_MAX)'); } elseif ($amount < ~PHP_INT_MAX) { throw new \UnderflowException('You underflowed the minimum allowed integer (PHP_INT_MAX)'); } } /** * Casts an amount to integer ensuring that an overflow/underflow did not occur. * * @param int $amount * * @return string */ private function castInteger($amount) { $this->assertIntegerBounds($amount); return (string) intval($amount); } /** * Asserts that integer remains integer after arithmetic operations. * * @param int $amount */ private function assertInteger($amount) { if (filter_var($amount, FILTER_VALIDATE_INT) === false) { throw new \UnexpectedValueException('The result of arithmetic operation is not an integer'); } } } src/Calculator/BcMathCalculator.php 0000666 00000012220 15165570755 0013326 0 ustar 00 <?php namespace Money\Calculator; use Money\Calculator; use Money\Money; use Money\Number; /** * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class BcMathCalculator implements Calculator { /** * @var string */ private $scale; /** * @param int $scale */ public function __construct($scale = 14) { $this->scale = $scale; } /** * {@inheritdoc} */ public static function supported() { return extension_loaded('bcmath'); } /** * {@inheritdoc} */ public function compare($a, $b) { return bccomp($a, $b, $this->scale); } /** * {@inheritdoc} */ public function add($amount, $addend) { return (string) Number::fromString(bcadd($amount, $addend, $this->scale)); } /** * {@inheritdoc} * * @param $amount * @param $subtrahend * * @return string */ public function subtract($amount, $subtrahend) { return (string) Number::fromString(bcsub($amount, $subtrahend, $this->scale)); } /** * {@inheritdoc} */ public function multiply($amount, $multiplier) { $multiplier = Number::fromNumber($multiplier); return bcmul($amount, (string) $multiplier, $this->scale); } /** * {@inheritdoc} */ public function divide($amount, $divisor) { $divisor = Number::fromNumber($divisor); return bcdiv($amount, (string) $divisor, $this->scale); } /** * {@inheritdoc} */ public function ceil($number) { $number = Number::fromNumber($number); if ($number->isInteger()) { return (string) $number; } if ($number->isNegative()) { return bcadd((string) $number, '0', 0); } return bcadd((string) $number, '1', 0); } /** * {@inheritdoc} */ public function floor($number) { $number = Number::fromNumber($number); if ($number->isInteger()) { return (string) $number; } if ($number->isNegative()) { return bcadd((string) $number, '-1', 0); } return bcadd($number, '0', 0); } /** * {@inheritdoc} */ public function absolute($number) { return ltrim($number, '-'); } /** * {@inheritdoc} */ public function round($number, $roundingMode) { $number = Number::fromNumber($number); if ($number->isInteger()) { return (string) $number; } if ($number->isHalf() === false) { return $this->roundDigit($number); } if (Money::ROUND_HALF_UP === $roundingMode) { return bcadd( (string) $number, $number->getIntegerRoundingMultiplier(), 0 ); } if (Money::ROUND_HALF_DOWN === $roundingMode) { return bcadd((string) $number, '0', 0); } if (Money::ROUND_HALF_EVEN === $roundingMode) { if ($number->isCurrentEven()) { return bcadd((string) $number, '0', 0); } return bcadd( (string) $number, $number->getIntegerRoundingMultiplier(), 0 ); } if (Money::ROUND_HALF_ODD === $roundingMode) { if ($number->isCurrentEven()) { return bcadd( (string) $number, $number->getIntegerRoundingMultiplier(), 0 ); } return bcadd((string) $number, '0', 0); } if (Money::ROUND_HALF_POSITIVE_INFINITY === $roundingMode) { if ($number->isNegative()) { return bcadd((string) $number, '0', 0); } return bcadd( (string) $number, $number->getIntegerRoundingMultiplier(), 0 ); } if (Money::ROUND_HALF_NEGATIVE_INFINITY === $roundingMode) { if ($number->isNegative()) { return bcadd( (string) $number, $number->getIntegerRoundingMultiplier(), 0 ); } return bcadd( (string) $number, '0', 0 ); } throw new \InvalidArgumentException('Unknown rounding mode'); } /** * @param $number * * @return string */ private function roundDigit(Number $number) { if ($number->isCloserToNext()) { return bcadd( (string) $number, $number->getIntegerRoundingMultiplier(), 0 ); } return bcadd((string) $number, '0', 0); } /** * {@inheritdoc} */ public function share($amount, $ratio, $total) { return $this->floor(bcdiv(bcmul($amount, $ratio, $this->scale), $total, $this->scale)); } /** * {@inheritdoc} */ public function mod($amount, $divisor) { return bcmod($amount, $divisor); } } src/Calculator/GmpCalculator.php 0000666 00000020347 15165570755 0012724 0 ustar 00 <?php namespace Money\Calculator; use Money\Calculator; use Money\Money; use Money\Number; /** * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class GmpCalculator implements Calculator { /** * @var string */ private $scale; /** * @param int $scale */ public function __construct($scale = 14) { $this->scale = $scale; } /** * {@inheritdoc} */ public static function supported() { return extension_loaded('gmp'); } /** * {@inheritdoc} */ public function compare($a, $b) { $aNum = Number::fromNumber($a); $bNum = Number::fromNumber($b); if ($aNum->isDecimal() || $bNum->isDecimal()) { $integersCompared = gmp_cmp($aNum->getIntegerPart(), $bNum->getIntegerPart()); if ($integersCompared !== 0) { return $integersCompared; } $aNumFractional = $aNum->getFractionalPart() === '' ? '0' : $aNum->getFractionalPart(); $bNumFractional = $bNum->getFractionalPart() === '' ? '0' : $bNum->getFractionalPart(); return gmp_cmp($aNumFractional, $bNumFractional); } return gmp_cmp($a, $b); } /** * {@inheritdoc} */ public function add($amount, $addend) { return gmp_strval(gmp_add($amount, $addend)); } /** * {@inheritdoc} */ public function subtract($amount, $subtrahend) { return gmp_strval(gmp_sub($amount, $subtrahend)); } /** * {@inheritdoc} */ public function multiply($amount, $multiplier) { $multiplier = Number::fromNumber($multiplier); if ($multiplier->isDecimal()) { $decimalPlaces = strlen($multiplier->getFractionalPart()); $multiplierBase = $multiplier->getIntegerPart(); if ($multiplierBase) { $multiplierBase .= $multiplier->getFractionalPart(); } else { $multiplierBase = ltrim($multiplier->getFractionalPart(), '0'); } $resultBase = gmp_strval(gmp_mul(gmp_init($amount), gmp_init($multiplierBase))); if ('0' === $resultBase) { return '0'; } $result = substr($resultBase, $decimalPlaces * -1); $resultLength = strlen($result); if ($decimalPlaces > $resultLength) { return '0.'.str_pad('', $decimalPlaces - $resultLength, '0').$result; } return substr($resultBase, 0, $decimalPlaces * -1).'.'.$result; } return gmp_strval(gmp_mul(gmp_init($amount), gmp_init((string) $multiplier))); } /** * {@inheritdoc} */ public function divide($amount, $divisor) { $divisor = Number::fromNumber($divisor); if ($divisor->isDecimal()) { $decimalPlaces = strlen($divisor->getFractionalPart()); if ($divisor->getIntegerPart()) { $divisor = new Number($divisor->getIntegerPart().$divisor->getFractionalPart()); } else { $divisor = new Number(ltrim($divisor->getFractionalPart(), '0')); } $amount = gmp_strval(gmp_mul(gmp_init($amount), gmp_init('1'.str_pad('', $decimalPlaces, '0')))); } list($integer, $remainder) = gmp_div_qr(gmp_init($amount), gmp_init((string) $divisor)); if (gmp_cmp($remainder, '0') === 0) { return gmp_strval($integer); } $divisionOfRemainder = gmp_strval( gmp_div_q( gmp_mul($remainder, gmp_init('1'.str_pad('', $this->scale, '0'))), gmp_init((string) $divisor), GMP_ROUND_MINUSINF ) ); if ($divisionOfRemainder[0] === '-') { $divisionOfRemainder = substr($divisionOfRemainder, 1); } return gmp_strval($integer).'.'.str_pad($divisionOfRemainder, $this->scale, '0', STR_PAD_LEFT); } /** * {@inheritdoc} */ public function ceil($number) { $number = Number::fromNumber($number); if ($number->isInteger()) { return (string) $number; } if ($number->isNegative()) { return $this->add($number->getIntegerPart(), '0'); } return $this->add($number->getIntegerPart(), '1'); } /** * {@inheritdoc} */ public function floor($number) { $number = Number::fromNumber($number); if ($number->isInteger()) { return (string) $number; } if ($number->isNegative()) { return $this->add($number->getIntegerPart(), '-1'); } return $this->add($number->getIntegerPart(), '0'); } /** * {@inheritdoc} */ public function absolute($number) { return ltrim($number, '-'); } /** * {@inheritdoc} */ public function round($number, $roundingMode) { $number = Number::fromNumber($number); if ($number->isInteger()) { return (string) $number; } if ($number->isHalf() === false) { return $this->roundDigit($number); } if (Money::ROUND_HALF_UP === $roundingMode) { return $this->add( $number->getIntegerPart(), $number->getIntegerRoundingMultiplier() ); } if (Money::ROUND_HALF_DOWN === $roundingMode) { return $this->add($number->getIntegerPart(), '0'); } if (Money::ROUND_HALF_EVEN === $roundingMode) { if ($number->isCurrentEven()) { return $this->add($number->getIntegerPart(), '0'); } return $this->add( $number->getIntegerPart(), $number->getIntegerRoundingMultiplier() ); } if (Money::ROUND_HALF_ODD === $roundingMode) { if ($number->isCurrentEven()) { return $this->add( $number->getIntegerPart(), $number->getIntegerRoundingMultiplier() ); } return $this->add($number->getIntegerPart(), '0'); } if (Money::ROUND_HALF_POSITIVE_INFINITY === $roundingMode) { if ($number->isNegative()) { return $this->add( $number->getIntegerPart(), '0' ); } return $this->add( $number->getIntegerPart(), $number->getIntegerRoundingMultiplier() ); } if (Money::ROUND_HALF_NEGATIVE_INFINITY === $roundingMode) { if ($number->isNegative()) { return $this->add( $number->getIntegerPart(), $number->getIntegerRoundingMultiplier() ); } return $this->add( $number->getIntegerPart(), '0' ); } throw new \InvalidArgumentException('Unknown rounding mode'); } /** * @param $number * * @return string */ private function roundDigit(Number $number) { if ($number->isCloserToNext()) { return $this->add( $number->getIntegerPart(), $number->getIntegerRoundingMultiplier() ); } return $this->add($number->getIntegerPart(), '0'); } /** * {@inheritdoc} */ public function share($amount, $ratio, $total) { return $this->floor($this->divide($this->multiply($amount, $ratio), $total)); } /** * {@inheritdoc} */ public function mod($amount, $divisor) { // gmp_mod() only calculates non-negative integers, so we use absolutes $remainder = gmp_mod($this->absolute($amount), $this->absolute($divisor)); // If the amount was negative, we negate the result of the modulus operation $amount = Number::fromNumber($amount); if ($amount->isNegative()) { $remainder = gmp_neg($remainder); } return gmp_strval($remainder); } /** * @test */ public function it_divides_bug538() { $this->assertSame('-4.54545454545455', $this->getCalculator()->divide('-500', 110)); } } src/Money.php 0000666 00000037202 15165570755 0007163 0 ustar 00 <?php namespace Money; use Money\Calculator\BcMathCalculator; use Money\Calculator\GmpCalculator; use Money\Calculator\PhpCalculator; /** * Money Value Object. * * @author Mathias Verraes * * @psalm-immutable */ final class Money implements \JsonSerializable { use MoneyFactory; const ROUND_HALF_UP = PHP_ROUND_HALF_UP; const ROUND_HALF_DOWN = PHP_ROUND_HALF_DOWN; const ROUND_HALF_EVEN = PHP_ROUND_HALF_EVEN; const ROUND_HALF_ODD = PHP_ROUND_HALF_ODD; const ROUND_UP = 5; const ROUND_DOWN = 6; const ROUND_HALF_POSITIVE_INFINITY = 7; const ROUND_HALF_NEGATIVE_INFINITY = 8; /** * Internal value. * * @var string */ private $amount; /** * @var Currency */ private $currency; /** * @var Calculator */ private static $calculator; /** * @var array */ private static $calculators = [ BcMathCalculator::class, GmpCalculator::class, PhpCalculator::class, ]; /** * @param int|string $amount Amount, expressed in the smallest units of $currency (eg cents) * @param Currency $currency * * @throws \InvalidArgumentException If amount is not integer */ public function __construct($amount, Currency $currency) { if (filter_var($amount, FILTER_VALIDATE_INT) === false) { $numberFromString = Number::fromString($amount); if (!$numberFromString->isInteger()) { throw new \InvalidArgumentException('Amount must be an integer(ish) value'); } $amount = $numberFromString->getIntegerPart(); } $this->amount = (string) $amount; $this->currency = $currency; } /** * Returns a new Money instance based on the current one using the Currency. * * @param int|string $amount * * @return Money * * @throws \InvalidArgumentException If amount is not integer */ private function newInstance($amount) { return new self($amount, $this->currency); } /** * Checks whether a Money has the same Currency as this. * * @param Money $other * * @return bool */ public function isSameCurrency(Money $other) { return $this->currency->equals($other->currency); } /** * Asserts that a Money has the same currency as this. * * @param Money $other * * @throws \InvalidArgumentException If $other has a different currency */ private function assertSameCurrency(Money $other) { if (!$this->isSameCurrency($other)) { throw new \InvalidArgumentException('Currencies must be identical'); } } /** * Checks whether the value represented by this object equals to the other. * * @param Money $other * * @return bool */ public function equals(Money $other) { return $this->isSameCurrency($other) && $this->amount === $other->amount; } /** * Returns an integer less than, equal to, or greater than zero * if the value of this object is considered to be respectively * less than, equal to, or greater than the other. * * @param Money $other * * @return int */ public function compare(Money $other) { $this->assertSameCurrency($other); return $this->getCalculator()->compare($this->amount, $other->amount); } /** * Checks whether the value represented by this object is greater than the other. * * @param Money $other * * @return bool */ public function greaterThan(Money $other) { return $this->compare($other) > 0; } /** * @param \Money\Money $other * * @return bool */ public function greaterThanOrEqual(Money $other) { return $this->compare($other) >= 0; } /** * Checks whether the value represented by this object is less than the other. * * @param Money $other * * @return bool */ public function lessThan(Money $other) { return $this->compare($other) < 0; } /** * @param \Money\Money $other * * @return bool */ public function lessThanOrEqual(Money $other) { return $this->compare($other) <= 0; } /** * Returns the value represented by this object. * * @return string */ public function getAmount() { return $this->amount; } /** * Returns the currency of this object. * * @return Currency */ public function getCurrency() { return $this->currency; } /** * Returns a new Money object that represents * the sum of this and an other Money object. * * @param Money[] $addends * * @return Money */ public function add(Money ...$addends) { $amount = $this->amount; $calculator = $this->getCalculator(); foreach ($addends as $addend) { $this->assertSameCurrency($addend); $amount = $calculator->add($amount, $addend->amount); } return new self($amount, $this->currency); } /** * Returns a new Money object that represents * the difference of this and an other Money object. * * @param Money[] $subtrahends * * @return Money * * @psalm-pure */ public function subtract(Money ...$subtrahends) { $amount = $this->amount; $calculator = $this->getCalculator(); foreach ($subtrahends as $subtrahend) { $this->assertSameCurrency($subtrahend); $amount = $calculator->subtract($amount, $subtrahend->amount); } return new self($amount, $this->currency); } /** * Asserts that the operand is integer or float. * * @param float|int|string $operand * * @throws \InvalidArgumentException If $operand is neither integer nor float */ private function assertOperand($operand) { if (!is_numeric($operand)) { throw new \InvalidArgumentException(sprintf( 'Operand should be a numeric value, "%s" given.', is_object($operand) ? get_class($operand) : gettype($operand) )); } } /** * Asserts that rounding mode is a valid integer value. * * @param int $roundingMode * * @throws \InvalidArgumentException If $roundingMode is not valid */ private function assertRoundingMode($roundingMode) { if (!in_array( $roundingMode, [ self::ROUND_HALF_DOWN, self::ROUND_HALF_EVEN, self::ROUND_HALF_ODD, self::ROUND_HALF_UP, self::ROUND_UP, self::ROUND_DOWN, self::ROUND_HALF_POSITIVE_INFINITY, self::ROUND_HALF_NEGATIVE_INFINITY, ], true )) { throw new \InvalidArgumentException( 'Rounding mode should be Money::ROUND_HALF_DOWN | '. 'Money::ROUND_HALF_EVEN | Money::ROUND_HALF_ODD | '. 'Money::ROUND_HALF_UP | Money::ROUND_UP | Money::ROUND_DOWN'. 'Money::ROUND_HALF_POSITIVE_INFINITY | Money::ROUND_HALF_NEGATIVE_INFINITY' ); } } /** * Returns a new Money object that represents * the multiplied value by the given factor. * * @param float|int|string $multiplier * @param int $roundingMode * * @return Money */ public function multiply($multiplier, $roundingMode = self::ROUND_HALF_UP) { $this->assertOperand($multiplier); $this->assertRoundingMode($roundingMode); $product = $this->round($this->getCalculator()->multiply($this->amount, $multiplier), $roundingMode); return $this->newInstance($product); } /** * Returns a new Money object that represents * the divided value by the given factor. * * @param float|int|string $divisor * @param int $roundingMode * * @return Money */ public function divide($divisor, $roundingMode = self::ROUND_HALF_UP) { $this->assertOperand($divisor); $this->assertRoundingMode($roundingMode); $divisor = (string) Number::fromNumber($divisor); if ($this->getCalculator()->compare($divisor, '0') === 0) { throw new \InvalidArgumentException('Division by zero'); } $quotient = $this->round($this->getCalculator()->divide($this->amount, $divisor), $roundingMode); return $this->newInstance($quotient); } /** * Returns a new Money object that represents * the remainder after dividing the value by * the given factor. * * @param Money $divisor * * @return Money */ public function mod(Money $divisor) { $this->assertSameCurrency($divisor); return new self($this->getCalculator()->mod($this->amount, $divisor->amount), $this->currency); } /** * Allocate the money according to a list of ratios. * * @param array $ratios * * @return Money[] */ public function allocate(array $ratios) { if (count($ratios) === 0) { throw new \InvalidArgumentException('Cannot allocate to none, ratios cannot be an empty array'); } $remainder = $this->amount; $results = []; $total = array_sum($ratios); if ($total <= 0) { throw new \InvalidArgumentException('Cannot allocate to none, sum of ratios must be greater than zero'); } foreach ($ratios as $key => $ratio) { if ($ratio < 0) { throw new \InvalidArgumentException('Cannot allocate to none, ratio must be zero or positive'); } $share = $this->getCalculator()->share($this->amount, $ratio, $total); $results[$key] = $this->newInstance($share); $remainder = $this->getCalculator()->subtract($remainder, $share); } if ($this->getCalculator()->compare($remainder, '0') === 0) { return $results; } $fractions = array_map(function ($ratio) use ($total) { $share = ($ratio / $total) * $this->amount; return $share - floor($share); }, $ratios); while ($this->getCalculator()->compare($remainder, '0') > 0) { $index = !empty($fractions) ? array_keys($fractions, max($fractions))[0] : 0; $results[$index]->amount = $this->getCalculator()->add($results[$index]->amount, '1'); $remainder = $this->getCalculator()->subtract($remainder, '1'); unset($fractions[$index]); } return $results; } /** * Allocate the money among N targets. * * @param int $n * * @return Money[] * * @throws \InvalidArgumentException If number of targets is not an integer */ public function allocateTo($n) { if (!is_int($n)) { throw new \InvalidArgumentException('Number of targets must be an integer'); } if ($n <= 0) { throw new \InvalidArgumentException('Cannot allocate to none, target must be greater than zero'); } return $this->allocate(array_fill(0, $n, 1)); } /** * @param Money $money * * @return string */ public function ratioOf(Money $money) { if ($money->isZero()) { throw new \InvalidArgumentException('Cannot calculate a ratio of zero'); } return $this->getCalculator()->divide($this->amount, $money->amount); } /** * @param string $amount * @param int $rounding_mode * * @return string */ private function round($amount, $rounding_mode) { $this->assertRoundingMode($rounding_mode); if ($rounding_mode === self::ROUND_UP) { return $this->getCalculator()->ceil($amount); } if ($rounding_mode === self::ROUND_DOWN) { return $this->getCalculator()->floor($amount); } return $this->getCalculator()->round($amount, $rounding_mode); } /** * @return Money */ public function absolute() { return $this->newInstance($this->getCalculator()->absolute($this->amount)); } /** * @return Money */ public function negative() { return $this->newInstance(0)->subtract($this); } /** * Checks if the value represented by this object is zero. * * @return bool */ public function isZero() { return $this->getCalculator()->compare($this->amount, 0) === 0; } /** * Checks if the value represented by this object is positive. * * @return bool */ public function isPositive() { return $this->getCalculator()->compare($this->amount, 0) > 0; } /** * Checks if the value represented by this object is negative. * * @return bool */ public function isNegative() { return $this->getCalculator()->compare($this->amount, 0) < 0; } /** * {@inheritdoc} * * @return array */ #[\ReturnTypeWillChange] public function jsonSerialize() { return [ 'amount' => $this->amount, 'currency' => $this->currency->jsonSerialize(), ]; } /** * @param Money $first * @param Money ...$collection * * @return Money * * @psalm-pure */ public static function min(self $first, self ...$collection) { $min = $first; foreach ($collection as $money) { if ($money->lessThan($min)) { $min = $money; } } return $min; } /** * @param Money $first * @param Money ...$collection * * @return Money * * @psalm-pure */ public static function max(self $first, self ...$collection) { $max = $first; foreach ($collection as $money) { if ($money->greaterThan($max)) { $max = $money; } } return $max; } /** * @param Money $first * @param Money ...$collection * * @return Money * * @psalm-pure */ public static function sum(self $first, self ...$collection) { return $first->add(...$collection); } /** * @param Money $first * @param Money ...$collection * * @return Money * * @psalm-pure */ public static function avg(self $first, self ...$collection) { return $first->add(...$collection)->divide(func_num_args()); } /** * @param string $calculator */ public static function registerCalculator($calculator) { if (is_a($calculator, Calculator::class, true) === false) { throw new \InvalidArgumentException('Calculator must implement '.Calculator::class); } array_unshift(self::$calculators, $calculator); } /** * @return Calculator * * @throws \RuntimeException If cannot find calculator for money calculations */ private static function initializeCalculator() { $calculators = self::$calculators; foreach ($calculators as $calculator) { /** @var Calculator $calculator */ if ($calculator::supported()) { return new $calculator(); } } throw new \RuntimeException('Cannot find calculator for money calculations'); } /** * @return Calculator */ private function getCalculator() { if (null === self::$calculator) { self::$calculator = self::initializeCalculator(); } return self::$calculator; } } src/MoneyParser.php 0000666 00000000716 15165570755 0010340 0 ustar 00 <?php namespace Money; /** * Parses a string into a Money object. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ interface MoneyParser { /** * Parses a string into a Money object (including currency). * * @param string $money * @param Currency|string|null $forceCurrency * * @return Money * * @throws Exception\ParserException */ public function parse($money, $forceCurrency = null); } src/MoneyFormatter.php 0000666 00000000526 15165570755 0011046 0 ustar 00 <?php namespace Money; /** * Formats Money objects. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ interface MoneyFormatter { /** * Formats a Money object as string. * * @param Money $money * * @return string * * Exception\FormatterException */ public function format(Money $money); } src/Exception.php 0000666 00000000251 15165570755 0010024 0 ustar 00 <?php namespace Money; /** * Common interface for all exceptions thrown by this library. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ interface Exception { } src/Currencies/ISOCurrencies.php 0000666 00000004471 15165570755 0012655 0 ustar 00 <?php namespace Money\Currencies; use Money\Currencies; use Money\Currency; use Money\Exception\UnknownCurrencyException; /** * List of supported ISO 4217 currency codes and names. * * @author Mathias Verraes */ final class ISOCurrencies implements Currencies { /** * Map of known currencies indexed by code. * * @var array */ private static $currencies; /** * {@inheritdoc} */ public function contains(Currency $currency) { return isset($this->getCurrencies()[$currency->getCode()]); } /** * {@inheritdoc} */ public function subunitFor(Currency $currency) { if (!$this->contains($currency)) { throw new UnknownCurrencyException('Cannot find ISO currency '.$currency->getCode()); } return $this->getCurrencies()[$currency->getCode()]['minorUnit']; } /** * Returns the numeric code for a currency. * * @param Currency $currency * * @return int * * @throws UnknownCurrencyException If currency is not available in the current context */ public function numericCodeFor(Currency $currency) { if (!$this->contains($currency)) { throw new UnknownCurrencyException('Cannot find ISO currency '.$currency->getCode()); } return $this->getCurrencies()[$currency->getCode()]['numericCode']; } /** * @return \Traversable */ #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator( array_map( function ($code) { return new Currency($code); }, array_keys($this->getCurrencies()) ) ); } /** * Returns a map of known currencies indexed by code. * * @return array */ private function getCurrencies() { if (null === self::$currencies) { self::$currencies = $this->loadCurrencies(); } return self::$currencies; } /** * @return array */ private function loadCurrencies() { $file = __DIR__.'/../../resources/currency.php'; if (file_exists($file)) { return require $file; } throw new \RuntimeException('Failed to load currency ISO codes.'); } } src/Currencies/CurrencyList.php 0000666 00000003471 15165570755 0012625 0 ustar 00 <?php namespace Money\Currencies; use Money\Currencies; use Money\Currency; use Money\Exception\UnknownCurrencyException; /** * A list of custom currencies. * * @author George Mponos <gmponos@gmail.com> */ final class CurrencyList implements Currencies { /** * Map of currencies indexed by code. * * @var array */ private $currencies; public function __construct(array $currencies) { foreach ($currencies as $currencyCode => $subunit) { if (empty($currencyCode) || !is_string($currencyCode)) { throw new \InvalidArgumentException( sprintf('Currency code must be a string and not empty. "%s" given', $currencyCode) ); } if (!is_int($subunit) || $subunit < 0) { throw new \InvalidArgumentException( sprintf('Currency %s does not have a valid minor unit. Must be a positive integer.', $currencyCode) ); } } $this->currencies = $currencies; } /** * {@inheritdoc} */ public function contains(Currency $currency) { return isset($this->currencies[$currency->getCode()]); } /** * {@inheritdoc} */ public function subunitFor(Currency $currency) { if (!$this->contains($currency)) { throw new UnknownCurrencyException('Cannot find currency '.$currency->getCode()); } return $this->currencies[$currency->getCode()]; } /** * {@inheritdoc} */ public function getIterator() { return new \ArrayIterator( array_map( function ($code) { return new Currency($code); }, array_keys($this->currencies) ) ); } } src/Currencies/CachedCurrencies.php 0000666 00000004404 15165570755 0013366 0 ustar 00 <?php namespace Money\Currencies; use Cache\Taggable\TaggableItemInterface; use Money\Currencies; use Money\Currency; use Psr\Cache\CacheItemPoolInterface; /** * Cache the result of currency checking. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ final class CachedCurrencies implements Currencies { /** * @var Currencies */ private $currencies; /** * @var CacheItemPoolInterface */ private $pool; /** * @param Currencies $currencies * @param CacheItemPoolInterface $pool */ public function __construct(Currencies $currencies, CacheItemPoolInterface $pool) { $this->currencies = $currencies; $this->pool = $pool; } /** * {@inheritdoc} */ public function contains(Currency $currency) { $item = $this->pool->getItem('currency|availability|'.$currency->getCode()); if (false === $item->isHit()) { $item->set($this->currencies->contains($currency)); if ($item instanceof TaggableItemInterface) { $item->addTag('currency.availability'); } $this->pool->save($item); } return $item->get(); } /** * {@inheritdoc} */ public function subunitFor(Currency $currency) { $item = $this->pool->getItem('currency|subunit|'.$currency->getCode()); if (false === $item->isHit()) { $item->set($this->currencies->subunitFor($currency)); if ($item instanceof TaggableItemInterface) { $item->addTag('currency.subunit'); } $this->pool->save($item); } return $item->get(); } /** * {@inheritdoc} */ public function getIterator() { return new \CallbackFilterIterator( $this->currencies->getIterator(), function (Currency $currency) { $item = $this->pool->getItem('currency|availability|'.$currency->getCode()); $item->set(true); if ($item instanceof TaggableItemInterface) { $item->addTag('currency.availability'); } $this->pool->save($item); return true; } ); } } src/Currencies/AggregateCurrencies.php 0000666 00000003234 15165570755 0014105 0 ustar 00 <?php namespace Money\Currencies; use Money\Currencies; use Money\Currency; use Money\Exception\UnknownCurrencyException; /** * Aggregates several currency repositories. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ final class AggregateCurrencies implements Currencies { /** * @var Currencies[] */ private $currencies; /** * @param Currencies[] $currencies */ public function __construct(array $currencies) { foreach ($currencies as $c) { if (false === $c instanceof Currencies) { throw new \InvalidArgumentException('All currency repositories must implement '.Currencies::class); } } $this->currencies = $currencies; } /** * {@inheritdoc} */ public function contains(Currency $currency) { foreach ($this->currencies as $currencies) { if ($currencies->contains($currency)) { return true; } } return false; } /** * {@inheritdoc} */ public function subunitFor(Currency $currency) { foreach ($this->currencies as $currencies) { if ($currencies->contains($currency)) { return $currencies->subunitFor($currency); } } throw new UnknownCurrencyException('Cannot find currency '.$currency->getCode()); } /** * {@inheritdoc} */ public function getIterator() { $iterator = new \AppendIterator(); foreach ($this->currencies as $currencies) { $iterator->append($currencies->getIterator()); } return $iterator; } } src/Currencies/BitcoinCurrencies.php 0000666 00000001651 15165570755 0013607 0 ustar 00 <?php namespace Money\Currencies; use Money\Currencies; use Money\Currency; use Money\Exception\UnknownCurrencyException; /** * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class BitcoinCurrencies implements Currencies { const CODE = 'XBT'; const SYMBOL = "\xC9\x83"; /** * {@inheritdoc} */ public function contains(Currency $currency) { return self::CODE === $currency->getCode(); } /** * {@inheritdoc} */ public function subunitFor(Currency $currency) { if ($currency->getCode() !== self::CODE) { throw new UnknownCurrencyException( $currency->getCode().' is not bitcoin and is not supported by this currency repository' ); } return 8; } /** * {@inheritdoc} */ public function getIterator() { return new \ArrayIterator([new Currency(self::CODE)]); } } src/Formatter/IntlLocalizedDecimalFormatter.php 0000666 00000003153 15165570755 0015735 0 ustar 00 <?php namespace Money\Formatter; use Money\Currencies; use Money\Money; use Money\MoneyFormatter; /** * Formats a Money object using intl extension. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class IntlLocalizedDecimalFormatter implements MoneyFormatter { /** * @var \NumberFormatter */ private $formatter; /** * @var Currencies */ private $currencies; /** * @param \NumberFormatter $formatter * @param Currencies $currencies */ public function __construct(\NumberFormatter $formatter, Currencies $currencies) { $this->formatter = $formatter; $this->currencies = $currencies; } /** * {@inheritdoc} */ public function format(Money $money) { $valueBase = $money->getAmount(); $negative = false; if ($valueBase[0] === '-') { $negative = true; $valueBase = substr($valueBase, 1); } $subunit = $this->currencies->subunitFor($money->getCurrency()); $valueLength = strlen($valueBase); if ($valueLength > $subunit) { $formatted = substr($valueBase, 0, $valueLength - $subunit); $decimalDigits = substr($valueBase, $valueLength - $subunit); if (strlen($decimalDigits) > 0) { $formatted .= '.'.$decimalDigits; } } else { $formatted = '0.'.str_pad('', $subunit - $valueLength, '0').$valueBase; } if ($negative === true) { $formatted = '-'.$formatted; } return $this->formatter->format($formatted); } } src/Formatter/DecimalMoneyFormatter.php 0000666 00000002617 15165570755 0014273 0 ustar 00 <?php namespace Money\Formatter; use Money\Currencies; use Money\Money; use Money\MoneyFormatter; /** * Formats a Money object as a decimal string. * * @author Teoh Han Hui <teohhanhui@gmail.com> */ final class DecimalMoneyFormatter implements MoneyFormatter { /** * @var Currencies */ private $currencies; /** * @param Currencies $currencies */ public function __construct(Currencies $currencies) { $this->currencies = $currencies; } /** * {@inheritdoc} */ public function format(Money $money) { $valueBase = $money->getAmount(); $negative = false; if ($valueBase[0] === '-') { $negative = true; $valueBase = substr($valueBase, 1); } $subunit = $this->currencies->subunitFor($money->getCurrency()); $valueLength = strlen($valueBase); if ($valueLength > $subunit) { $formatted = substr($valueBase, 0, $valueLength - $subunit); $decimalDigits = substr($valueBase, $valueLength - $subunit); if (strlen($decimalDigits) > 0) { $formatted .= '.'.$decimalDigits; } } else { $formatted = '0.'.str_pad('', $subunit - $valueLength, '0').$valueBase; } if ($negative === true) { $formatted = '-'.$formatted; } return $formatted; } } src/Formatter/BitcoinMoneyFormatter.php 0000666 00000004601 15165570755 0014317 0 ustar 00 <?php namespace Money\Formatter; use Money\Currencies; use Money\Currencies\BitcoinCurrencies; use Money\Exception\FormatterException; use Money\Money; use Money\MoneyFormatter; use Money\Number; /** * Formats Money to Bitcoin currency. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class BitcoinMoneyFormatter implements MoneyFormatter { /** * @var int */ private $fractionDigits; /** * @var Currencies */ private $currencies; /** * @param int $fractionDigits * @param Currencies $currencies */ public function __construct($fractionDigits, Currencies $currencies) { $this->fractionDigits = $fractionDigits; $this->currencies = $currencies; } /** * {@inheritdoc} */ public function format(Money $money) { if (BitcoinCurrencies::CODE !== $money->getCurrency()->getCode()) { throw new FormatterException('Bitcoin Formatter can only format Bitcoin currency'); } $valueBase = $money->getAmount(); $negative = false; if ('-' === $valueBase[0]) { $negative = true; $valueBase = substr($valueBase, 1); } $subunit = $this->currencies->subunitFor($money->getCurrency()); $valueBase = Number::roundMoneyValue($valueBase, $this->fractionDigits, $subunit); $valueLength = strlen($valueBase); if ($valueLength > $subunit) { $formatted = substr($valueBase, 0, $valueLength - $subunit); if ($subunit) { $formatted .= '.'; $formatted .= substr($valueBase, $valueLength - $subunit); } } else { $formatted = '0.'.str_pad('', $subunit - $valueLength, '0').$valueBase; } if ($this->fractionDigits === 0) { $formatted = substr($formatted, 0, strpos($formatted, '.')); } elseif ($this->fractionDigits > $subunit) { $formatted .= str_pad('', $this->fractionDigits - $subunit, '0'); } elseif ($this->fractionDigits < $subunit) { $lastDigit = strpos($formatted, '.') + $this->fractionDigits + 1; $formatted = substr($formatted, 0, $lastDigit); } $formatted = BitcoinCurrencies::SYMBOL.$formatted; if (true === $negative) { $formatted = '-'.$formatted; } return $formatted; } } src/Formatter/IntlMoneyFormatter.php 0000666 00000003212 15165570755 0013633 0 ustar 00 <?php namespace Money\Formatter; use Money\Currencies; use Money\Money; use Money\MoneyFormatter; /** * Formats a Money object using intl extension. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class IntlMoneyFormatter implements MoneyFormatter { /** * @var \NumberFormatter */ private $formatter; /** * @var Currencies */ private $currencies; /** * @param \NumberFormatter $formatter * @param Currencies $currencies */ public function __construct(\NumberFormatter $formatter, Currencies $currencies) { $this->formatter = $formatter; $this->currencies = $currencies; } /** * {@inheritdoc} */ public function format(Money $money) { $valueBase = $money->getAmount(); $negative = false; if ($valueBase[0] === '-') { $negative = true; $valueBase = substr($valueBase, 1); } $subunit = $this->currencies->subunitFor($money->getCurrency()); $valueLength = strlen($valueBase); if ($valueLength > $subunit) { $formatted = substr($valueBase, 0, $valueLength - $subunit); $decimalDigits = substr($valueBase, $valueLength - $subunit); if (strlen($decimalDigits) > 0) { $formatted .= '.'.$decimalDigits; } } else { $formatted = '0.'.str_pad('', $subunit - $valueLength, '0').$valueBase; } if ($negative === true) { $formatted = '-'.$formatted; } return $this->formatter->formatCurrency($formatted, $money->getCurrency()->getCode()); } } src/Formatter/AggregateMoneyFormatter.php 0000666 00000002670 15165570755 0014622 0 ustar 00 <?php namespace Money\Formatter; use Money\Exception\FormatterException; use Money\Money; use Money\MoneyFormatter; /** * Formats a Money object using other Money formatters. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class AggregateMoneyFormatter implements MoneyFormatter { /** * @var MoneyFormatter[] */ private $formatters = []; /** * @param MoneyFormatter[] $formatters */ public function __construct(array $formatters) { if (empty($formatters)) { throw new \InvalidArgumentException(sprintf('Initialize an empty %s is not possible', self::class)); } foreach ($formatters as $currencyCode => $formatter) { if (false === $formatter instanceof MoneyFormatter) { throw new \InvalidArgumentException('All formatters must implement '.MoneyFormatter::class); } $this->formatters[$currencyCode] = $formatter; } } /** * {@inheritdoc} */ public function format(Money $money) { $currencyCode = $money->getCurrency()->getCode(); if (isset($this->formatters[$currencyCode])) { return $this->formatters[$currencyCode]->format($money); } if (isset($this->formatters['*'])) { return $this->formatters['*']->format($money); } throw new FormatterException('No formatter found for currency '.$currencyCode); } } src/Exchange/ReversedCurrenciesExchange.php 0000666 00000002414 15165570755 0015060 0 ustar 00 <?php namespace Money\Exchange; use Money\Currency; use Money\CurrencyPair; use Money\Exception\UnresolvableCurrencyPairException; use Money\Exchange; /** * Tries the reverse of the currency pair if one is not available. * * Note: adding nested ReversedCurrenciesExchange could cause a huge performance hit. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ final class ReversedCurrenciesExchange implements Exchange { /** * @var Exchange */ private $exchange; /** * @param Exchange $exchange */ public function __construct(Exchange $exchange) { $this->exchange = $exchange; } /** * {@inheritdoc} */ public function quote(Currency $baseCurrency, Currency $counterCurrency) { try { return $this->exchange->quote($baseCurrency, $counterCurrency); } catch (UnresolvableCurrencyPairException $exception) { try { $currencyPair = $this->exchange->quote($counterCurrency, $baseCurrency); return new CurrencyPair($baseCurrency, $counterCurrency, 1 / $currencyPair->getConversionRatio()); } catch (UnresolvableCurrencyPairException $inversedException) { throw $exception; } } } } src/Exchange/FixedExchange.php 0000666 00000002021 15165570755 0012307 0 ustar 00 <?php namespace Money\Exchange; use Money\Currency; use Money\CurrencyPair; use Money\Exception\UnresolvableCurrencyPairException; use Money\Exchange; /** * Provides a way to get exchange rate from a static list (array). * * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class FixedExchange implements Exchange { /** * @var array */ private $list; /** * @param array $list */ public function __construct(array $list) { $this->list = $list; } /** * {@inheritdoc} */ public function quote(Currency $baseCurrency, Currency $counterCurrency) { if (isset($this->list[$baseCurrency->getCode()][$counterCurrency->getCode()])) { return new CurrencyPair( $baseCurrency, $counterCurrency, $this->list[$baseCurrency->getCode()][$counterCurrency->getCode()] ); } throw UnresolvableCurrencyPairException::createFromCurrencies($baseCurrency, $counterCurrency); } } src/Exchange/IndirectExchange.php 0000666 00000013304 15165570755 0013017 0 ustar 00 <?php namespace Money\Exchange; use Money\Calculator; use Money\Calculator\BcMathCalculator; use Money\Calculator\GmpCalculator; use Money\Calculator\PhpCalculator; use Money\Currencies; use Money\Currency; use Money\CurrencyPair; use Money\Exception\UnresolvableCurrencyPairException; use Money\Exchange; /** * Provides a way to get an exchange rate through a minimal set of intermediate conversions. * * @author Michael Cordingley <Michael.Cordingley@gmail.com> */ final class IndirectExchange implements Exchange { /** * @var Calculator */ private static $calculator; /** * @var array */ private static $calculators = [ BcMathCalculator::class, GmpCalculator::class, PhpCalculator::class, ]; /** * @var Currencies */ private $currencies; /** * @var Exchange */ private $exchange; /** * @param Exchange $exchange * @param Currencies $currencies */ public function __construct(Exchange $exchange, Currencies $currencies) { $this->exchange = $exchange; $this->currencies = $currencies; } /** * @param string $calculator */ public static function registerCalculator($calculator) { if (is_a($calculator, Calculator::class, true) === false) { throw new \InvalidArgumentException('Calculator must implement '.Calculator::class); } array_unshift(self::$calculators, $calculator); } /** * {@inheritdoc} */ public function quote(Currency $baseCurrency, Currency $counterCurrency) { try { return $this->exchange->quote($baseCurrency, $counterCurrency); } catch (UnresolvableCurrencyPairException $exception) { $rate = array_reduce($this->getConversions($baseCurrency, $counterCurrency), function ($carry, CurrencyPair $pair) { return static::getCalculator()->multiply($carry, $pair->getConversionRatio()); }, '1.0'); return new CurrencyPair($baseCurrency, $counterCurrency, $rate); } } /** * @param Currency $baseCurrency * @param Currency $counterCurrency * * @return CurrencyPair[] * * @throws UnresolvableCurrencyPairException */ private function getConversions(Currency $baseCurrency, Currency $counterCurrency) { $startNode = $this->initializeNode($baseCurrency); $startNode->discovered = true; $nodes = [$baseCurrency->getCode() => $startNode]; $frontier = new \SplQueue(); $frontier->enqueue($startNode); while ($frontier->count()) { /** @var \stdClass $currentNode */ $currentNode = $frontier->dequeue(); /** @var Currency $currentCurrency */ $currentCurrency = $currentNode->currency; if ($currentCurrency->equals($counterCurrency)) { return $this->reconstructConversionChain($nodes, $currentNode); } /** @var Currency $candidateCurrency */ foreach ($this->currencies as $candidateCurrency) { if (!isset($nodes[$candidateCurrency->getCode()])) { $nodes[$candidateCurrency->getCode()] = $this->initializeNode($candidateCurrency); } /** @var \stdClass $node */ $node = $nodes[$candidateCurrency->getCode()]; if (!$node->discovered) { try { // Check if the candidate is a neighbor. This will throw an exception if it isn't. $this->exchange->quote($currentCurrency, $candidateCurrency); $node->discovered = true; $node->parent = $currentNode; $frontier->enqueue($node); } catch (UnresolvableCurrencyPairException $exception) { // Not a neighbor. Move on. } } } } throw UnresolvableCurrencyPairException::createFromCurrencies($baseCurrency, $counterCurrency); } /** * @param Currency $currency * * @return \stdClass */ private function initializeNode(Currency $currency) { $node = new \stdClass(); $node->currency = $currency; $node->discovered = false; $node->parent = null; return $node; } /** * @param array $currencies * @param \stdClass $goalNode * * @return CurrencyPair[] */ private function reconstructConversionChain(array $currencies, \stdClass $goalNode) { $current = $goalNode; $conversions = []; while ($current->parent) { $previous = $currencies[$current->parent->currency->getCode()]; $conversions[] = $this->exchange->quote($previous->currency, $current->currency); $current = $previous; } return array_reverse($conversions); } /** * @return Calculator */ private function getCalculator() { if (null === self::$calculator) { self::$calculator = self::initializeCalculator(); } return self::$calculator; } /** * @return Calculator * * @throws \RuntimeException If cannot find calculator for money calculations */ private static function initializeCalculator() { $calculators = self::$calculators; foreach ($calculators as $calculator) { /** @var Calculator $calculator */ if ($calculator::supported()) { return new $calculator(); } } throw new \RuntimeException('Cannot find calculator for money calculations'); } } src/Exchange/SwapExchange.php 0000666 00000002115 15165570755 0012166 0 ustar 00 <?php namespace Money\Exchange; use Exchanger\Exception\Exception as ExchangerException; use Money\Currency; use Money\CurrencyPair; use Money\Exception\UnresolvableCurrencyPairException; use Money\Exchange; use Swap\Swap; /** * Provides a way to get exchange rate from a third-party source and return a currency pair. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ final class SwapExchange implements Exchange { /** * @var Swap */ private $swap; /** * @param Swap $swap */ public function __construct(Swap $swap) { $this->swap = $swap; } /** * {@inheritdoc} */ public function quote(Currency $baseCurrency, Currency $counterCurrency) { try { $rate = $this->swap->latest($baseCurrency->getCode().'/'.$counterCurrency->getCode()); } catch (ExchangerException $e) { throw UnresolvableCurrencyPairException::createFromCurrencies($baseCurrency, $counterCurrency); } return new CurrencyPair($baseCurrency, $counterCurrency, $rate->getValue()); } } src/Exchange/ExchangerExchange.php 0000666 00000002611 15165570755 0013161 0 ustar 00 <?php namespace Money\Exchange; use Exchanger\CurrencyPair as ExchangerCurrencyPair; use Exchanger\Contract\ExchangeRateProvider; use Exchanger\Exception\Exception as ExchangerException; use Exchanger\ExchangeRateQuery; use Money\Currency; use Money\CurrencyPair; use Money\Exception\UnresolvableCurrencyPairException; use Money\Exchange; /** * Provides a way to get exchange rate from a third-party source and return a currency pair. * * @author Maksim (Ellrion) Platonov <ellrion11@gmail.com> */ final class ExchangerExchange implements Exchange { /** * @var ExchangeRateProvider */ private $exchanger; /** * @param ExchangeRateProvider $exchanger */ public function __construct(ExchangeRateProvider $exchanger) { $this->exchanger = $exchanger; } /** * {@inheritdoc} */ public function quote(Currency $baseCurrency, Currency $counterCurrency) { try { $query = new ExchangeRateQuery( new ExchangerCurrencyPair($baseCurrency->getCode(), $counterCurrency->getCode()) ); $rate = $this->exchanger->getExchangeRate($query); } catch (ExchangerException $e) { throw UnresolvableCurrencyPairException::createFromCurrencies($baseCurrency, $counterCurrency); } return new CurrencyPair($baseCurrency, $counterCurrency, $rate->getValue()); } } src/Converter.php 0000666 00000002651 15165570755 0010043 0 ustar 00 <?php namespace Money; /** * Provides a way to convert Money to Money in another Currency using an exchange rate. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class Converter { /** * @var Currencies */ private $currencies; /** * @var Exchange */ private $exchange; /** * @param Currencies $currencies * @param Exchange $exchange */ public function __construct(Currencies $currencies, Exchange $exchange) { $this->currencies = $currencies; $this->exchange = $exchange; } /** * @param Money $money * @param Currency $counterCurrency * @param int $roundingMode * * @return Money */ public function convert(Money $money, Currency $counterCurrency, $roundingMode = Money::ROUND_HALF_UP) { $baseCurrency = $money->getCurrency(); $ratio = $this->exchange->quote($baseCurrency, $counterCurrency)->getConversionRatio(); $baseCurrencySubunit = $this->currencies->subunitFor($baseCurrency); $counterCurrencySubunit = $this->currencies->subunitFor($counterCurrency); $subunitDifference = $baseCurrencySubunit - $counterCurrencySubunit; $ratio = (string) Number::fromFloat($ratio)->base10($subunitDifference); $counterValue = $money->multiply($ratio, $roundingMode); return new Money($counterValue->getAmount(), $counterCurrency); } } src/Exception/UnresolvableCurrencyPairException.php 0000666 00000001551 15165570755 0016677 0 ustar 00 <?php namespace Money\Exception; use Money\Currency; use Money\Exception; /** * Thrown when there is no currency pair (rate) available for the given currencies. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ final class UnresolvableCurrencyPairException extends \InvalidArgumentException implements Exception { /** * Creates an exception from Currency objects. * * @param Currency $baseCurrency * @param Currency $counterCurrency * * @return UnresolvableCurrencyPairException */ public static function createFromCurrencies(Currency $baseCurrency, Currency $counterCurrency) { $message = sprintf( 'Cannot resolve a currency pair for currencies: %s/%s', $baseCurrency->getCode(), $counterCurrency->getCode() ); return new self($message); } } src/Exception/UnknownCurrencyException.php 0000666 00000000411 15165570755 0015053 0 ustar 00 <?php namespace Money\Exception; use Money\Exception; /** * Thrown when trying to get ISO currency that does not exists. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class UnknownCurrencyException extends \DomainException implements Exception { } src/Exception/FormatterException.php 0000666 00000000405 15165570755 0013647 0 ustar 00 <?php namespace Money\Exception; use Money\Exception; /** * Thrown when a Money object cannot be formatted into a string. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class FormatterException extends \RuntimeException implements Exception { } src/Exception/ParserException.php 0000666 00000000375 15165570755 0013146 0 ustar 00 <?php namespace Money\Exception; use Money\Exception; /** * Thrown when a string cannot be parsed to a Money object. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class ParserException extends \RuntimeException implements Exception { } src/Exchange.php 0000666 00000001310 15165570755 0007605 0 ustar 00 <?php namespace Money; use Money\Exception\UnresolvableCurrencyPairException; /** * Provides a way to get exchange rate from a third-party source and return a currency pair. * * @author Márk Sági-Kazár <mark.sagikazar@gmail.com> */ interface Exchange { /** * Returns a currency pair for the passed currencies with the rate coming from a third-party source. * * @param Currency $baseCurrency * @param Currency $counterCurrency * * @return CurrencyPair * * @throws UnresolvableCurrencyPairException When there is no currency pair (rate) available for the given currencies */ public function quote(Currency $baseCurrency, Currency $counterCurrency); } src/Number.php 0000666 00000020306 15165570755 0007321 0 ustar 00 <?php namespace Money; /** * Represents a numeric value. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class Number { /** * @var string */ private $integerPart; /** * @var string */ private $fractionalPart; /** * @var array */ private static $numbers = [0 => 1, 1 => 1, 2 => 1, 3 => 1, 4 => 1, 5 => 1, 6 => 1, 7 => 1, 8 => 1, 9 => 1]; /** * @param string $integerPart * @param string $fractionalPart */ public function __construct($integerPart, $fractionalPart = '') { if ('' === $integerPart && '' === $fractionalPart) { throw new \InvalidArgumentException('Empty number is invalid'); } $this->integerPart = $this->parseIntegerPart((string) $integerPart); $this->fractionalPart = $this->parseFractionalPart((string) $fractionalPart); } /** * @param $number * * @return self */ public static function fromString($number) { $decimalSeparatorPosition = strpos($number, '.'); if ($decimalSeparatorPosition === false) { return new self($number, ''); } return new self( substr($number, 0, $decimalSeparatorPosition), rtrim(substr($number, $decimalSeparatorPosition + 1), '0') ); } /** * @param float $number * * @return self */ public static function fromFloat($number) { if (is_float($number) === false) { throw new \InvalidArgumentException('Floating point value expected'); } return self::fromString(sprintf('%.14F', $number)); } /** * @param float|int|string $number * * @return self */ public static function fromNumber($number) { if (is_float($number)) { return self::fromString(sprintf('%.14F', $number)); } if (is_int($number)) { return new self($number); } if (is_string($number)) { return self::fromString($number); } throw new \InvalidArgumentException('Valid numeric value expected'); } /** * @return bool */ public function isDecimal() { return $this->fractionalPart !== ''; } /** * @return bool */ public function isInteger() { return $this->fractionalPart === ''; } /** * @return bool */ public function isHalf() { return $this->fractionalPart === '5'; } /** * @return bool */ public function isCurrentEven() { $lastIntegerPartNumber = $this->integerPart[strlen($this->integerPart) - 1]; return $lastIntegerPartNumber % 2 === 0; } /** * @return bool */ public function isCloserToNext() { if ($this->fractionalPart === '') { return false; } return $this->fractionalPart[0] >= 5; } /** * @return string */ public function __toString() { if ($this->fractionalPart === '') { return $this->integerPart; } return $this->integerPart.'.'.$this->fractionalPart; } /** * @return bool */ public function isNegative() { return $this->integerPart[0] === '-'; } /** * @return string */ public function getIntegerPart() { return $this->integerPart; } /** * @return string */ public function getFractionalPart() { return $this->fractionalPart; } /** * @return string */ public function getIntegerRoundingMultiplier() { if ($this->integerPart[0] === '-') { return '-1'; } return '1'; } /** * @param int $number * * @return self */ public function base10($number) { if (!is_int($number)) { throw new \InvalidArgumentException('Expecting integer'); } if ($this->integerPart === '0' && !$this->fractionalPart) { return $this; } $sign = ''; $integerPart = $this->integerPart; if ($integerPart[0] === '-') { $sign = '-'; $integerPart = substr($integerPart, 1); } if ($number >= 0) { $integerPart = ltrim($integerPart, '0'); $lengthIntegerPart = strlen($integerPart); $integers = $lengthIntegerPart - min($number, $lengthIntegerPart); $zeroPad = $number - min($number, $lengthIntegerPart); return new self( $sign.substr($integerPart, 0, $integers), rtrim(str_pad('', $zeroPad, '0').substr($integerPart, $integers).$this->fractionalPart, '0') ); } $number = abs($number); $lengthFractionalPart = strlen($this->fractionalPart); $fractions = $lengthFractionalPart - min($number, $lengthFractionalPart); $zeroPad = $number - min($number, $lengthFractionalPart); return new self( $sign.ltrim($integerPart.substr($this->fractionalPart, 0, $lengthFractionalPart - $fractions).str_pad('', $zeroPad, '0'), '0'), substr($this->fractionalPart, $lengthFractionalPart - $fractions) ); } /** * @param string $number * * @return string */ private static function parseIntegerPart($number) { if ('' === $number || '0' === $number) { return '0'; } if ('-' === $number) { return '-0'; } $nonZero = false; for ($position = 0, $characters = strlen($number); $position < $characters; ++$position) { $digit = $number[$position]; if (!isset(static::$numbers[$digit]) && !(0 === $position && '-' === $digit)) { throw new \InvalidArgumentException( sprintf('Invalid integer part %1$s. Invalid digit %2$s found', $number, $digit) ); } if (false === $nonZero && '0' === $digit) { throw new \InvalidArgumentException( 'Leading zeros are not allowed' ); } $nonZero = true; } return $number; } /** * @param string $number * * @return string */ private static function parseFractionalPart($number) { if ('' === $number) { return $number; } for ($position = 0, $characters = strlen($number); $position < $characters; ++$position) { $digit = $number[$position]; if (!isset(static::$numbers[$digit])) { throw new \InvalidArgumentException( sprintf('Invalid fractional part %1$s. Invalid digit %2$s found', $number, $digit) ); } } return $number; } /** * @param string $moneyValue * @param int $targetDigits * @param int $havingDigits * * @return string */ public static function roundMoneyValue($moneyValue, $targetDigits, $havingDigits) { $valueLength = strlen($moneyValue); $shouldRound = $targetDigits < $havingDigits && $valueLength - $havingDigits + $targetDigits > 0; if ($shouldRound && $moneyValue[$valueLength - $havingDigits + $targetDigits] >= 5) { $position = $valueLength - $havingDigits + $targetDigits; $addend = 1; while ($position > 0) { $newValue = (string) ((int) $moneyValue[$position - 1] + $addend); if ($newValue >= 10) { $moneyValue[$position - 1] = $newValue[1]; $addend = $newValue[0]; --$position; if ($position === 0) { $moneyValue = $addend.$moneyValue; } } else { if ($moneyValue[$position - 1] === '-') { $moneyValue[$position - 1] = $newValue[0]; $moneyValue = '-'.$moneyValue; } else { $moneyValue[$position - 1] = $newValue[0]; } break; } } } return $moneyValue; } } src/CurrencyPair.php 0000666 00000006456 15165570755 0010511 0 ustar 00 <?php namespace Money; /** * Currency Pair holding a base, a counter currency and a conversion ratio. * * @author Mathias Verraes * * @see http://en.wikipedia.org/wiki/Currency_pair */ final class CurrencyPair implements \JsonSerializable { /** * Currency to convert from. * * @var Currency */ private $baseCurrency; /** * Currency to convert to. * * @var Currency */ private $counterCurrency; /** * @var float */ private $conversionRatio; /** * @param Currency $baseCurrency * @param Currency $counterCurrency * @param float $conversionRatio * * @throws \InvalidArgumentException If conversion ratio is not numeric */ public function __construct(Currency $baseCurrency, Currency $counterCurrency, $conversionRatio) { if (!is_numeric($conversionRatio)) { throw new \InvalidArgumentException('Conversion ratio must be numeric'); } $this->counterCurrency = $counterCurrency; $this->baseCurrency = $baseCurrency; $this->conversionRatio = (float) $conversionRatio; } /** * Creates a new Currency Pair based on "EUR/USD 1.2500" form representation. * * @param string $iso String representation of the form "EUR/USD 1.2500" * * @return CurrencyPair * * @throws \InvalidArgumentException Format of $iso is invalid */ public static function createFromIso($iso) { $currency = '([A-Z]{2,3})'; $ratio = "([0-9]*\.?[0-9]+)"; // @see http://www.regular-expressions.info/floatingpoint.html $pattern = '#'.$currency.'/'.$currency.' '.$ratio.'#'; $matches = []; if (!preg_match($pattern, $iso, $matches)) { throw new \InvalidArgumentException( sprintf( 'Cannot create currency pair from ISO string "%s", format of string is invalid', $iso ) ); } return new self(new Currency($matches[1]), new Currency($matches[2]), $matches[3]); } /** * Returns the counter currency. * * @return Currency */ public function getCounterCurrency() { return $this->counterCurrency; } /** * Returns the base currency. * * @return Currency */ public function getBaseCurrency() { return $this->baseCurrency; } /** * Returns the conversion ratio. * * @return float */ public function getConversionRatio() { return $this->conversionRatio; } /** * Checks if an other CurrencyPair has the same parameters as this. * * @param CurrencyPair $other * * @return bool */ public function equals(CurrencyPair $other) { return $this->baseCurrency->equals($other->baseCurrency) && $this->counterCurrency->equals($other->counterCurrency) && $this->conversionRatio === $other->conversionRatio ; } /** * {@inheritdoc} * * @return array */ public function jsonSerialize() { return [ 'baseCurrency' => $this->baseCurrency, 'counterCurrency' => $this->counterCurrency, 'ratio' => $this->conversionRatio, ]; } } src/Currency.php 0000666 00000003130 15165570755 0007657 0 ustar 00 <?php namespace Money; /** * Currency Value Object. * * Holds Currency specific data. * * @author Mathias Verraes * * @psalm-immutable */ final class Currency implements \JsonSerializable { /** * Currency code. * * @var string */ private $code; /** * @param string $code */ public function __construct($code) { if (!is_string($code)) { throw new \InvalidArgumentException('Currency code should be string'); } if ($code === '') { throw new \InvalidArgumentException('Currency code should not be empty string'); } $this->code = $code; } /** * Returns the currency code. * * @return string */ public function getCode() { return $this->code; } /** * Checks whether this currency is the same as an other. * * @param Currency $other * * @return bool */ public function equals(Currency $other) { return $this->code === $other->code; } /** * Checks whether this currency is available in the passed context. * * @param Currencies $currencies * * @return bool */ public function isAvailableWithin(Currencies $currencies) { return $currencies->contains($this); } /** * @return string */ public function __toString() { return $this->code; } /** * {@inheritdoc} * * @return string */ #[\ReturnTypeWillChange] public function jsonSerialize() { return $this->code; } } src/Currencies.php 0000666 00000001265 15165570755 0010176 0 ustar 00 <?php namespace Money; use Money\Exception\UnknownCurrencyException; /** * Implement this to provide a list of currencies. * * @author Mathias Verraes */ interface Currencies extends \IteratorAggregate { /** * Checks whether a currency is available in the current context. * * @param Currency $currency * * @return bool */ public function contains(Currency $currency); /** * Returns the subunit for a currency. * * @param Currency $currency * * @return int * * @throws UnknownCurrencyException If currency is not available in the current context */ public function subunitFor(Currency $currency); } src/PHPUnit/Comparator.php 0000666 00000003540 15165570755 0011470 0 ustar 00 <?php namespace Money\PHPUnit; use Money\Currencies\AggregateCurrencies; use Money\Currencies\BitcoinCurrencies; use Money\Currencies\ISOCurrencies; use Money\Formatter\IntlMoneyFormatter; use Money\Money; use SebastianBergmann\Comparator\ComparisonFailure; /** * The comparator is for comparing Money objects in PHPUnit tests. * * Add this to your bootstrap file: * * \SebastianBergmann\Comparator\Factory::getInstance()->register(new \Money\PHPUnit\Comparator()); */ final class Comparator extends \SebastianBergmann\Comparator\Comparator { /** * @var IntlMoneyFormatter */ private $formatter; public function __construct() { parent::__construct(); $currencies = new AggregateCurrencies([ new ISOCurrencies(), new BitcoinCurrencies(), ]); $numberFormatter = new \NumberFormatter('en_US', \NumberFormatter::CURRENCY); $this->formatter = new IntlMoneyFormatter($numberFormatter, $currencies); } public function accepts($expected, $actual) { return $expected instanceof Money && $actual instanceof Money; } /** * @param Money $expected * @param Money $actual * @param float $delta * @param bool $canonicalize * @param bool $ignoreCase * @param array $processed */ public function assertEquals( $expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false, array &$processed = [] ) { if (!$expected->equals($actual)) { throw new ComparisonFailure( $expected, $actual, $this->formatter->format($expected), $this->formatter->format($actual), false, 'Failed asserting that two Money objects are equal.' ); } } } src/Parser/IntlLocalizedDecimalParser.php 0000666 00000005654 15165570755 0014527 0 ustar 00 <?php namespace Money\Parser; 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. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class IntlLocalizedDecimalParser implements MoneyParser { /** * @var \NumberFormatter */ private $formatter; /** * @var Currencies */ private $currencies; /** * @param \NumberFormatter $formatter * @param Currencies $currencies */ public function __construct(\NumberFormatter $formatter, Currencies $currencies) { $this->formatter = $formatter; $this->currencies = $currencies; } /** * {@inheritdoc} */ public function parse($money, $forceCurrency = null) { if (!is_string($money)) { throw new ParserException('Formatted raw money should be string, e.g. $1.00'); } if (null === $forceCurrency) { throw new ParserException( 'IntlLocalizedDecimalParser cannot parse currency symbols. Use forceCurrency argument' ); } $decimal = $this->formatter->parse($money); if (false === $decimal) { throw new ParserException( 'Cannot parse '.$money.' to Money. '.$this->formatter->getErrorMessage() ); } /* * This conversion is only required whilst currency can be either a string or a * Currency object. */ if (!$forceCurrency instanceof Currency) { @trigger_error('Passing a currency as string is deprecated since 3.1 and will be removed in 4.0. Please pass a '.Currency::class.' instance instead.', E_USER_DEPRECATED); $forceCurrency = new Currency($forceCurrency); } $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); } } src/Parser/BitcoinMoneyParser.php 0000666 00000004453 15165570755 0013106 0 ustar 00 <?php namespace Money\Parser; use Money\Currencies\BitcoinCurrencies; use Money\Currency; use Money\Exception\ParserException; use Money\Money; use Money\MoneyParser; /** * Parses Bitcoin currency to Money. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class BitcoinMoneyParser implements MoneyParser { /** * @var int */ private $fractionDigits; /** * @param int $fractionDigits */ public function __construct($fractionDigits) { $this->fractionDigits = $fractionDigits; } /** * {@inheritdoc} */ public function parse($money, $forceCurrency = null) { if (is_string($money) === false) { throw new ParserException('Formatted raw money should be string, e.g. $1.00'); } if (strpos($money, BitcoinCurrencies::SYMBOL) === false) { throw new ParserException('Value cannot be parsed as Bitcoin'); } if ($forceCurrency === null) { $forceCurrency = new Currency(BitcoinCurrencies::CODE); } /* * This conversion is only required whilst currency can be either a string or a * Currency object. */ $currency = $forceCurrency; if (!$currency instanceof Currency) { @trigger_error('Passing a currency as string is deprecated since 3.1 and will be removed in 4.0. Please pass a '.Currency::class.' instance instead.', E_USER_DEPRECATED); $currency = new Currency($currency); } $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); } } src/Parser/IntlMoneyParser.php 0000666 00000005602 15165570755 0012422 0 ustar 00 <?php namespace Money\Parser; 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. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class IntlMoneyParser implements MoneyParser { /** * @var \NumberFormatter */ private $formatter; /** * @var Currencies */ private $currencies; /** * @param \NumberFormatter $formatter * @param Currencies $currencies */ public function __construct(\NumberFormatter $formatter, Currencies $currencies) { $this->formatter = $formatter; $this->currencies = $currencies; } /** * {@inheritdoc} */ public function parse($money, $forceCurrency = null) { if (!is_string($money)) { throw new ParserException('Formatted raw money should be string, e.g. $1.00'); } $currency = null; $decimal = $this->formatter->parseCurrency($money, $currency); if (false === $decimal) { throw new ParserException( 'Cannot parse '.$money.' to Money. '.$this->formatter->getErrorMessage() ); } if (null !== $forceCurrency) { $currency = $forceCurrency; } else { $currency = new Currency($currency); } /* * This conversion is only required whilst currency can be either a string or a * Currency object. */ if (!$currency instanceof Currency) { @trigger_error('Passing a currency as string is deprecated since 3.1 and will be removed in 4.0. Please pass a '.Currency::class.' instance instead.', E_USER_DEPRECATED); $currency = new Currency($currency); } $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); } } src/Parser/AggregateMoneyParser.php 0000666 00000003107 15165570755 0013400 0 ustar 00 <?php namespace Money\Parser; use Money\Currency; use Money\Exception; use Money\MoneyParser; /** * Parses a string into a Money object using other parsers. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ final class AggregateMoneyParser implements MoneyParser { /** * @var MoneyParser[] */ private $parsers = []; /** * @param MoneyParser[] $parsers */ public function __construct(array $parsers) { if (empty($parsers)) { throw new \InvalidArgumentException(sprintf('Initialize an empty %s is not possible', self::class)); } foreach ($parsers as $parser) { if (false === $parser instanceof MoneyParser) { throw new \InvalidArgumentException('All parsers must implement '.MoneyParser::class); } $this->parsers[] = $parser; } } /** * {@inheritdoc} */ public function parse($money, $forceCurrency = null) { if ($forceCurrency !== null && !$forceCurrency instanceof Currency) { @trigger_error('Passing a currency as string is deprecated since 3.1 and will be removed in 4.0. Please pass a '.Currency::class.' instance instead.', E_USER_DEPRECATED); $forceCurrency = new Currency($forceCurrency); } foreach ($this->parsers as $parser) { try { return $parser->parse($money, $forceCurrency); } catch (Exception\ParserException $e) { } } throw new Exception\ParserException(sprintf('Unable to parse %s', $money)); } } src/Parser/DecimalMoneyParser.php 0000666 00000005746 15165570755 0013063 0 ustar 00 <?php namespace Money\Parser; 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. * * @author Teoh Han Hui <teohhanhui@gmail.com> */ final class DecimalMoneyParser implements MoneyParser { const DECIMAL_PATTERN = '/^(?P<sign>-)?(?P<digits>0|[1-9]\d*)?\.?(?P<fraction>\d+)?$/'; /** * @var Currencies */ private $currencies; /** * @param Currencies $currencies */ public function __construct(Currencies $currencies) { $this->currencies = $currencies; } /** * {@inheritdoc} */ public function parse($money, $forceCurrency = null) { if (!is_string($money)) { throw new ParserException('Formatted raw money should be string, e.g. 1.00'); } if (null === $forceCurrency) { throw new ParserException( 'DecimalMoneyParser cannot parse currency symbols. Use forceCurrency argument' ); } /* * This conversion is only required whilst currency can be either a string or a * Currency object. */ $currency = $forceCurrency; if (!$currency instanceof Currency) { @trigger_error('Passing a currency as string is deprecated since 3.1 and will be removed in 4.0. Please pass a '.Currency::class.' instance instead.', E_USER_DEPRECATED); $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); } } src/Calculator.php 0000666 00000004772 15165570755 0010173 0 ustar 00 <?php namespace Money; /** * Money calculations abstracted away from the Money value object. * * @author Frederik Bosch <f.bosch@genkgo.nl> */ interface Calculator { /** * Returns whether the calculator is supported in * the current server environment. * * @return bool */ public static function supported(); /** * Compare a to b. * * @param string $a * @param string $b * * @return int */ public function compare($a, $b); /** * Add added to amount. * * @param string $amount * @param string $addend * * @return string */ public function add($amount, $addend); /** * Subtract subtrahend from amount. * * @param string $amount * @param string $subtrahend * * @return string */ public function subtract($amount, $subtrahend); /** * Multiply amount with multiplier. * * @param string $amount * @param int|float|string $multiplier * * @return string */ public function multiply($amount, $multiplier); /** * Divide amount with divisor. * * @param string $amount * @param int|float|string $divisor * * @return string */ public function divide($amount, $divisor); /** * Round number to following integer. * * @param string $number * * @return string */ public function ceil($number); /** * Round number to preceding integer. * * @param string $number * * @return string */ public function floor($number); /** * Returns the absolute value of the number. * * @param string $number * * @return string */ public function absolute($number); /** * Round number, use rounding mode for tie-breaker. * * @param int|float|string $number * @param int $roundingMode * * @return string */ public function round($number, $roundingMode); /** * Share amount among ratio / total portions. * * @param string $amount * @param int|float|string $ratio * @param int|float|string $total * * @return string */ public function share($amount, $ratio, $total); /** * Get the modulus of an amount. * * @param string $amount * @param int|float|string $divisor * * @return string */ public function mod($amount, $divisor); } CHANGELOG.md 0000666 00000023743 15165570755 0006412 0 ustar 00 # Change Log All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] ## [3.3.0] - 2019-12-27 ### Changed - Added types for `Money` to be understood as pure/immutable downstream (#576) ### Fixed - JSON serialization (#551) - Several documentation fixes - Minor fixes ## [3.2.1] - 2019-02-07 ### Changed - `Money::allocate` now maintains keys of ratios array - All parsers now emit a deprecation warning when passing currency as string ### Fixed - Docs fix : plus sign in numeric strings is allowed - Added ext-json as required extension - Throw exception in case of empty currency - BCMath calculator now uses scale parameters for addition and subtracting - Fixed allocation remainder bug - Added PHP 7.3 in test suite - Fixed dockerignore to ignore Dockerfile - Fixed Bitcoin parsing bug when using trailing zeros ## [3.2.0] - 2018-12-05 ### Added - [Exchanger](https://github.com/florianv/exchanger) exchange - Generated static factory to help IDEs understand code like `Money::EUR(500)` - Aggregation functions (min, max, avg, sum) ### Changed - `Money::add` and `Money::subtract` now accept variadic arguments ### Fixed - Division causing unnecessary fractional parts - Numeric comparison for negative numbers ## [3.1.3] - 2018-02-16 ### Fixed - Allocation when the amount is smaller than the number of ratios ## [3.1.2] - 2018-02-16 ### Added - `Number::fromNumber` to be used when the actual type is not known ### Changed - Refactored `Number` usage to make the code cleaner and use less casting ### Fixed - Float cast to string issue on certain locales ## [3.1.1] - 2018-01-19 ### Fixed - Float cast to string issue on certain locales - Deal with numbers represented with E-XX ## [3.1.0] - 2018-01-10 ### Added - CurrencyList to instantiate in-memory currencies - modulus method to Money - ratioOf method to Money - Comparator for easier testing Money object with PHPUnit - IntlLocalizedDecimalParser and IntlLocalizedDecimalFormatter ### Changed - `MoneyParser::parse` method now expects a Currency object - Dropped PHP 5.5 ### Deprecated - Passing currency code as string to `MoneyParser::parse` ### Fixed - Do not allocate remainder to a ratio of zero - Conversion result is always 0 when subunit difference is large enough - Unexpected result when converting small Bitcoin amounts - Fixed StyleCI being too aggressive ## [3.0.9] - 2017-11-05 ### Fixed - Bitcoin currency symbol ## [3.0.8] - 2017-10-03 ### Fixed - Rounding issue in Number class. - Reduce composer package file size by leaving out docs and logo. - Missing Travis tests for PHP 7.2. ## [3.0.7] - 2017-08-07 ### Changed - Currencies ## [3.0.6] - 2017-07-25 ### Added - IndirectExchange: a way to get an exchange rate through a minimal set of intermediate conversions. ### Fixed - Tests for HHVM - Incorrect documentation on Bitcoin parser ## [3.0.5] - 2017-04-26 ### Added - numericCodeFor method to ISOCurrencies ## [3.0.4] - 2017-04-21 ### Added - Negative method ### Changed - Updated ISO Currencies - Removed old Belarusian ruble from ISOCurrencies (BYR) ### Fixed - ISOCurrencies will no longer have a blank currency - Double symbol when formatting negative Bitcoin amounts ## [3.0.3] - 2017-03-22 ### Fixed - Parsing empty strings and number starting or ending with a decimal point for DecimalMoneyParser - Parsing zero for DecimalMoneyParser - Multiplying and dividing with a locale that use commas as separator ## [3.0.2] - 2017-03-11 ### Fixed - BCMath / GMP: comparing values smaller than one - GMP: multiplying with zero - ISOCurrencies: minor refactoring, remove duplication of code ## [3.0.1] - 2017-02-14 ### Added - Reversed Currencies Exchange to try resolving reverse of a currency pair - Documentation on allowed integer(ish) values when constructing Money ### Fixed - Passing integer validation when chunk started with a dash - Passing integer validation when the fractional part started with a dash - Formatting problem for Bitcoin currency with small amounts in PHP < 7.0 - Money constructed from a string with fractional zeroes equals to a Money constructed without the fractional part (eg. `'5.00'` and `'5'`) ## [3.0.0] - 2016-10-26 ### Added - DecimalMoneyFormatter: returns locale-independent raw decimal string ### Changed - **[BC break]** Replaced StringToUnitsParser with DecimalMoneyParser - **[BC break]** Moved `Money\Exception\Exception` to `Money\Exception` - **[BC break]** UnkownCurrencyException is now DomainException instead of RuntimeException - **[Doctrine break]** In `Currency` the private variable `name` was renamed to `code`, which could break your Doctrine mapping if you are using embeddables or any other Reflection related implementation. ## [3.0.0-beta.3] - 2016-10-04 ### Added - FixedExchange: returns fixed exchange rates based on a list (array) ### Changed - **[BC break]** Convert method now moved to its own class: Converter - **[BC break]** Exchange had one method getCurrencyPair which is now renamed to quote - Minor documentation issues ### Fixed - Integer detection when the number overflows the integer type and contains zeros - Rounding numbers containg trailing zeros - Converting Money to currency with different number of subunits ## [3.0.0-beta.2] - 2016-08-03 ### Added - PHP Spec tests - absolute method to Money and Calculator - subunitFor method to Currencies - Currencies now extends IteratorAggregate - Library exceptions now implement a common interface - Formatter and Parser implementation are now rounding half up ### Changed - **[BC break]** Dropped PHP 5.4 support - **[BC break]** Intl and Bitcoin formatters and parsers now require Currencies - ISOCurrencies now uses moneyphp/iso-currencies as currency data source ### Fixed - Documentation to be inline with upcoming version 3 - Rounding issues in calculators with negative numbers - Formatting and parser issues for amounts and numbers with a trailing zero - Improved many exception messages - Registration of own Calculator implementations ## [3.0.0-beta] - 2016-03-01 ### Added - Bitcoin parser and formatter - Also checking tests folder for StyleCI ### Fixed - Currencies are now included in the repo - Currency list generation moved to dev dependency: reduces repo size - BC Math calculator adding and subtracting failed when bcscale was set - Parsing zero for StringToUnitsParser ## 3.0.0-alpha - 2016-02-04 ### Added - Currency repositories (ISO currencies included) - Money exchange (including [Swap](https://github.com/florianv/swap) implementation) - Money formatting (including intl formatter) - Money parsing (including intl parser) - Big integer support utilizing different, transparent calculation logic upon availability (bcmath, gmp, plain php) - Money and Currency implements JsonSerializable - Rounding up and down - Allocation to N targets ### Changed - **[BC break]** Money::getAmount() returns a string instead of an int value - **[BC break]** Moved stringToUnits to StringToUnitsParser parser - Library requires at least PHP 5.4 - Library uses PSR-4 ### Fixed - Integer overflow ### Removed - **[BC break]** UnkownCurrency exception - **[BC break]** Currency list is now provided by [umpirsky/currency-list](https://github.com/umpirsky/currency-list/) - **[BC break]** RoundingMode class - **[BC break]** Announced deprecations are removed (Currency::getName, CurrencyPair::getRatio, Money::getUnits) ## Pre 3.0 - 2015-03-23 Minimum php version is now 5.4 - 2015-03-23 JsonSerializable - (... missing changelog because who remembers to document stuff anyway?) - 2014-03-22 Removed \Money\InvalidArgumentException in favour of plain old InvalidArgumentException - 2014-03-22 Introduce RoundingMode object, used to specify desired rounding - 2014-03-22 Introduced RoundingMode backwards compatible API changes to Money::multiply and Money::divide - 2014-03-22 Allow RoundingMode to be specified when converting currencies - 2014-03-22 CurrencyPair has an equals() method - 2013-10-13 Base currency and counter currency in CurrencyPair named correctly. - 2013-01-08 Removed the Doctrine2\MoneyType helper, to be replaced by something better in the future. It's available at https://gist.github.com/4485025 in case you need it. - 2013-01-08 Use vendor/autoload.php instead of lib/bootstrap.php (or use PSR-0 autolaoding) - 2012-12-10 Renamed Money::getUnits() to Money::getAmount() [Unreleased]: https://github.com/moneyphp/money/compare/v3.3.0...HEAD [3.3.0]: https://github.com/moneyphp/money/compare/v3.2.1...v3.3.0 [3.2.1]: https://github.com/moneyphp/money/compare/v3.2.0...v3.2.1 [3.2.0]: https://github.com/moneyphp/money/compare/v3.1.3...v3.2.0 [3.1.3]: https://github.com/moneyphp/money/compare/v3.1.2...v3.1.3 [3.1.2]: https://github.com/moneyphp/money/compare/v3.1.1...v3.1.2 [3.1.1]: https://github.com/moneyphp/money/compare/v3.1.0...v3.1.1 [3.1.0]: https://github.com/moneyphp/money/compare/v3.0.9...v3.1.0 [3.0.9]: https://github.com/moneyphp/money/compare/v3.0.8...v3.0.9 [3.0.8]: https://github.com/moneyphp/money/compare/v3.0.7...v3.0.8 [3.0.7]: https://github.com/moneyphp/money/compare/v3.0.6...v3.0.7 [3.0.6]: https://github.com/moneyphp/money/compare/v3.0.5...v3.0.6 [3.0.5]: https://github.com/moneyphp/money/compare/v3.0.4...v3.0.5 [3.0.4]: https://github.com/moneyphp/money/compare/v3.0.3...v3.0.4 [3.0.3]: https://github.com/moneyphp/money/compare/v3.0.2...v3.0.3 [3.0.2]: https://github.com/moneyphp/money/compare/v3.0.1...v3.0.2 [3.0.1]: https://github.com/moneyphp/money/compare/v3.0.0...v3.0.1 [3.0.0]: https://github.com/moneyphp/money/compare/v3.0.0-beta.4...v3.0.0 [3.0.0-beta4]: https://github.com/moneyphp/money/compare/v3.0.0-beta.3...v3.0.0-beta.4 [3.0.0-beta3]: https://github.com/moneyphp/money/compare/v3.0.0-beta.2...v3.0.0-beta.3 [3.0.0-beta2]: https://github.com/moneyphp/money/compare/v3.0.0-beta...v3.0.0-beta.2 [3.0.0-beta]: https://github.com/moneyphp/money/compare/v3.0.0-alpha...v3.0.0-beta resources/currency.php 0000666 00000061400 15165570755 0011146 0 ustar 00 <?php return array ( 'AFN' => array ( 'alphabeticCode' => 'AFN', 'currency' => 'Afghani', 'minorUnit' => 2, 'numericCode' => 971, ), 'EUR' => array ( 'alphabeticCode' => 'EUR', 'currency' => 'Euro', 'minorUnit' => 2, 'numericCode' => 978, ), 'ALL' => array ( 'alphabeticCode' => 'ALL', 'currency' => 'Lek', 'minorUnit' => 2, 'numericCode' => 8, ), 'DZD' => array ( 'alphabeticCode' => 'DZD', 'currency' => 'Algerian Dinar', 'minorUnit' => 2, 'numericCode' => 12, ), 'USD' => array ( 'alphabeticCode' => 'USD', 'currency' => 'US Dollar', 'minorUnit' => 2, 'numericCode' => 840, ), 'AOA' => array ( 'alphabeticCode' => 'AOA', 'currency' => 'Kwanza', 'minorUnit' => 2, 'numericCode' => 973, ), 'XCD' => array ( 'alphabeticCode' => 'XCD', 'currency' => 'East Caribbean Dollar', 'minorUnit' => 2, 'numericCode' => 951, ), 'ARS' => array ( 'alphabeticCode' => 'ARS', 'currency' => 'Argentine Peso', 'minorUnit' => 2, 'numericCode' => 32, ), 'AMD' => array ( 'alphabeticCode' => 'AMD', 'currency' => 'Armenian Dram', 'minorUnit' => 2, 'numericCode' => 51, ), 'AWG' => array ( 'alphabeticCode' => 'AWG', 'currency' => 'Aruban Florin', 'minorUnit' => 2, 'numericCode' => 533, ), 'AUD' => array ( 'alphabeticCode' => 'AUD', 'currency' => 'Australian Dollar', 'minorUnit' => 2, 'numericCode' => 36, ), 'AZN' => array ( 'alphabeticCode' => 'AZN', 'currency' => 'Azerbaijan Manat', 'minorUnit' => 2, 'numericCode' => 944, ), 'BSD' => array ( 'alphabeticCode' => 'BSD', 'currency' => 'Bahamian Dollar', 'minorUnit' => 2, 'numericCode' => 44, ), 'BHD' => array ( 'alphabeticCode' => 'BHD', 'currency' => 'Bahraini Dinar', 'minorUnit' => 3, 'numericCode' => 48, ), 'BDT' => array ( 'alphabeticCode' => 'BDT', 'currency' => 'Taka', 'minorUnit' => 2, 'numericCode' => 50, ), 'BBD' => array ( 'alphabeticCode' => 'BBD', 'currency' => 'Barbados Dollar', 'minorUnit' => 2, 'numericCode' => 52, ), 'BYN' => array ( 'alphabeticCode' => 'BYN', 'currency' => 'Belarusian Ruble', 'minorUnit' => 2, 'numericCode' => 933, ), 'BZD' => array ( 'alphabeticCode' => 'BZD', 'currency' => 'Belize Dollar', 'minorUnit' => 2, 'numericCode' => 84, ), 'XOF' => array ( 'alphabeticCode' => 'XOF', 'currency' => 'CFA Franc BCEAO', 'minorUnit' => 0, 'numericCode' => 952, ), 'BMD' => array ( 'alphabeticCode' => 'BMD', 'currency' => 'Bermudian Dollar', 'minorUnit' => 2, 'numericCode' => 60, ), 'INR' => array ( 'alphabeticCode' => 'INR', 'currency' => 'Indian Rupee', 'minorUnit' => 2, 'numericCode' => 356, ), 'BTN' => array ( 'alphabeticCode' => 'BTN', 'currency' => 'Ngultrum', 'minorUnit' => 2, 'numericCode' => 64, ), 'BOB' => array ( 'alphabeticCode' => 'BOB', 'currency' => 'Boliviano', 'minorUnit' => 2, 'numericCode' => 68, ), 'BOV' => array ( 'alphabeticCode' => 'BOV', 'currency' => 'Mvdol', 'minorUnit' => 2, 'numericCode' => 984, ), 'BAM' => array ( 'alphabeticCode' => 'BAM', 'currency' => 'Convertible Mark', 'minorUnit' => 2, 'numericCode' => 977, ), 'BWP' => array ( 'alphabeticCode' => 'BWP', 'currency' => 'Pula', 'minorUnit' => 2, 'numericCode' => 72, ), 'NOK' => array ( 'alphabeticCode' => 'NOK', 'currency' => 'Norwegian Krone', 'minorUnit' => 2, 'numericCode' => 578, ), 'BRL' => array ( 'alphabeticCode' => 'BRL', 'currency' => 'Brazilian Real', 'minorUnit' => 2, 'numericCode' => 986, ), 'BND' => array ( 'alphabeticCode' => 'BND', 'currency' => 'Brunei Dollar', 'minorUnit' => 2, 'numericCode' => 96, ), 'BGN' => array ( 'alphabeticCode' => 'BGN', 'currency' => 'Bulgarian Lev', 'minorUnit' => 2, 'numericCode' => 975, ), 'BIF' => array ( 'alphabeticCode' => 'BIF', 'currency' => 'Burundi Franc', 'minorUnit' => 0, 'numericCode' => 108, ), 'CVE' => array ( 'alphabeticCode' => 'CVE', 'currency' => 'Cabo Verde Escudo', 'minorUnit' => 2, 'numericCode' => 132, ), 'KHR' => array ( 'alphabeticCode' => 'KHR', 'currency' => 'Riel', 'minorUnit' => 2, 'numericCode' => 116, ), 'XAF' => array ( 'alphabeticCode' => 'XAF', 'currency' => 'CFA Franc BEAC', 'minorUnit' => 0, 'numericCode' => 950, ), 'CAD' => array ( 'alphabeticCode' => 'CAD', 'currency' => 'Canadian Dollar', 'minorUnit' => 2, 'numericCode' => 124, ), 'KYD' => array ( 'alphabeticCode' => 'KYD', 'currency' => 'Cayman Islands Dollar', 'minorUnit' => 2, 'numericCode' => 136, ), 'CLP' => array ( 'alphabeticCode' => 'CLP', 'currency' => 'Chilean Peso', 'minorUnit' => 0, 'numericCode' => 152, ), 'CLF' => array ( 'alphabeticCode' => 'CLF', 'currency' => 'Unidad de Fomento', 'minorUnit' => 4, 'numericCode' => 990, ), 'CNY' => array ( 'alphabeticCode' => 'CNY', 'currency' => 'Yuan Renminbi', 'minorUnit' => 2, 'numericCode' => 156, ), 'COP' => array ( 'alphabeticCode' => 'COP', 'currency' => 'Colombian Peso', 'minorUnit' => 2, 'numericCode' => 170, ), 'COU' => array ( 'alphabeticCode' => 'COU', 'currency' => 'Unidad de Valor Real', 'minorUnit' => 2, 'numericCode' => 970, ), 'KMF' => array ( 'alphabeticCode' => 'KMF', 'currency' => 'Comorian Franc ', 'minorUnit' => 0, 'numericCode' => 174, ), 'CDF' => array ( 'alphabeticCode' => 'CDF', 'currency' => 'Congolese Franc', 'minorUnit' => 2, 'numericCode' => 976, ), 'NZD' => array ( 'alphabeticCode' => 'NZD', 'currency' => 'New Zealand Dollar', 'minorUnit' => 2, 'numericCode' => 554, ), 'CRC' => array ( 'alphabeticCode' => 'CRC', 'currency' => 'Costa Rican Colon', 'minorUnit' => 2, 'numericCode' => 188, ), 'HRK' => array ( 'alphabeticCode' => 'HRK', 'currency' => 'Kuna', 'minorUnit' => 2, 'numericCode' => 191, ), 'CUP' => array ( 'alphabeticCode' => 'CUP', 'currency' => 'Cuban Peso', 'minorUnit' => 2, 'numericCode' => 192, ), 'CUC' => array ( 'alphabeticCode' => 'CUC', 'currency' => 'Peso Convertible', 'minorUnit' => 2, 'numericCode' => 931, ), 'ANG' => array ( 'alphabeticCode' => 'ANG', 'currency' => 'Netherlands Antillean Guilder', 'minorUnit' => 2, 'numericCode' => 532, ), 'CZK' => array ( 'alphabeticCode' => 'CZK', 'currency' => 'Czech Koruna', 'minorUnit' => 2, 'numericCode' => 203, ), 'DKK' => array ( 'alphabeticCode' => 'DKK', 'currency' => 'Danish Krone', 'minorUnit' => 2, 'numericCode' => 208, ), 'DJF' => array ( 'alphabeticCode' => 'DJF', 'currency' => 'Djibouti Franc', 'minorUnit' => 0, 'numericCode' => 262, ), 'DOP' => array ( 'alphabeticCode' => 'DOP', 'currency' => 'Dominican Peso', 'minorUnit' => 2, 'numericCode' => 214, ), 'EGP' => array ( 'alphabeticCode' => 'EGP', 'currency' => 'Egyptian Pound', 'minorUnit' => 2, 'numericCode' => 818, ), 'SVC' => array ( 'alphabeticCode' => 'SVC', 'currency' => 'El Salvador Colon', 'minorUnit' => 2, 'numericCode' => 222, ), 'ERN' => array ( 'alphabeticCode' => 'ERN', 'currency' => 'Nakfa', 'minorUnit' => 2, 'numericCode' => 232, ), 'ETB' => array ( 'alphabeticCode' => 'ETB', 'currency' => 'Ethiopian Birr', 'minorUnit' => 2, 'numericCode' => 230, ), 'FKP' => array ( 'alphabeticCode' => 'FKP', 'currency' => 'Falkland Islands Pound', 'minorUnit' => 2, 'numericCode' => 238, ), 'FJD' => array ( 'alphabeticCode' => 'FJD', 'currency' => 'Fiji Dollar', 'minorUnit' => 2, 'numericCode' => 242, ), 'XPF' => array ( 'alphabeticCode' => 'XPF', 'currency' => 'CFP Franc', 'minorUnit' => 0, 'numericCode' => 953, ), 'GMD' => array ( 'alphabeticCode' => 'GMD', 'currency' => 'Dalasi', 'minorUnit' => 2, 'numericCode' => 270, ), 'GEL' => array ( 'alphabeticCode' => 'GEL', 'currency' => 'Lari', 'minorUnit' => 2, 'numericCode' => 981, ), 'GHS' => array ( 'alphabeticCode' => 'GHS', 'currency' => 'Ghana Cedi', 'minorUnit' => 2, 'numericCode' => 936, ), 'GIP' => array ( 'alphabeticCode' => 'GIP', 'currency' => 'Gibraltar Pound', 'minorUnit' => 2, 'numericCode' => 292, ), 'GTQ' => array ( 'alphabeticCode' => 'GTQ', 'currency' => 'Quetzal', 'minorUnit' => 2, 'numericCode' => 320, ), 'GBP' => array ( 'alphabeticCode' => 'GBP', 'currency' => 'Pound Sterling', 'minorUnit' => 2, 'numericCode' => 826, ), 'GNF' => array ( 'alphabeticCode' => 'GNF', 'currency' => 'Guinean Franc', 'minorUnit' => 0, 'numericCode' => 324, ), 'GYD' => array ( 'alphabeticCode' => 'GYD', 'currency' => 'Guyana Dollar', 'minorUnit' => 2, 'numericCode' => 328, ), 'HTG' => array ( 'alphabeticCode' => 'HTG', 'currency' => 'Gourde', 'minorUnit' => 2, 'numericCode' => 332, ), 'HNL' => array ( 'alphabeticCode' => 'HNL', 'currency' => 'Lempira', 'minorUnit' => 2, 'numericCode' => 340, ), 'HKD' => array ( 'alphabeticCode' => 'HKD', 'currency' => 'Hong Kong Dollar', 'minorUnit' => 2, 'numericCode' => 344, ), 'HUF' => array ( 'alphabeticCode' => 'HUF', 'currency' => 'Forint', 'minorUnit' => 2, 'numericCode' => 348, ), 'ISK' => array ( 'alphabeticCode' => 'ISK', 'currency' => 'Iceland Krona', 'minorUnit' => 0, 'numericCode' => 352, ), 'IDR' => array ( 'alphabeticCode' => 'IDR', 'currency' => 'Rupiah', 'minorUnit' => 2, 'numericCode' => 360, ), 'XDR' => array ( 'alphabeticCode' => 'XDR', 'currency' => 'SDR (Special Drawing Right)', 'minorUnit' => 0, 'numericCode' => 960, ), 'IRR' => array ( 'alphabeticCode' => 'IRR', 'currency' => 'Iranian Rial', 'minorUnit' => 2, 'numericCode' => 364, ), 'IQD' => array ( 'alphabeticCode' => 'IQD', 'currency' => 'Iraqi Dinar', 'minorUnit' => 3, 'numericCode' => 368, ), 'ILS' => array ( 'alphabeticCode' => 'ILS', 'currency' => 'New Israeli Sheqel', 'minorUnit' => 2, 'numericCode' => 376, ), 'JMD' => array ( 'alphabeticCode' => 'JMD', 'currency' => 'Jamaican Dollar', 'minorUnit' => 2, 'numericCode' => 388, ), 'JPY' => array ( 'alphabeticCode' => 'JPY', 'currency' => 'Yen', 'minorUnit' => 0, 'numericCode' => 392, ), 'JOD' => array ( 'alphabeticCode' => 'JOD', 'currency' => 'Jordanian Dinar', 'minorUnit' => 3, 'numericCode' => 400, ), 'KZT' => array ( 'alphabeticCode' => 'KZT', 'currency' => 'Tenge', 'minorUnit' => 2, 'numericCode' => 398, ), 'KES' => array ( 'alphabeticCode' => 'KES', 'currency' => 'Kenyan Shilling', 'minorUnit' => 2, 'numericCode' => 404, ), 'KPW' => array ( 'alphabeticCode' => 'KPW', 'currency' => 'North Korean Won', 'minorUnit' => 2, 'numericCode' => 408, ), 'KRW' => array ( 'alphabeticCode' => 'KRW', 'currency' => 'Won', 'minorUnit' => 0, 'numericCode' => 410, ), 'KWD' => array ( 'alphabeticCode' => 'KWD', 'currency' => 'Kuwaiti Dinar', 'minorUnit' => 3, 'numericCode' => 414, ), 'KGS' => array ( 'alphabeticCode' => 'KGS', 'currency' => 'Som', 'minorUnit' => 2, 'numericCode' => 417, ), 'LAK' => array ( 'alphabeticCode' => 'LAK', 'currency' => 'Lao Kip', 'minorUnit' => 2, 'numericCode' => 418, ), 'LBP' => array ( 'alphabeticCode' => 'LBP', 'currency' => 'Lebanese Pound', 'minorUnit' => 2, 'numericCode' => 422, ), 'LSL' => array ( 'alphabeticCode' => 'LSL', 'currency' => 'Loti', 'minorUnit' => 2, 'numericCode' => 426, ), 'ZAR' => array ( 'alphabeticCode' => 'ZAR', 'currency' => 'Rand', 'minorUnit' => 2, 'numericCode' => 710, ), 'LRD' => array ( 'alphabeticCode' => 'LRD', 'currency' => 'Liberian Dollar', 'minorUnit' => 2, 'numericCode' => 430, ), 'LYD' => array ( 'alphabeticCode' => 'LYD', 'currency' => 'Libyan Dinar', 'minorUnit' => 3, 'numericCode' => 434, ), 'CHF' => array ( 'alphabeticCode' => 'CHF', 'currency' => 'Swiss Franc', 'minorUnit' => 2, 'numericCode' => 756, ), 'MOP' => array ( 'alphabeticCode' => 'MOP', 'currency' => 'Pataca', 'minorUnit' => 2, 'numericCode' => 446, ), 'MKD' => array ( 'alphabeticCode' => 'MKD', 'currency' => 'Denar', 'minorUnit' => 2, 'numericCode' => 807, ), 'MGA' => array ( 'alphabeticCode' => 'MGA', 'currency' => 'Malagasy Ariary', 'minorUnit' => 2, 'numericCode' => 969, ), 'MWK' => array ( 'alphabeticCode' => 'MWK', 'currency' => 'Malawi Kwacha', 'minorUnit' => 2, 'numericCode' => 454, ), 'MYR' => array ( 'alphabeticCode' => 'MYR', 'currency' => 'Malaysian Ringgit', 'minorUnit' => 2, 'numericCode' => 458, ), 'MVR' => array ( 'alphabeticCode' => 'MVR', 'currency' => 'Rufiyaa', 'minorUnit' => 2, 'numericCode' => 462, ), 'MRU' => array ( 'alphabeticCode' => 'MRU', 'currency' => 'Ouguiya', 'minorUnit' => 2, 'numericCode' => 929, ), 'MUR' => array ( 'alphabeticCode' => 'MUR', 'currency' => 'Mauritius Rupee', 'minorUnit' => 2, 'numericCode' => 480, ), 'XUA' => array ( 'alphabeticCode' => 'XUA', 'currency' => 'ADB Unit of Account', 'minorUnit' => 0, 'numericCode' => 965, ), 'MXN' => array ( 'alphabeticCode' => 'MXN', 'currency' => 'Mexican Peso', 'minorUnit' => 2, 'numericCode' => 484, ), 'MXV' => array ( 'alphabeticCode' => 'MXV', 'currency' => 'Mexican Unidad de Inversion (UDI)', 'minorUnit' => 2, 'numericCode' => 979, ), 'MDL' => array ( 'alphabeticCode' => 'MDL', 'currency' => 'Moldovan Leu', 'minorUnit' => 2, 'numericCode' => 498, ), 'MNT' => array ( 'alphabeticCode' => 'MNT', 'currency' => 'Tugrik', 'minorUnit' => 2, 'numericCode' => 496, ), 'MAD' => array ( 'alphabeticCode' => 'MAD', 'currency' => 'Moroccan Dirham', 'minorUnit' => 2, 'numericCode' => 504, ), 'MZN' => array ( 'alphabeticCode' => 'MZN', 'currency' => 'Mozambique Metical', 'minorUnit' => 2, 'numericCode' => 943, ), 'MMK' => array ( 'alphabeticCode' => 'MMK', 'currency' => 'Kyat', 'minorUnit' => 2, 'numericCode' => 104, ), 'NAD' => array ( 'alphabeticCode' => 'NAD', 'currency' => 'Namibia Dollar', 'minorUnit' => 2, 'numericCode' => 516, ), 'NPR' => array ( 'alphabeticCode' => 'NPR', 'currency' => 'Nepalese Rupee', 'minorUnit' => 2, 'numericCode' => 524, ), 'NIO' => array ( 'alphabeticCode' => 'NIO', 'currency' => 'Cordoba Oro', 'minorUnit' => 2, 'numericCode' => 558, ), 'NGN' => array ( 'alphabeticCode' => 'NGN', 'currency' => 'Naira', 'minorUnit' => 2, 'numericCode' => 566, ), 'OMR' => array ( 'alphabeticCode' => 'OMR', 'currency' => 'Rial Omani', 'minorUnit' => 3, 'numericCode' => 512, ), 'PKR' => array ( 'alphabeticCode' => 'PKR', 'currency' => 'Pakistan Rupee', 'minorUnit' => 2, 'numericCode' => 586, ), 'PAB' => array ( 'alphabeticCode' => 'PAB', 'currency' => 'Balboa', 'minorUnit' => 2, 'numericCode' => 590, ), 'PGK' => array ( 'alphabeticCode' => 'PGK', 'currency' => 'Kina', 'minorUnit' => 2, 'numericCode' => 598, ), 'PYG' => array ( 'alphabeticCode' => 'PYG', 'currency' => 'Guarani', 'minorUnit' => 0, 'numericCode' => 600, ), 'PEN' => array ( 'alphabeticCode' => 'PEN', 'currency' => 'Sol', 'minorUnit' => 2, 'numericCode' => 604, ), 'PHP' => array ( 'alphabeticCode' => 'PHP', 'currency' => 'Philippine Peso', 'minorUnit' => 2, 'numericCode' => 608, ), 'PLN' => array ( 'alphabeticCode' => 'PLN', 'currency' => 'Zloty', 'minorUnit' => 2, 'numericCode' => 985, ), 'QAR' => array ( 'alphabeticCode' => 'QAR', 'currency' => 'Qatari Rial', 'minorUnit' => 2, 'numericCode' => 634, ), 'RON' => array ( 'alphabeticCode' => 'RON', 'currency' => 'Romanian Leu', 'minorUnit' => 2, 'numericCode' => 946, ), 'RUB' => array ( 'alphabeticCode' => 'RUB', 'currency' => 'Russian Ruble', 'minorUnit' => 2, 'numericCode' => 643, ), 'RWF' => array ( 'alphabeticCode' => 'RWF', 'currency' => 'Rwanda Franc', 'minorUnit' => 0, 'numericCode' => 646, ), 'SHP' => array ( 'alphabeticCode' => 'SHP', 'currency' => 'Saint Helena Pound', 'minorUnit' => 2, 'numericCode' => 654, ), 'WST' => array ( 'alphabeticCode' => 'WST', 'currency' => 'Tala', 'minorUnit' => 2, 'numericCode' => 882, ), 'STN' => array ( 'alphabeticCode' => 'STN', 'currency' => 'Dobra', 'minorUnit' => 2, 'numericCode' => 930, ), 'SAR' => array ( 'alphabeticCode' => 'SAR', 'currency' => 'Saudi Riyal', 'minorUnit' => 2, 'numericCode' => 682, ), 'RSD' => array ( 'alphabeticCode' => 'RSD', 'currency' => 'Serbian Dinar', 'minorUnit' => 2, 'numericCode' => 941, ), 'SCR' => array ( 'alphabeticCode' => 'SCR', 'currency' => 'Seychelles Rupee', 'minorUnit' => 2, 'numericCode' => 690, ), 'SLL' => array ( 'alphabeticCode' => 'SLL', 'currency' => 'Leone', 'minorUnit' => 2, 'numericCode' => 694, ), 'SGD' => array ( 'alphabeticCode' => 'SGD', 'currency' => 'Singapore Dollar', 'minorUnit' => 2, 'numericCode' => 702, ), 'XSU' => array ( 'alphabeticCode' => 'XSU', 'currency' => 'Sucre', 'minorUnit' => 0, 'numericCode' => 994, ), 'SBD' => array ( 'alphabeticCode' => 'SBD', 'currency' => 'Solomon Islands Dollar', 'minorUnit' => 2, 'numericCode' => 90, ), 'SOS' => array ( 'alphabeticCode' => 'SOS', 'currency' => 'Somali Shilling', 'minorUnit' => 2, 'numericCode' => 706, ), 'SSP' => array ( 'alphabeticCode' => 'SSP', 'currency' => 'South Sudanese Pound', 'minorUnit' => 2, 'numericCode' => 728, ), 'LKR' => array ( 'alphabeticCode' => 'LKR', 'currency' => 'Sri Lanka Rupee', 'minorUnit' => 2, 'numericCode' => 144, ), 'SDG' => array ( 'alphabeticCode' => 'SDG', 'currency' => 'Sudanese Pound', 'minorUnit' => 2, 'numericCode' => 938, ), 'SRD' => array ( 'alphabeticCode' => 'SRD', 'currency' => 'Surinam Dollar', 'minorUnit' => 2, 'numericCode' => 968, ), 'SZL' => array ( 'alphabeticCode' => 'SZL', 'currency' => 'Lilangeni', 'minorUnit' => 2, 'numericCode' => 748, ), 'SEK' => array ( 'alphabeticCode' => 'SEK', 'currency' => 'Swedish Krona', 'minorUnit' => 2, 'numericCode' => 752, ), 'CHE' => array ( 'alphabeticCode' => 'CHE', 'currency' => 'WIR Euro', 'minorUnit' => 2, 'numericCode' => 947, ), 'CHW' => array ( 'alphabeticCode' => 'CHW', 'currency' => 'WIR Franc', 'minorUnit' => 2, 'numericCode' => 948, ), 'SYP' => array ( 'alphabeticCode' => 'SYP', 'currency' => 'Syrian Pound', 'minorUnit' => 2, 'numericCode' => 760, ), 'TWD' => array ( 'alphabeticCode' => 'TWD', 'currency' => 'New Taiwan Dollar', 'minorUnit' => 2, 'numericCode' => 901, ), 'TJS' => array ( 'alphabeticCode' => 'TJS', 'currency' => 'Somoni', 'minorUnit' => 2, 'numericCode' => 972, ), 'TZS' => array ( 'alphabeticCode' => 'TZS', 'currency' => 'Tanzanian Shilling', 'minorUnit' => 2, 'numericCode' => 834, ), 'THB' => array ( 'alphabeticCode' => 'THB', 'currency' => 'Baht', 'minorUnit' => 2, 'numericCode' => 764, ), 'TOP' => array ( 'alphabeticCode' => 'TOP', 'currency' => 'Pa’anga', 'minorUnit' => 2, 'numericCode' => 776, ), 'TTD' => array ( 'alphabeticCode' => 'TTD', 'currency' => 'Trinidad and Tobago Dollar', 'minorUnit' => 2, 'numericCode' => 780, ), 'TND' => array ( 'alphabeticCode' => 'TND', 'currency' => 'Tunisian Dinar', 'minorUnit' => 3, 'numericCode' => 788, ), 'TRY' => array ( 'alphabeticCode' => 'TRY', 'currency' => 'Turkish Lira', 'minorUnit' => 2, 'numericCode' => 949, ), 'TMT' => array ( 'alphabeticCode' => 'TMT', 'currency' => 'Turkmenistan New Manat', 'minorUnit' => 2, 'numericCode' => 934, ), 'UGX' => array ( 'alphabeticCode' => 'UGX', 'currency' => 'Uganda Shilling', 'minorUnit' => 0, 'numericCode' => 800, ), 'UAH' => array ( 'alphabeticCode' => 'UAH', 'currency' => 'Hryvnia', 'minorUnit' => 2, 'numericCode' => 980, ), 'AED' => array ( 'alphabeticCode' => 'AED', 'currency' => 'UAE Dirham', 'minorUnit' => 2, 'numericCode' => 784, ), 'USN' => array ( 'alphabeticCode' => 'USN', 'currency' => 'US Dollar (Next day)', 'minorUnit' => 2, 'numericCode' => 997, ), 'UYU' => array ( 'alphabeticCode' => 'UYU', 'currency' => 'Peso Uruguayo', 'minorUnit' => 2, 'numericCode' => 858, ), 'UYI' => array ( 'alphabeticCode' => 'UYI', 'currency' => 'Uruguay Peso en Unidades Indexadas (UI)', 'minorUnit' => 0, 'numericCode' => 940, ), 'UYW' => array ( 'alphabeticCode' => 'UYW', 'currency' => 'Unidad Previsional', 'minorUnit' => 4, 'numericCode' => 927, ), 'UZS' => array ( 'alphabeticCode' => 'UZS', 'currency' => 'Uzbekistan Sum', 'minorUnit' => 2, 'numericCode' => 860, ), 'VUV' => array ( 'alphabeticCode' => 'VUV', 'currency' => 'Vatu', 'minorUnit' => 0, 'numericCode' => 548, ), 'VES' => array ( 'alphabeticCode' => 'VES', 'currency' => 'Bolívar Soberano', 'minorUnit' => 2, 'numericCode' => 928, ), 'VND' => array ( 'alphabeticCode' => 'VND', 'currency' => 'Dong', 'minorUnit' => 0, 'numericCode' => 704, ), 'YER' => array ( 'alphabeticCode' => 'YER', 'currency' => 'Yemeni Rial', 'minorUnit' => 2, 'numericCode' => 886, ), 'ZMW' => array ( 'alphabeticCode' => 'ZMW', 'currency' => 'Zambian Kwacha', 'minorUnit' => 2, 'numericCode' => 967, ), 'ZWL' => array ( 'alphabeticCode' => 'ZWL', 'currency' => 'Zimbabwe Dollar', 'minorUnit' => 2, 'numericCode' => 932, ), 'XBA' => array ( 'alphabeticCode' => 'XBA', 'currency' => 'Bond Markets Unit European Composite Unit (EURCO)', 'minorUnit' => 0, 'numericCode' => 955, ), 'XBB' => array ( 'alphabeticCode' => 'XBB', 'currency' => 'Bond Markets Unit European Monetary Unit (E.M.U.-6)', 'minorUnit' => 0, 'numericCode' => 956, ), 'XBC' => array ( 'alphabeticCode' => 'XBC', 'currency' => 'Bond Markets Unit European Unit of Account 9 (E.U.A.-9)', 'minorUnit' => 0, 'numericCode' => 957, ), 'XBD' => array ( 'alphabeticCode' => 'XBD', 'currency' => 'Bond Markets Unit European Unit of Account 17 (E.U.A.-17)', 'minorUnit' => 0, 'numericCode' => 958, ), 'XTS' => array ( 'alphabeticCode' => 'XTS', 'currency' => 'Codes specifically reserved for testing purposes', 'minorUnit' => 0, 'numericCode' => 963, ), 'XXX' => array ( 'alphabeticCode' => 'XXX', 'currency' => 'The codes assigned for transactions where no currency is involved', 'minorUnit' => 0, 'numericCode' => 999, ), 'XAU' => array ( 'alphabeticCode' => 'XAU', 'currency' => 'Gold', 'minorUnit' => 0, 'numericCode' => 959, ), 'XPD' => array ( 'alphabeticCode' => 'XPD', 'currency' => 'Palladium', 'minorUnit' => 0, 'numericCode' => 964, ), 'XPT' => array ( 'alphabeticCode' => 'XPT', 'currency' => 'Platinum', 'minorUnit' => 0, 'numericCode' => 962, ), 'XAG' => array ( 'alphabeticCode' => 'XAG', 'currency' => 'Silver', 'minorUnit' => 0, 'numericCode' => 961, ), ); resources/generate-money-factory.php 0000666 00000002451 15165570755 0013701 0 ustar 00 <?php require __DIR__.'/../vendor/autoload.php'; use Money\Currencies; $buffer = <<<PHP <?php namespace Money; /** * This is a generated file. Do not edit it manually! * PHPDOC */ trait MoneyFactory { /** * Convenience factory method for a Money object. * * <code> * \$fiveDollar = Money::USD(500); * </code> * * @param string \$method * @param array \$arguments * * @return Money * * @throws \InvalidArgumentException If amount is not integer(ish) */ public static function __callStatic(\$method, \$arguments) { return new Money(\$arguments[0], new Currency(\$method)); } } PHP; $methodBuffer = ''; $currencies = new Currencies\AggregateCurrencies([ new Currencies\ISOCurrencies(), new Currencies\BitcoinCurrencies(), ]); $currencies = iterator_to_array($currencies); usort($currencies, function (\Money\Currency $a, \Money\Currency $b) { return strcmp($a->getCode(), $b->getCode()); }); /** @var \Money\Currency[] $currencies */ foreach ($currencies as $currency) { $methodBuffer .= sprintf(" * @method static Money %s(string|int \$amount)\n", $currency->getCode()); } $buffer = str_replace('PHPDOC', rtrim($methodBuffer), $buffer); file_put_contents(__DIR__.'/../src/MoneyFactory.php', $buffer); LICENSE 0000666 00000002237 15165570755 0005601 0 ustar 00 Copyright (c) 2011-2016 Mathias Verraes Copyright (c) 2016 Márk Sági-Kazár <mark.sagikazar@gmail.com> Copyright (c) 2016 Frederik Bosch <f.bosch@genkgo.nl> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. composer.json 0000666 00000005157 15165570755 0007322 0 ustar 00 { "name": "moneyphp/money", "description": "PHP implementation of Fowler's Money pattern", "keywords": [ "money", "vo", "value object" ], "homepage": "http://moneyphp.org", "license": "MIT", "authors": [ { "name": "Mathias Verraes", "email": "mathias@verraes.net", "homepage": "http://verraes.net" }, { "name": "Márk Sági-Kazár", "email": "mark.sagikazar@gmail.com" }, { "name": "Frederik Bosch", "email": "f.bosch@genkgo.nl" } ], "require": { "php": ">=5.6", "ext-json": "*" }, "require-dev": { "ext-bcmath": "*", "ext-gmp": "*", "ext-intl": "*", "cache/taggable-cache": "^0.4.0", "doctrine/instantiator": "^1.0.5", "florianv/exchanger": "^1.0", "florianv/swap": "^3.0", "friends-of-phpspec/phpspec-code-coverage": "^3.1.1 || ^4.3", "moneyphp/iso-currencies": "^3.2.1", "php-http/message": "^1.4", "php-http/mock-client": "^1.0.0", "phpspec/phpspec": "^3.4.3", "phpunit/phpunit": "^5.7.27 || ^6.5.14 || ^7.5.18 || ^8.5", "psr/cache": "^1.0", "symfony/phpunit-bridge": "^4" }, "suggest": { "ext-bcmath": "Calculate without integer limits", "ext-gmp": "Calculate without integer limits", "ext-intl": "Format Money objects with intl", "florianv/exchanger": "Exchange rates library for PHP", "florianv/swap": "Exchange rates library for PHP", "psr/cache-implementation": "Used for Currency caching" }, "config": { "sort-packages": true }, "extra": { "branch-alias": { "dev-master": "3.x-dev" } }, "autoload": { "psr-4": { "Money\\": "src/" } }, "autoload-dev": { "psr-4": { "Tests\\Money\\": "tests/", "spec\\Money\\": "spec/" } }, "minimum-stability": "dev", "prefer-stable": true, "scripts": { "clean": "rm -rf build/ vendor/", "test": [ "vendor/bin/phpspec run", "vendor/bin/phpunit -v" ], "test-coverage": [ "vendor/bin/phpspec run -c phpspec.ci.yml", "vendor/bin/phpunit -v --coverage-text --coverage-clover=build/unit_coverage.xml" ], "update-currencies": [ "cp vendor/moneyphp/iso-currencies/resources/current.php resources/currency.php", "php resources/generate-money-factory.php" ] } }
| ver. 1.4 |
Github
|
.
| PHP 5.4.45 | Generation time: 0.01 |
proxy
|
phpinfo
|
Settings