24
loading...
This website collects cookies to deliver better user experience
floor($amount);
ceil($value);
round($amount, $precision, $mode);
number_format($amount, $decimals);
Base price (€) | VAT 21% (€) | Total (€) |
---|---|---|
4.55 | 0.95 | 5.50 |
4.55 | 0.95 | 5.50 |
4.55 | 0.95 | 5.50 |
4.55 | 0.95 | 5.50 |
4.55 | 0.95 | 5.50 |
4.38 | 0.92 | 5.30 |
4.38 | 0.92 | 5.30 |
4.38 | 0.92 | 5.30 |
4.38 | 0.92 | 5.30 |
4.38 | 0.92 | 5.30 |
44.63 | 9.37 | 54.00 |
Base price (€) | VAT 21% (€) | Total (€) |
---|---|---|
4.545 | 0.9545 | 5.4995 |
4.545 | 0.9545 | 5.4995 |
4.545 | 0.9545 | 5.4995 |
4.545 | 0.9545 | 5.4995 |
4.545 | 0.9545 | 5.4995 |
4.380 | 0.9198 | 5.2998 |
4.380 | 0.9198 | 5.2998 |
4.380 | 0.9198 | 5.2998 |
4.380 | 0.9198 | 5.2998 |
4.380 | 0.9198 | 5.2998 |
44.625 | 9.371 | 53.996 |
Base price (€) | VAT 21% (€) | Total (€) |
---|---|---|
4.550 | 0.9555 | 5.5055 |
4.550 | 0.9555 | 5.5055 |
4.550 | 0.9555 | 5.5055 |
4.550 | 0.9555 | 5.5055 |
4.550 | 0.9555 | 5.5055 |
4.380 | 0.9198 | 5.2998 |
4.380 | 0.9198 | 5.2998 |
4.380 | 0.9198 | 5.2998 |
4.380 | 0.9198 | 5.2998 |
4.380 | 0.9198 | 5.2998 |
44.65 | 9.38 | 54.03 |
brick/money
because it uses underlying the package brick/math
, that allows more robust calculations. There is a comparison between the two libraries, but you should be safe using either one of them, specially after moneyphp/money
got a big rewrite one month ago (on May 2021).Amount
Value Object:<?php
declare(strict_types = 1);
namespace SharedKernel\Domain\ValueObject;
use Brick\Math\BigNumber;
use Brick\Math\Exception\NumberFormatException;
use Brick\Math\RoundingMode;
use Brick\Money\Exception\MoneyMismatchException;
use Brick\Money\Exception\UnknownCurrencyException;
use Brick\Money\Money;
use SharedKernel\Domain\Exception\InvalidAmountException;
final class Amount
{
private const ROUNDING_MODE = RoundingMode::HALF_UP;
private int $amount;
private string $currency;
private function __construct(int $amount, string $currency)
{
$this->amount = $amount;
$this->currency = $currency;
}
/**
* @param BigNumber|float|int|string $amount
* @param string $currency
*
* @return Amount
*
* @throws InvalidAmountException
*/
public static function of($amount, string $currency): self
{
$amountAsMoney = self::parseAndValidateOrFail($amount, $currency);
return new self(
$amountAsMoney->getMinorAmount()->toInt(),
$amountAsMoney->getCurrency()->getCurrencyCode(),
);
}
public function equalsTo(self $secondAmount): bool
{
try {
return $this->amount()->isEqualTo($secondAmount->amount());
} catch (MoneyMismatchException $e) {
return false;
}
}
public function amount(): Money
{
return Money::ofMinor($this->amount, $this->currency, null, self::ROUNDING_MODE);
}
/**
* @throws InvalidAmountException
*/
private static function parseAndValidateOrFail($amount, string $currency): Money
{
try {
return Money::of($amount, strtoupper($currency), null, self::ROUNDING_MODE);
} catch (UnknownCurrencyException $e) {
throw InvalidAmountException::withInvalidCurrency($currency);
} catch (NumberFormatException $e) {
throw InvalidAmountException::withInvalidAmountFormat($amount);
}
}
}
amount
: stored as int
with the minor unit (cents). For example, €105.35 will be stored as 10535.currency
: the currency code defined by the ISO 4127 standard.brick/money
library to validate any input value, and then we represent them with both amount
and currency
attributes. We can generate a Brick\Money\Money
value from them.Brick\Money\Money
value from them.SharedKernel\Domain\ValueObject\Amount
.amount
and currency
as scalar values, and then reconstruct the Amount
ValueObject from them.<?xml version="1.0" encoding="UTF-8" ?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<embeddable name="SharedKernel\Domain\ValueObject\Amount">
<field name="amount" type="integer" column="amount" />
<field name="currency" type="string" column="currency" length="3" />
</embeddable>
</doctrine-mapping>
Amount
Value Object to our entities easily. Another option would have been to create a custom type to persist both values as JSON in a single column. That would be the chosen option if we used a No-SQL storage.