Download the PHP package whitecube/php-prices without Composer

On this page you can find all versions of the php package whitecube/php-prices. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package php-prices

PHP Prices

run-tests

💸 Version 3.x

This new major version aims to avoid rounding errors when working with division and multiplication.

We have replaced almost all Brick\Money\Money typehints to Brick\Money\AbstractMoney in order to allow usage of Brick\Money\RationalMoney instances as the base for the price object, in order to allow rounding-free division and multiplication. See the new chapter on rounding errors in this documentation for more information.
We have also added type definitions everywhere we could. This introduces some breaking changes.

Using the underlying brick/money library, this simple Price object allows to work with complex composite monetary values which include exclusive, inclusive, VAT (and other potential taxes) and discount amounts. It makes it safer and easier to compute final displayable prices without having to worry about their construction.

Install

Getting started

Each Price object has a base Brick\Money\Money or Brick\Money\RationalMoney instance which is considered to be the item's unchanged, per-unit & exclusive amount. All the composition operations, such as adding VAT or applying discounts, are added on top of this base value.

It is common practice and always best to work with amounts represented in the smallest currency unit (minor values) such as "cents".

There are several convenient ways to obtain a Price instance:

Method Using major values Using minor values Defining units
Constructor new Price(AbstractMoney $base) new Price(AbstractMoney $base) new Price(AbstractMoney $base, $units)
Brick/Money API Price::of($major, $currency) Price::ofMinor($minor, $currency) -
Currency API - Price::EUR($minor) Price::USD($minor, $units)
Parsed strings Price::parse($value, $currency) - Price::parse($value, $currency, $units)

From Constructor

You can set this basic value by instantiating the Price directly with the desired Brick\Money\Money instance:

From Brick/Money-like methods

For convenience, it is also possible to use the shorthand Money factory methods:

Using these static calls, you cannot define quantities or units directly with the constructor methods.

For more information on all the available Brick/Money constructors, please take a look at their documentation.

From currency-code methods

You can also create an instance directly with the intended currency and quantities using the 3-letter currency ISO codes:

Using these static calls, all monetary values are considered minor values (e.g. cents).

For a list of all available ISO 4217 currencies, take a look at Brick/Money's iso-currencies definition.

From parsed string values

Additionnaly, prices can also be parsed from "raw currency value" strings. This method can be useful but should always be used carefully since it may produce unexpected results in some edge-case situations, especially when "guessing" the currency :

Parsing formatted strings is a tricky subject. More information on parsing string values below.

Accessing the Money objects (getters)

Once set, the base amount can be accessed using the base() method.

Note If you give an instance of Brick\Money\Money as a parameter when instanciating the price object, you will get a Brick\Money\Money instance back. Similarly, instanciating with Brick\Money\RationalMoney will give you a RationalMoney object back.

Getting the currency instance is just as easy:

The total exclusive amount (with all modifiers except VAT):

The total inclusive amount (with all modifiers and VAT applied):

The VAT variables:

Comparing amounts

It is possible to check whether a price object's total inclusive amount is greater, lesser or equal to another value using the compareTo method:

For convenience there also is an equals() method:

If you don't want to compare final modified values, there is a compareBaseTo method:

Modifying the base price

The price object will forward all the Brick\Money\Money API method calls to its base value.

Warning: In opposition to Money objects, Price objects are not immutable. Therefore, operations like plus, minus, etc. will directly modify the price's base value instead of returning a new instance.

Please refer to brick/money's documentation for the full list of available features.

💡 Nice to know: Whenever possible, you should prefer using modifiers to alter a price since its base value is meant to be constant. For more information on modifiers, please take at the "Adding modifiers" section below.

Handling rounding properly when using division and multiplication

When creating a price object from a Brick\Money\Money instance, rounding errors can occur when doing division and multiplication.

An example of the problem: we have a base price of 1000 minor units, that we need to divide by 12 and then multiply by 11.

1000 / 12 * 11 = 916,6666666666...

Using the regular Brick\Money\Money class forces us to specify a rounding mode when doing the division, which means we have a rounded result before doing the multiplication, which introduces an error in the result:

The solution is to build the Price instance with a base Brick\Money\RationalMoney instance instead, which represents the amount as a fraction and thus does not require rounding.

For more information, see brick/money's documentation on the matter.

Setting units (quantities)

This package's default behavior is to consider its base price as the "per unit" price. When no units have been specified, it defaults to 1. Since "units" can be anything from a number of undividable products to a measurement, they are always converted to floats.

You can set the units amount (or "quantity" if you prefer) during instantiation:

...or modify it later using the setUnits() method:

You can return the units count using the units() method (always float):

Setting VAT

VAT can be added by providing its relative value (eg. 21%):

Once set, the price object will be able to provide various VAT-related information:

Setting modifiers

Modifiers are all the custom operations a business needs to apply on a price before displaying it on a bill. They range from discounts to taxes, including custom rules and coupons. These are the main reason this package exists.

Discounts

Taxes (other than VAT)

Custom modifier types

Sometimes modifiers cannot be categorized into "discounts" or "taxes", in which case you can add your own modifier type:

💡 Nice to know: Modifier types (tax, discount or your own) are useful for filtering, grouping and displaying sub-totals or price construction details. More information in the "Displaying modification details" section below.

Complex modifiers

Most of the time, modifiers are more complex to define than simple "+" or "-" operations. Depending on the level of complexity, there are a few options that will let you configure your modifiers just as you wish.

