Installation:
composer require baks-dev/reference-money
Ensure your project uses PHP 8.4+ and Doctrine ORM (required dependency).
Basic Usage:
ReferenceMoney type:
use BaksDev\ReferenceMoney\Type\ReferenceMoneyType;
#[ORM\Column(type: ReferenceMoneyType::NAME)]
private string $amount;
ReferenceMoney class:
use BaksDev\ReferenceMoney\ReferenceMoney;
$money = ReferenceMoney::fromFloat(123.45); // Stores as "12345" (string)
$floatValue = $money->toFloat(); // Returns 123.45
First Use Case:
decimal/float fields in financial entities (e.g., Order, Invoice) with ReferenceMoney to avoid floating-point precision issues.Entity Integration:
ReferenceMoneyType for Doctrine columns to auto-handle storage/retrieval.#[ORM\Entity]
class Order {
#[ORM\Column(type: ReferenceMoneyType::NAME)]
private string $totalAmount;
public function setTotal(float $amount): void {
$this->totalAmount = ReferenceMoney::fromFloat($amount)->getValue();
}
public function getTotal(): float {
return ReferenceMoney::fromString($this->totalAmount)->toFloat();
}
}
API/Service Layer:
float and ReferenceMoney at service boundaries:
class PaymentService {
public function process(float $amount): void {
$storedAmount = ReferenceMoney::fromFloat($amount);
// Save to DB via repository...
}
}
Validation:
ReferenceMoney::validate() to ensure values are valid before storage:
if (!ReferenceMoney::validate($userInput)) {
throw new \InvalidArgumentException("Invalid money format");
}
Custom Precision:
Override the default 2-decimal precision by extending ReferenceMoney:
class CustomMoney extends ReferenceMoney {
public static function fromFloat(float $amount, int $precision = 4): self {
return parent::fromFloat($amount * pow(10, $precision));
}
}
Query Filtering:
Use ReferenceMoney in DQL for precise filtering:
$query->andWhere('o.totalAmount = :amount')
->setParameter('amount', ReferenceMoney::fromFloat(100.0)->getValue());
Type Mismatch:
ReferenceMoney::fromString() fails if the stored value isn’t a string.string (not integer or decimal).
# config/doctrine/orm.yaml
orm:
mappings:
App:
type: attribute
dir: "%kernel.project_dir%/src/Entity"
prefix: "App\Entity"
alias: App
is_bundle: false
# Ensure no custom type overrides exist
Serialization Issues:
ReferenceMoney objects are directly serialized.float/string before serialization:
$serializable = $order->getTotal(); // Returns float
Database Schema:
string but doesn’t enforce it via migrations.SchemaTool to validate:
$schemaTool = new \Doctrine\ORM\Tools\SchemaTool($entityManager);
$schemaTool->createSchema([new Order()]); // Validates column types
Verify Storage: Check raw DB values with:
$money = ReferenceMoney::fromString("12345"); // Should return 123.45
$storedValue = $money->getValue(); // Debug: "12345"
Precision Errors: If calculations seem off, inspect the stored value:
$money = ReferenceMoney::fromString($entity->amount);
$debug = $money->getValue() / 100; // Should match expected float
Custom Storage:
Override ReferenceMoney::getValue()/setValue() for non-string storage (e.g., integer):
class IntegerMoney extends ReferenceMoney {
public function getValue(): int {
return (int) parent::getValue();
}
}
Currency Support: Extend the class to include currency codes:
class CurrencyMoney extends ReferenceMoney {
private string $currency;
public static function fromFloat(float $amount, string $currency): self {
$instance = new self();
$instance->setValue(ReferenceMoney::fromFloat($amount)->getValue());
$instance->currency = $currency;
return $instance;
}
}
Event Listeners:
Add validation listeners for prePersist/preUpdate:
$entityManager->getEventManager()->addEventListener(
\Doctrine\ORM\Events::prePersist,
function ($event) {
$entity = $event->getObject();
if ($entity instanceof Order) {
$entity->setTotal($entity->getTotal()); // Auto-convert
}
}
);
Doctrine Cache:
Clear metadata cache if ReferenceMoneyType changes aren’t reflected:
php bin/console doctrine:cache:clear-metadata
PHP Extensions:
Ensure bcmath or gmp is installed for high-precision operations (though the package defaults to string math).
How can I help you explore Laravel packages today?