Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ Makefile export-ignore

# Remove directories for archives
.docker/ export-ignore
docs/ export-ignore
.github/ export-ignore
tests/ export-ignore
60 changes: 60 additions & 0 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Deploy Documentation

on:
push:
branches:
- master
paths:
- 'docs/**'
- '.github/workflows/deploy-docs.yml'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: pages
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Setup Node
uses: actions/setup-node@v6
with:
node-version: 24
cache: npm
cache-dependency-path: docs/package-lock.json

- name: Install dependencies
run: npm ci
working-directory: docs

- name: Build with VitePress
run: npm run docs:build
working-directory: docs

- name: Upload artifact
uses: actions/upload-pages-artifact@v5
with:
path: docs/.vitepress/dist

deploy:
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
needs: build
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v5
71 changes: 41 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,56 +9,67 @@

Decimal value object for PHP.

## Documentation

**<https://php-collective.github.io/decimal-object/>**

## Background
When working with decimal (e.g. monetary) values, normal data types like int or float are not suitable for exact arithmetic.
Try out the following in PHP:

Floats cannot represent most decimal fractions exactly, which makes them unsuitable for money and other values that must add up:

```php
var_dump(0.1 + 0.2); // float(0.3)
var_dump(0.1 + 0.2 - 0.3); // float(5.5511151231258E-17)
var_dump(0.1 + 0.2 === 0.3); // bool(false)
```

Handling them as strings is a workaround, but as value object you can more easily encapsulate some of the logic.
Handling such values as strings works, and a value object keeps the logic for it in one place:

