Value Object that represents a monetary value (using a currency's smallest unit).

Related tags

E-commerce money
Overview

This project has been abandoned. It was only ever intended to be used as an example for PHPUnit features etc. and not for usage in production. I am sorry that I failed to make that clear. Please have a look at moneyphp/money instead.

Money

Value Object that represents a monetary value using a currency's smallest unit.

Installation

Simply add a dependency on sebastian/money to your project's composer.json file if you use Composer to manage the dependencies of your project.

Here is a minimal example of a composer.json file that just defines a dependency on Money:

{
    "require": {
        "sebastian/money": "^1.6"
    }
}

Usage Examples

Creating a Money object and accessing its monetary value

use SebastianBergmann\Money\Currency;
use SebastianBergmann\Money\Money;

// Create Money object that represents 1 EUR
$m = new Money(100, new Currency('EUR'));

// Access the Money object's monetary value
print $m->getAmount();

// Access the Money object's monetary value converted to its base units
print $m->getConvertedAmount();

The code above produces the output shown below:

100

1.00

Creating a Money object from a string value

use SebastianBergmann\Money\Currency;
use SebastianBergmann\Money\Money;

// Create Money object that represents 12.34 EUR
$m = Money::fromString('12.34', new Currency('EUR'))

// Access the Money object's monetary value
print $m->getAmount();

The code above produces the output shown below:

1234

Using a Currency-specific subclass of Money

use SebastianBergmann\Money\EUR;

// Create Money object that represents 1 EUR
$m = new EUR(100);

// Access the Money object's monetary value
print $m->getAmount();

The code above produces the output shown below:

100

Please note that there is no subclass of Money that is specific to Turkish Lira as TRY is not a valid class name in PHP.

Formatting a Money object using PHP's built-in NumberFormatter

use SebastianBergmann\Money\Currency;
use SebastianBergmann\Money\Money;
use SebastianBergmann\Money\IntlFormatter;

// Create Money object that represents 1 EUR
$m = new Money(100, new Currency('EUR'));

// Format a Money object using PHP's built-in NumberFormatter (German locale)
$f = new IntlFormatter('de_DE');

print $f->format($m);

The code above produces the output shown below:

1,00 €

Basic arithmetic using Money objects

use SebastianBergmann\Money\Currency;
use SebastianBergmann\Money\Money;

// Create two Money objects that represent 1 EUR and 2 EUR, respectively
$a = new Money(100, new Currency('EUR'));
$b = new Money(200, new Currency('EUR'));

// Negate a Money object
$c = $a->negate();
print $c->getAmount();

// Calculate the sum of two Money objects
$c = $a->add($b);
print $c->getAmount();

// Calculate the difference of two Money objects
$c = $b->subtract($a);
print $c->getAmount();

// Multiply a Money object with a factor
$c = $a->multiply(2);
print $c->getAmount();

The code above produces the output shown below:

-100
300
100
200

Comparing Money objects

use SebastianBergmann\Money\Currency;
use SebastianBergmann\Money\Money;

// Create two Money objects that represent 1 EUR and 2 EUR, respectively
$a = new Money(100, new Currency('EUR'));
$b = new Money(200, new Currency('EUR'));

var_dump($a->lessThan($b));
var_dump($a->greaterThan($b));

var_dump($b->lessThan($a));
var_dump($b->greaterThan($a));

var_dump($a->compareTo($b));
var_dump($a->compareTo($a));
var_dump($b->compareTo($a));

The code above produces the output shown below:

bool(true)
bool(false)
bool(false)
bool(true)
int(-1)
int(0)
int(1)

The compareTo() method returns an integer less than, equal to, or greater than zero if the value of one Money object is considered to be respectively less than, equal to, or greater than that of another Money object.

You can use the compareTo() method to sort an array of Money objects using PHP's built-in sorting functions:

use SebastianBergmann\Money\Currency;
use SebastianBergmann\Money\Money;

$m = array(
    new Money(300, new Currency('EUR')),
    new Money(100, new Currency('EUR')),
    new Money(200, new Currency('EUR'))
);

usort(
    $m,
    function ($a, $b) { return $a->compareTo($b); }
);

foreach ($m as $_m) {
    print $_m->getAmount() . "\n";
}

The code above produces the output shown below:

100
200
300

Allocate the monetary value represented by a Money object among N targets

use SebastianBergmann\Money\Currency;
use SebastianBergmann\Money\Money;

// Create a Money object that represents 0,99 EUR
$a = new Money(99, new Currency('EUR'));

foreach ($a->allocateToTargets(10) as $t) {
    print $t->getAmount() . "\n";
}

The code above produces the output shown below:

10
10
10
10
10
10
10
10
10
9

Allocate the monetary value represented by a Money object using a list of ratios

use SebastianBergmann\Money\Currency;
use SebastianBergmann\Money\Money;

// Create a Money object that represents 0,05 EUR
$a = new Money(5, new Currency('EUR'));

foreach ($a->allocateByRatios(array(3, 7)) as $t) {
    print $t->getAmount() . "\n";
}

The code above produces the output shown below:

2
3

Extract a percentage (and a subtotal) from the monetary value represented by a Money object

use SebastianBergmann\Money\Currency;
use SebastianBergmann\Money\Money;

// Create a Money object that represents 100,00 EUR
$original = new Money(10000, new Currency('EUR'));

// Extract 21% (and the corresponding subtotal)
$extract = $original->extractPercentage(21);

printf(
    "%d = %d + %d\n",
    $original->getAmount(),
    $extract['subtotal']->getAmount(),
    $extract['percentage']->getAmount()
);

The code above produces the output shown below:

10000 = 8265 + 1735

Please note that this extracts the percentage out of a monetary value where the percentage is already included. If you want to get the percentage of the monetary value you should use multiplication (multiply(0.21), for instance, to calculate 21% of a monetary value represented by a Money object) instead.

Comments
  • Added divide method and changed private properties/methods to protected

    Added divide method and changed private properties/methods to protected

    I've added a divide method to the Money class and set all private properties and methods to protected to allow for easier extension. I also added unit tests for the divide method.

    Since the rounding mode exception can be thrown now from 2 locations (multiply, divide) I have extracted it to a new protected method assertValidRoundingMode.

    Just noticed that git seems to have cut my commit messages off after the first word. Not sure what's going on there...

    opened by boris-glumpler 6
  • New currency pair functionality for currency conversion

    New currency pair functionality for currency conversion

    Also includes new rounding mode functionality to correctly handle multiplication and division in currency conversions.

    This is a proposal as much as it is a PR.

    opened by camspiers 5
  • Add Currency::getCurrencies() to access registered currencies

    Add Currency::getCurrencies() to access registered currencies

    This could be useful if you want to list supported currencies.

    I think it would be better than doing this: https://github.com/sebastianbergmann/money/blob/b1f97e9f7da4a625027798cb8cb9c856a2fcde07/build/generate-child-classes.php#L15-L17

    opened by hkdobrev 3
  • Throw more informative exceptions when addition and subtract cause overflow

    Throw more informative exceptions when addition and subtract cause overflow

    Currently an InvalidArgumentException is thrown during overflow causing addition and subtract.

    This exception type is not very informative, and because it is an internal operation that is causing it, a more informative exception should be thrown.

    With this change, where it is expected that an operation should produce an integer, when it doesn't the Money object now throws an OverflowException

    opened by camspiers 3
  • Remove currencies

    Remove currencies

    is a Euro a currency or a money?

    The way this package is currently setup, it is both. EUR extends Money, but then the currency property of the object can also be a Euro. IMHO, it should not be both. I believe a Euro is a type of currency, and that a Money should be comprised of a 'value' and a 'currency'. i believe there is confusion when it is treated as both.

    This PR removes all of the subclasses of Money. This accomplishes a couple things.

    • makes the class cleaner, WITHOUT losing functionality
    • reduce complexity, which helps avoid bugs
    • smaller footprint
    • simpler autoloader.
    • simpler (no) build process, no need generate money subclasses from template
    • easier to swap out currencies or use multiple currencies. don't need to use every subclass, simply use the Money class.

    There are actually no tests (as far as I could tell) to make sure the subclasses worked correctly either.

    How does this affect the user? Obviously this causes breaking changes, but all it means is the user must switch calls of new EUR(100) to new Money(100, 'eur').

    This is a breaking change, so it would have to be released with a major version.

    opened by browner12 2
  • accept different amount types, and either base units or subunits

    accept different amount types, and either base units or subunits

    sorry for the size of this PR, but it was difficult to break it down into smaller parts, as they were all very intertwined.

    This PR attempts to address 3 issues:

    1. consolidate creation of a Money object.
    2. allow user to pass any type of numeric variable to create a Money object.
    3. be explicit whether amount passed is in the currencies base units (i.e dollars) or subunits (cents)

    1 - currently users can create a Money object 1 of 2 ways:

    • through the constructor
    • through the ::fromString() static method

    Ideally the user would create all Money objects through the constructor. this enforces one point of entry, and can help prevent inconsistencies in the way the object is created. i realize the fromString method was put in place to address a specific problem, but that is addressed in number 2 below

    2 - currently the user can create a Money object by passing an integer to the constructor, or passing a string to the static ::fromString() method. this means the Money object cannot be created from a float. All three of these variable types are legitimate userland occurrences, and Money should be capable of handling all of them. this puts the responsibility on Money and takes it off the user, and allows for more consistency and fewer errors. the new setAmount method is capable of handling all of these types, but will also throw an exception (as it did before) if it is passed something it does not know how to handle (for example, a non-numeric string). Internally the value will still be stored as an integer, but this method is Moneys way of converting the input to that integer.

    Why do we need this? While it would be great if we'd only get integers, no one is ever that lucky in the real world. we have input coming in from many sources (client, database, 3rd party API). this takes the burden off the users to convert their variables to an appropriate type, and places the burden appropriately on the Money object.

    3 - currently there is some inconsistency between the value set when using the constructor and when using the ::fromString() method. for example

    $usingConstructor = new Money(1234, 'usd');
    $usingMethod = Money::fromString('1234', 'usd');
    
    echo $usingConstructor->getAmount();     // 1234
    echo $usingMethod->getAmount();           // 123400
    

    this is because the ::fromString() method multiplies the input by the currencies getSubunit() value, which in the case of the USD is 100. this implicit behavior is not immediately apparent to the user, and is liable to cause confusion. a more consistent implementation would be to allow the user to explicitly declare if they would like the input value treated as if it were the currencies base units. this is made possible by the 3rd constructor parameter called convert. it is a boolean value, and has a default value of false. this means by default the value is treated as the currencies subunits, but can be overridden.

    Why do we need this? Obviously ideally we would handle everything in subunits, but there are many cases, like when dealing with 3rd party APIs, that we are given a value in base units rather than subunits. One specific example is the Easypost Shipping API, which returns a float value in dollars (i.e. 1.23). while we could leave this up to the user, again we can provide consistency by internalizing this responsibility to the Money value object.

    how does this affect the public API?

    • fromString() method will be deprecated, in favor of constructor instantiation
    • 3rd optional parameter on the constructor

    again, sorry for the length. thanks for checking this out, and let me know if you have any questions or comments.

    opened by browner12 2
  • create method to retrieve amount converted to base units

    create method to retrieve amount converted to base units

    getConvertedAmount converts the Moneys value into its base units (dollars, euros, etc) and rounds to the appropriate digits.

    update the IntlFormatter to use this new method.

    add test for method.

    update readme to explain how to use method

    opened by browner12 2
  • Money: call static function handleCurrencyArgument() with self::

    Money: call static function handleCurrencyArgument() with self::

    Hi Sebastian,

    just being picky really.

    Nice lib, I actually have done a similar class myself. I am also glad not be the only one to think that IT systems dealing with money should use integers (cents) and not floats ...

    opened by whatthefrog 1
  • Allocate negative amounts

    Allocate negative amounts

    Applies to #65

    • Fixed allocateToTargets for negative amounts
    • Fixed allocateByRatios for negative amounts
    • Added test for allocateToTargets with negative amount
    • Added test for allocateByRatios with negative amount
    • Extended the method behaviour documentation for negative amounts in README.md
    opened by hollodotme 1
  • add a changelog

    add a changelog

    a file to keep track of all notable changes so users will have an easy place to go to see any updates.

    it should track things that are Added, Deprecated, Fixed, Removed, and any Security issues.

    Obviously it would be a little difficult to go back and add this info for all previous releases, but with this commit at least we have a history of versions and their release dates, and a place to document changes as the package moves forward.

    opened by browner12 1
  • update `getAmount` to return either base units or subunits

    update `getAmount` to return either base units or subunits

    sometimes it is beneficial to return the base unit value of a currency rather than the subunit value. this commit allows us to do that by passing a boolean to the getAmount method. this implementation will not break BC, and users can continue to use the getAmount method as before.

    in fact, the PHP number formatter doesn't do any of this math for you, which is why you needed to include it in your IntlFormatter. This commit allows us to move that responsibility from the formatter to the Money class.

    if the mixed return types bothers you, I could also extract this out into a separate method, something like getConvertedAmount()

    opened by browner12 1
Releases(v1.3.0)
Owner
Sebastian Bergmann
Sebastian Bergmann is the creator of PHPUnit. He co-founded thePHP.cc and helps PHP teams build better software.
Sebastian Bergmann
Laravel paypal payment package , help you process credit card payment using paypal api

Important :The use of the PayPal REST /payments APIs to accept credit card payments is restricted by paypal and they recomand to use Braintree Direct

Anouar Absslm 328 Oct 31, 2022
Begining of an e-commerce website using PHP and the MVC Pattern

Begining of an e-commerce website using PHP and the MVC Pattern

Ulysse Valdenaire 5 Dec 25, 2022
E-commerce web application using php routing

E-commerce Website E-commerce web application built using php routing. Instead of relying on the web server to map the request path to a file, all req

Olorunfemi-Ojo Tomiwa 13 Dec 26, 2022
The Online Shopping System in PHP using XAMPP as virtual Server.

Online shopping is a form of electronic commerce which allows consumers to directly buy goods or services from a seller over the Internet using a web browser or a mobile app.

Magesh Surya Ambikapathi 5 Sep 15, 2022
vfsStream is a stream wrapper for a virtual file system that may be helpful in unit tests to mock the real file system. It can be used with any unit test framework, like PHPUnit or SimpleTest.

vfsStream vfsStream is a stream wrapper for a virtual file system that may be helpful in unit tests to mock the real file system. It can be used with

null 1.4k Dec 23, 2022
A simple PHP library for complex monetary prices management

PHP Prices ?? Version 2.x This new major version is shifting the package towards more flexibility and configuration possibilities in general. One of t

Whitecube 134 Dec 16, 2022
Instagram automation represents the use of third-party software to manage your account, carry out tasks and/or interact with users without a human present. Bulit in Laravel Framework

How to Deploy laravel project to heroku Video Link : https://youtu.be/7Nq_a2QiaHo Home Page Login Page Dashboard Page About Laravel Laravel is a web a

null 1 Dec 3, 2021
Quite possibly the smallest MVC framework you'll ever use.

Swiftlet Swiftlet is quite possibly the smallest MVC framework you'll ever use. And it's swift. Licensed under the MIT license. Buzzword compliance ✔

Elbert Alias 429 Nov 13, 2022
Twittee is the smallest, and still useful, Dependency Injection Container in PHP

What is Twittee? Twittee is the smallest, and still useful, Dependency Injection Container in PHP; it is also probably one of the first public softwar

null 133 Dec 5, 2022
Share value objects that contain the same primitive value as a singleton

sharable-value-objects Share value objects that contain the same primitive value as a singleton. Singletons are kept under WeakReference objects. Inst

mpyw 5 Nov 14, 2021
To run time/IO related unit tests (e.g., sleep function calls, database queries, API calls, etc) faster using Swoole.

To run time/IO related unit tests (e.g., sleep function calls, database queries, API calls, etc) faster using Swoole.

Demin Yin 11 Sep 9, 2022
An object-oriented option parser library for PHP, which supports type constraints, flag, multiple flag, multiple values, required value checking

GetOptionKit Code Quality Versions & Stats A powerful option parser toolkit for PHP, supporting type constraints, flag, multiple flag, multiple values

Yo-An Lin 140 Sep 28, 2022
PHP library that helps to map any input into a strongly-typed value object structure.

Valinor • PHP object mapper with strong type support Valinor is a PHP library that helps to map any input into a strongly-typed value object structure

Team CuyZ 873 Jan 7, 2023
Immutable value object for IPv4 and IPv6 addresses, including helper methods and Doctrine support.

IP is an immutable value object for (both version 4 and 6) IP addresses. Several helper methods are provided for ranges, broadcast and network address

Darsyn 224 Dec 28, 2022
Decimal handling as value object instead of plain strings.

Decimal Object Decimal value object for PHP. Background When working with monetary values, normal data types like int or float are not suitable for ex

Spryker 16 Oct 24, 2022
Yet another Value Object Library (YAVOL)

Yet Another DDD Library Value object This library is a foundation in order to implement the Value Object pattern. It helps you to introduce some DDD s

YADDDL 3 Nov 17, 2022
An object-oriented option parser library for PHP, which supports type constraints, flag, multiple flag, multiple values, required value checking

GetOptionKit Code Quality Versions & Stats A powerful option parser toolkit for PHP, supporting type constraints, flag, multiple flag, multiple values

Yo-An Lin 140 Sep 28, 2022
Email address value object.

Email address value object Installation Via Composer: $ composer require nepada/email-address Usage This package provides two implementations of email

null 5 Jan 1, 2022
Provides JSON pointer as a value object

json-pointer Provides JSON pointer as a value object. Installation Run composer require ergebnis/json-pointer Usage ReferenceToken You can create a Re

null 3 Dec 15, 2022