Closure modifiers

Instead of providing a monetary value to the modifiers, you can use a closure which will get a Whitecube\Price\Modifier instance. This object can then be used to perform some operations on the price value. Available operations are:

Method Description
add() Registers a plus() method call on the Money object.
subtract() Registers a minus() method call on the Money object.
multiply() Registers a multipliedBy() method call on the Money object.
divide() Registers a dividedBy() method call on the Money object.
abs() Registers a abs() method call on the Money object.

All these methods have the same signatures as their Brick\Money\Money equivalent. The reason we're not using the same method names is to imply object mutability.

Furthermore, using closure modifiers you can also add other useful configurations, such as:

Method Default Description
setKey(string) null Define an identifier on the modifier. This can be anything and its main purpose is to make a modifier recognizable on display, for instance a translation key or a CSS class name.
setPostVat(bool) false Indicate whether the modifier should be applied before (false) or after (true) the VAT has been calculated. More information on this feature below.
setPerUnit(bool) true Indicate whether the add() and subtract() operations define "per-unit" amounts instead of providing a fixed amount that would be applied no matter the quantity.
setAttributes(array) [] Define as many extra modifier attributes as needed. This can be very useful in order to display the applied modifiers in complex user interfaces.

Modifier classes

For even more flexibility and readability, it is also possible to extract all these features into their own class:

These classes have to implement the Whitecube\Price\PriceAmendable interface, which then looks more or less like this:

If needed, it is also possible to pass arguments to these custom classes from the Price configuration:

Before or after VAT?

Depending on the modifier's nature, VAT could be applied before or after its intervention on the final price. All modifiers can be configured to be executed during one of these phases.

By default modifiers are added before VAT is applied, meaning they will most probably also modify the VAT value. In order to prevent that, it is possible to add a modifier on top of the calculated VAT. Legally speaking this is honestly quite rare but why not:

In custom classes, this is handled by the appliesAfterVat method.

⚠️ Warning: Applying modifiers after VAT will alter the modifiers execution order. Prices will first apply all the modifiers that should be executed before VAT (in order of appearance), then the VAT itself, followed by the remaining modifiers (also in order of appearance).

Inclusive prices will contain all the modifiers (before and after VAT), but exclusive prices only contain the "before VAT" modifiers by default. If you consider the "after VAT" modifiers to be part of the exclusive price, you can always count them in by providing $includeAfterVat = true as second argument of the exclusive() method:

Displaying modification details

When debugging or building complex user interfaces, it is often necessary to retrieve the complete Price modification history. This can be done using the modifications() method after all the modifiers have been added on the Price instance:

Each history item contains the amount it applied to the total price. If you want to query these modifications with their "per-unit" value:

Filter this history based on the modifier types:

Most of the time you won't need all the data from the modifications() method, only the modification totals. These can be returned using the discounts(), taxes() and the generic modifiers() methods:

Output

By default, all handled monetary values are wrapped into a Brick\Money\Money object. This should be the only way to manipulate these values in order to avoid decimal approximation errors.

Displaying prices as strings

There are a lot of different ways to format a price for display and your application most certainly has its own needs that have to be respected. While it is of course possible to handle price formatting directly from the returned Brick\Money\Money objects, we also included a convenient Price formatter. Please note that its default behavior is based on PHP's NumberFormatter (by default it uses the current locale, see setlocale for more information).

For formatting in another language, provide the desired locale name as second parameter:

For advanced custom use cases, use the Price::formatUsing() method to provide a custom formatter function:

The Price::formatUsing() method accepts a closure function, a Formatter class name or a Formatter instance. The two last options should both extend \Whitecube\Price\Formatting\CustomFormatter:

For even more flexibility, it is possible to define multiple named formatters and call them using their own dynamic static method:

Please note that extra parameters can be forwarded to your custom formatters:

JSON

Prices can be serialized to JSON and rehydrated using the Price::json($value) method, which can be useful when storing/retrieving prices from a database or an external API for example:

💡 Nice to know: you can also use Price::json() in order to create a Price object from an associative array, as long as it contains the base, currency, units and vat keys.

Parsing values

There are a few available methods that will allow to transform a monetary string value into a Price object. The generic parseCurrency method will try to guess the currency type from the given string:

For this to work, the string should always contain an indication on the currency being used (either a valid ISO code or symbol). When using symbols, be aware that some of them ($ for instance) are used in multiple currencies, resulting in ambiguous results.

When you're sure which ISO Currency is concerned, you should directly pass it as the second parameter of the parse() method:

When using dedicated currency parsers, all units/symbols and non-numerical characters are ignored.


🔥 Sponsorships

If you are reliant on this package in your production applications, consider sponsoring us! It is the best way to help us keep doing what we love to do: making great open source software.

Contributing

Feel free to suggest changes, ask for new features or fix bugs yourself. We're sure there are still a lot of improvements that could be made, and we would be very happy to merge useful pull requests.

Thanks!

Made with ❤️ for open source

At Whitecube we use a lot of open source software as part of our daily work. So when we have an opportunity to give something back, we're super excited!

We hope you will enjoy this small contribution from us and would love to Twitter for more updates!


All versions of php-prices with dependencies

PHP Build Version
Package Version
Requires php Version ^8.0
brick/money Version 0.8.*
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package whitecube/php-prices contains the following files

Loading the files please wait ....