### Alternatives
Solutions like [php-decimal](https://php-decimal.github.io/#introduction) require a custom PHP extension (would make it faster, but also more difficult for some
servers to be available).
Monetary values themselves could be handled also with [brick/money](https://github.com/brick/money) or [moneyphp/money](https://github.com/moneyphp/money).
```php
use PhpCollective\DecimalObject\Decimal;

For details see the [wiki](https://github.com/php-collective/decimal-object/wiki).
$total = Decimal::create('0.1')->add('0.2');

Note: PHP 8.1 is covered by the 1.3 releases. For anything older, check out the [legacy library](https://github.com/spryker/decimal-object).
echo $total; // 0.3
var_dump($total->equals('0.3')); // bool(true)
```

## Features

- Super strict on precision/scale. Does not lose significant digits on its own. You need to `trim()` for this manually.
- Speaking API (no le, gt methods).
- Basic math operations and checks supported.
- Immutability.
- Handle very large and very small numbers.
- Strict about precision and scale. Significant digits are only dropped when you `trim()` or round.
- Readable API: `add()`, `greaterThan()`, `isZero()`.
- Arithmetic, rounding, comparison and conversion.
- Immutable.
- Handles numbers beyond the integer and float range.
- No custom PHP extension, only `bcmath`.

## Installation

### Requirements

- PHP 8.2+
- `bcmath` PHP extension enabled

### Composer (preferred)
```
composer require php-collective/decimal-object
```

Requires PHP 8.2+ and the `bcmath` extension. PHP 8.1 is covered by the 1.3 releases. For anything older, use the [legacy library](https://github.com/spryker/decimal-object).

## Usage

See [Documentation](/docs) for more details.
- [Getting started](https://php-collective.github.io/decimal-object/guide/getting-started)
- [Arithmetic](https://php-collective.github.io/decimal-object/guide/arithmetic)
- [Precision and scale](https://php-collective.github.io/decimal-object/guide/scale)
- [Rounding](https://php-collective.github.io/decimal-object/guide/rounding)
- [API reference](https://php-collective.github.io/decimal-object/reference/api)

## Integrations

- [dereuromark/cakephp-decimal](https://dereuromark.github.io/cakephp-decimal/) as decimal type for the CakePHP ORM.

See [Alternatives](https://php-collective.github.io/decimal-object/reference/alternatives) for how this library compares to php-decimal, brick/math and the money libraries.

## Contributing

## Implementations
The following libraries are using the `Decimal` value object:
Pull requests are welcome:

- [dereuromark/cakephp-decimal](https://github.com/dereuromark/cakephp-decimal) as decimal type replacement for CakePHP ORM.
- Target `master` for bug fixes and backwards compatible improvements.
- Target `next` (the next major version) for anything that breaks backwards compatibility.

The original library here was written 2019 for [Spryker](https://spryker.com/) ecommerce framework
and since then battle-tested through millions of customers and orders as well as other complex calculations under the hood.
This here is the freshly upgraded and independently maintained version for the PHP ecosystem as a whole.
## History

Enjoy!
The library was written in 2019 for the [Spryker](https://spryker.com/) commerce framework and has been used there in order and price calculations since. This repository is the independently maintained continuation for the PHP ecosystem as a whole.
3 changes: 3 additions & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
.vitepress/dist/
.vitepress/cache/
53 changes: 53 additions & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { defineConfig } from 'vitepress'

export default defineConfig({
title: 'Decimal Object',
description: 'Immutable decimal value object for PHP, built on bcmath.',
base: '/decimal-object/',
srcExclude: ['README.md'],
head: [['link', { rel: 'icon', type: 'image/svg+xml', href: '/decimal-object/favicon.svg' }]],
themeConfig: {
logo: '/logo.svg',
nav: [
{ text: 'Installation', link: '/guide/installation' },
{ text: 'Getting started', link: '/guide/getting-started' },
{ text: 'API', link: '/reference/api' },
{
text: 'Ecosystem',
items: [
{ text: 'Integrations', link: '/reference/integrations' },
{ text: 'CakePHP Decimal', link: 'https://dereuromark.github.io/cakephp-decimal/' },
{ text: 'Packagist', link: 'https://packagist.org/packages/php-collective/decimal-object' },
],
},
],
sidebar: [
{
text: 'Guide',
items: [
{ text: 'Installation', link: '/guide/installation' },
{ text: 'Getting started', link: '/guide/getting-started' },
{ text: 'Creating decimals', link: '/guide/creating' },
{ text: 'Arithmetic', link: '/guide/arithmetic' },
{ text: 'Precision and scale', link: '/guide/scale' },
{ text: 'Rounding', link: '/guide/rounding' },
{ text: 'Comparison and checks', link: '/guide/comparison' },
{ text: 'Conversion', link: '/guide/conversion' },
],
},
{
text: 'Reference',
items: [
{ text: 'API', link: '/reference/api' },
{ text: 'Integrations', link: '/reference/integrations' },
{ text: 'Alternatives', link: '/reference/alternatives' },
{ text: 'Upgrading', link: '/reference/upgrading' },
],
},
],
search: { provider: 'local' },
socialLinks: [{ icon: 'github', link: 'https://github.com/php-collective/decimal-object' }],
editLink: { pattern: 'https://github.com/php-collective/decimal-object/edit/master/docs/:path' },
footer: { message: 'Released under the MIT License.', copyright: 'Copyright The PHP Collective' },
},
})
27 changes: 27 additions & 0 deletions docs/.vitepress/theme/custom.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
:root {
--vp-c-brand-1: #1e40af;
--vp-c-brand-2: #3b82f6;
--vp-c-brand-3: #1e40af;
--vp-c-brand-soft: rgba(59, 130, 246, 0.14);

--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: linear-gradient(135deg, #1e40af 0%, #0891b2 100%);
--vp-home-hero-image-background-image: linear-gradient(135deg, #1e40af 0%, #0891b2 100%);
--vp-home-hero-image-filter: blur(42px);
}

.dark {
--vp-c-brand-1: #93c5fd;
--vp-c-brand-2: #60a5fa;
--vp-c-brand-3: #1e40af;
}

.vp-doc table code,
.vp-doc p code,
.vp-doc li code {
white-space: nowrap;
}

.vp-doc .custom-block.tip {
border-color: var(--vp-c-brand-1);
}
4 changes: 4 additions & 0 deletions docs/.vitepress/theme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import DefaultTheme from 'vitepress/theme'
import './custom.css'

export default DefaultTheme
111 changes: 7 additions & 104 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,108 +1,11 @@
# Decimal VO documentation
# Decimal Object documentation

Decimal value object for PHP.
Read the [documentation website](https://php-collective.github.io/decimal-object/) or start with [Installation](guide/installation.md) and [Getting started](guide/getting-started.md).

## Basic information
To preview the site locally:

The value objects are immutable, always assign them when running modifications on them.

## Usage

You can create the value object from
- string
- integer
- float
- object that implements Stringable (and numeric `toString()` method)

```php
use PhpCollective\DecimalObject\Decimal;

$value = '1.234';
$decimalObject = Decimal::create($value);

echo 'Value: ' . $decimalObject;
```sh
cd docs
npm install
npm run docs:dev
```

It will auto-cast to string where necessary, you can force it using `(string)$decimalObject`.

### Operations

Transformation:
- `sign()`: Returns int `0` if zero, `-1` if negative, or `1` if positive.
- `toString()`: Default casting mechanism (this method is equivalent to a cast to string).
- `toFloat()`: Returns some approximation of this Decimal as a PHP native float.
- `toInt()`: Returns integer value (this method is equivalent to a cast to integer).

These return a new object:
- `absolute()`: Returns the absolute (positive) value of this decimal.
- `negate()`: Returns the negation (positive if negative and vice versa).
- `trim()`: Remove trailing zeros after the comma (same value, but different semantic meaning in terms of precision/scale).

There is only one static method and acts as a convenience wrapper to create an object:
- `create()`: Internally does `new Decimal($value)`, allows for easier chaining without need of `()` wrapping.
Use this if your input can already be the `Decimal` object as it will then just be re-used. Constructor creation
builds a new object.

### Checks

Boolean checks:
- `isZero()`: If exactly `0`.
- `isNegative()`: If < `0`.
- `isPositive()`: If > `0` (zero itself is not included).

### Comparison

- `compareTo()`: Compare this Decimal to another value.
- `equals()`: This method is equivalent to the `==` operator.
- `greaterThan()`: Returns true if the Decimal is greater than given value.
- `lessThan()`: Returns true if the Decimal is smaller than given value.
- `greaterThanOrEquals()`: Returns true if the Decimal is greater than or equal to the given value.
- `lessThanOrEquals()`: Returns true if the Decimal is greater than or equal to the given value.

### Math and Calculation
You can use
- `add()`
- `subtract()`
- `multiply()`
- `divide()`
- `round()`: Round using different modes.
- `truncate()`: Truncate after places of decimal.
- `mod()`
- `pow()`
- `sqrt()`

```php
$decimalOne = Decimal::create('1.1');
$decimalTwo = Decimal::create('2.2');

$decimalAdded = $decimalOne->add($decimalTwo); // Now '3.3'
```

Note that due to immutability `$decimalOne` is not modified here. The re-assignment is necessary for the operation to persist.

### Precision/Scale
Operations like `add()` use the higher one of the scales of the operands.
If both are the same, they would also stay the same.

With other operations like `multiply()`, the scale would be the addition of both operands' scale by default:
```php
$decimalOne = Decimal::create('1.55');
$decimalTwo = Decimal::create('2.00');

echo $decimalOne->multiply($decimalTwo); // Prints '3.1000'
```

To produce a result with a different number of decimal places, provide a value for the `$scale` parameter:
```php
$decimalOne = Decimal::create('1.55');
$decimalTwo = Decimal::create('2.00');

echo $decimalOne->multiply($decimalTwo, 2); // Prints '3.10'
```


## Contributing

You can contribute as pull request directly:
- Target `master` branch for: bugfixes, improvements that are BC
- Target `next` branch (next major version) for: Any BC breaking behavior, cleanup like removing deprecations or alike
Loading
Loading