mesilov/moneyphp-percentage
Tiny PHP helper for applying percentage calculations to MoneyPHP money values. Useful for discounts, taxes, fees, commissions, and proportional splits while keeping monetary amounts precise and reusable across your app.
Installation
composer require mesilov/moneyphp-percentage
Ensure moneyphp/money is also installed (dependency).
First Use Case Create a percentage value object for VAT calculations:
use Money\Money;
use MoneyPhp\Percentage\Percentage;
$vatRate = new Percentage(21); // 21% VAT
$amount = Money::EUR(100);
$vatAmount = $vatRate->of($amount); // Calculates 21% of 100 EUR
Key Classes
Percentage: Core class for percentage calculations.PercentageException: Handles invalid operations (e.g., negative rates).src/Percentage.php for core logic.tests/ for usage examples and edge cases.VAT Calculation
$vatRate = new Percentage(21);
$subtotal = Money::EUR(1000);
$vat = $vatRate->of($subtotal); // 210 EUR
$total = $subtotal->add($vat); // 1210 EUR
Discounts
$discountRate = new Percentage(10); // 10% off
$price = Money::USD(500);
$discount = $discountRate->of($price); // 50 USD
$finalPrice = $price->subtract($discount); // 450 USD
Dynamic Rates
$rates = [
'standard' => new Percentage(21),
'reduced' => new Percentage(7),
];
$rate = $rates[$taxType];
Laravel Request Binding Bind percentage inputs (e.g., VAT rates) from forms:
use Illuminate\Http\Request;
use MoneyPhp\Percentage\Percentage;
$request->validate(['vat_rate' => 'required|numeric|min:0|max:100']);
$vatRate = new Percentage($request->vat_rate);
Service Layer Encapsulate logic in a service:
class TaxService {
public function calculateVat(Money $amount, Percentage $rate) {
return $rate->of($amount);
}
}
Localization Format percentages for display:
$rate = new Percentage(21);
echo $rate->getValue() . '%'; // "21%"
Negative Rates
Throws PercentageException if rate < 0. Validate inputs:
if ($rate->getValue() < 0) {
throw new \InvalidArgumentException('Rate cannot be negative.');
}
Precision Issues Percentages use floating-point arithmetic. For exact calculations:
$rate = new Percentage(21.5); // 21.5% (may cause rounding errors)
$amount = Money::EUR(100);
$vat = $rate->of($amount); // Use Money's precision handling
Currency Mismatch
Percentage::of() ignores currency. Ensure Money objects use the same currency for operations.
$rate = new Percentage(21);
var_dump($rate->getValue()); // Debug raw value
$vat = $rate->of($amount);
logger()->debug("VAT Calculation", [
'rate' => $rate->getValue(),
'amount' => $amount->getAmount(),
'vat' => $vat->getAmount(),
]);
Custom Rounding
Extend Percentage to use Money's rounding mode:
$rate = new Percentage(21, Money::ROUND_HALF_UP);
Percentage Formatter Create a formatter trait:
trait PercentageFormatter {
public function format(): string {
return number_format($this->getValue(), 2) . '%';
}
}
Percentage Storage Serialize to/from database:
// Store
$request->vat_rate; // e.g., 21
$rate = new Percentage($request->vat_rate);
// Retrieve
$storedRate = new Percentage($model->vat_rate);
config/moneyphp-percentage.php exists. All logic is runtime-based.moneyphp/money is installed and configured (e.g., currency, rounding) before using this package.How can I help you explore Laravel packages today?