Skip to content

Instantly share code, notes, and snippets.

@parijke
Last active February 1, 2021 09:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save parijke/ad4c197559c2af8d0a61a8d141173924 to your computer and use it in GitHub Desktop.
Save parijke/ad4c197559c2af8d0a61a8d141173924 to your computer and use it in GitHub Desktop.
MoneyPHP in Symfony
<?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://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<embeddable name="Money\Currency">
<field name="code" type="string" length="3">
<options>
<option name="fixed">true</option>
</options>
</field>
</embeddable>
</doctrine-mapping>
<?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://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<embeddable name="Money\Money">
<field name="amount" type="string"/>
<embedded name="currency" class="Money\Currency"/>
</embeddable>
</doctrine-mapping>
<?php
declare(strict_types=1);
namespace App\Twig;
use Money\MoneyFormatter;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
class MoneyExtension extends AbstractExtension
{
private MoneyFormatter $intlMoneyFormatter;
public function __construct(MoneyFormatter $intlMoneyFormatter)
{
$this->intlMoneyFormatter = $intlMoneyFormatter;
}
public function getFilters(): array
{
return [
new TwigFilter('money', [$this->intlMoneyFormatter, 'format']),
];
}
}
<?php
declare(strict_types=1);
namespace App\Form\DataTransformer;
use Money\Currencies;
use Money\Currency;
use Money\Money;
use Money\MoneyFormatter;
use Money\Number;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;
class MoneyTransformer implements DataTransformerInterface
{
private Currency $currency;
private MoneyFormatter $moneyFormatter;
private int $subunit;
public function __construct(string $defaultCurrency, MoneyFormatter $moneyFormatter, Currencies $currencies)
{
$currency = new Currency($defaultCurrency);
$this->subunit = $currencies->subunitFor($currency);
$this->currency = $currency;
$this->moneyFormatter = $moneyFormatter;
}
public function transform($value): ?string
{
if (!$value instanceof Money) {
return null;
}
return $this->moneyFormatter->format($value);
}
public function reverseTransform($value): Money
{
if ($value instanceof Money) {
return $value;
}
if (empty($value) && !is_array($value)) {
return new Money(0, $this->currency);
}
if (!is_numeric($value)) {
throw new TransformationFailedException(sprintf('Money value has to be a numeric value, "%s" given', is_object($value) ? get_class($value) : gettype($value)));
}
$number = Number::fromNumber($value)->base10(-$this->subunit);
return new Money($number->getIntegerPart(), $this->currency);
}
}
<?php
declare(strict_types=1);
namespace App\Form\Type;
use App\Form\DataTransformer\MoneyTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\FormBuilderInterface;
class MoneyValueType extends AbstractType
{
private MoneyTransformer $moneyTransformer;
public function __construct(MoneyTransformer $moneyTransformer)
{
$this->moneyTransformer = $moneyTransformer;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addModelTransformer($this->moneyTransformer);
}
public function getParent(): string
{
return NumberType::class;
}
}
services:
Money\Currencies:
class: Money\Currencies\ISOCurrencies
Money\MoneyFormatter:
class: Money\Formatter\DecimalMoneyFormatter
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment