coverd / money-bundle
这是一个整合了 moneyphp/money 库(Fowler 模式)的 Symfony 扩展包:https://github.com/moneyphp/money。
Requires
- php: ^8.0
- moneyphp/money: ^4.0
- symfony/console: ^5.3|^6.0
- symfony/form: ^5.3|^6.0
- symfony/framework-bundle: ^5.3|^6.0
- symfony/intl: ^5.3|^6.0
Requires (Dev)
- beberlei/doctrineextensions: ^1.2
- doctrine/doctrine-bundle: ^2.0
- phpunit/phpunit: ^9.0
- symfony/browser-kit: ^5.3|^6.0
- symfony/phpunit-bridge: ^5.3|^6.0
- symfony/twig-bundle: ^5.3|^6.0
- symfony/yaml: ^5.3|^6.0
README
免责声明
原始包为 TbbcMoneyBundle。由于此仓库维护不足,我们进行了分支并大量简化,移除了所有不必要的功能(基本上,与对/比相关的所有功能)。
描述
此包用于将 mathiasverraes 的 Money 库整合到 Symfony 项目中。
该库基于 Fowler 的 Money 模式
特性
- 整合 mathiasverraes 的 money 库
- 模板中用于货币和货币单位的 Twig 过滤器和 PHP 辅助函数
- Symfony 表单集成
- 用于指定网站使用的货币的配置解析器
- 货币格式化国际化
安装
使用 Composer 并使用 composer require coverd/money-bundle
安装
配置包(配置文件应位于 config/packages/coverd_money.yml 中)
coverd_money: currencies: ["USD", "EUR"] # Choose all availables currencies reference_currency: "EUR" # Choose the default currency decimals: 2 # Choose the number of decimals (default: 2)
使用 twig 表单主题
twig: form_themes: - 'MoneyBundle:Form:fields.html.twig'
注册 Doctrine Money 类型
doctrine: dbal: types: money: Coverd\MoneyBundle\Type\MoneyType
用法
Money 库集成
use Money\Money; $fiveEur = Money::EUR(500); $tenEur = $fiveEur->add($fiveEur); list($part1, $part2, $part3) = $tenEur->allocate(array(1, 1, 1)); assert($part1->equals(Money::EUR(334))); assert($part2->equals(Money::EUR(333))); assert($part3->equals(Money::EUR(333)));
表单集成
你有 3 种新的表单类型(位于 Coverd\MoneyBundle\Form\Type
命名空间下)
- CurrencyType:要求选择在 config.yml 中定义的货币之一
- MoneyType:要求输入金额和货币
- SimpleMoneyType:要求输入金额,并将货币设置为 config.yml 中设置的参考货币
示例
use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; // I create my form $form = $this->createFormBuilder() ->add('name', TextType::class) ->add('price', MoneyType::class, [ 'data' => Money::EUR(1000), ]) ->getForm();
操作表单
使用 MoneyType
,您可以使用以下方式操作表单元素:
amount_options
用于金额字段,currency_options
用于货币字段,例如,如果您想更改标签。
$form = $this->createFormBuilder() ->add('price', MoneyType::class, [ 'data' => Money::EUR(1000), 'amount_options' => [ 'label' => 'Amount', ], 'currency_options' => [ 'label' => 'Currency', ], ]) ->getForm();
使用 CurrencyType
只能使用 currency_options
,使用 SimpleMoneyType
只能使用 amount_options
。
使用 Doctrine 保存货币
解决方案 1:数据库中的两个字段
请注意,数据库表中有两列:$priceAmount 和 $priceCurrency,只有一个 getter/setter:getPrice 和 setPrice。
get/setPrice 方法透明地处理这两列。
- 优势:您的数据库干净,您可以在数据库的两个不同列中使用数量和货币进行SQL求和、分组、排序等操作
- 劣势:在实体中看起来比较丑。
<?php namespace App\AdministratorBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Money\Currency; use Money\Money; /** * @ORM\Table("test_money") * @ORM\Entity */ class TestMoney { /** * @var integer * * @ORM\Column(name="price_amount", type="integer") */ private $priceAmount; /** * @var string * * @ORM\Column(name="price_currency", type="string", length=64) */ private $priceCurrency; public function getPrice(): Money { if (!$this->priceCurrency) { return null; } if (!$this->priceAmount) { return new Money(0, new Currency($this->priceCurrency)); } return new Money($this->priceAmount, new Currency($this->priceCurrency)); } public function setPrice(Money $price): void { $this->priceAmount = $price->getAmount(); $this->priceCurrency = $price->getCurrency()->getCode(); } }
解决方案2:使用Doctrine类型
您的数据库表只有一个字符串列。货币对象通过新的Doctrine类型手动序列化。
1.25欧元在数据库中序列化为'EUR 125'。 此格式是稳定的。未来版本中不会更改。
新的Doctrine类型名称为"money"。
- 优势:实体易于创建和使用
- 劣势:直接在SQL中请求数据库更为困难。
<?php namespace App\AdministratorBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Money\Money; /** * @ORM\Table("test_money") * @ORM\Entity */ class TestMoney { /** * @var Money * * @ORM\Column(name="price", type="money") */ private $price; public function getPrice(): Money { return $this->price; } public function setPrice(Money $price): void { $this->price = $price; } }
货币格式化器
<?php namespace My\Controller\IndexController; use Money\Money; use Money\Currency; class IndexController extends Controller { public function myAction() { $moneyFormatter = $this->get('coverd_money.formatter.money_formatter'); $price = new Money(123456789, new Currency('EUR')); \Locale::setDefault('fr_FR'); $formatedPrice = $moneyFormatter->localizedFormatMoney($price); // 1 234 567,89 € $formatedPrice = $moneyFormatter->localizedFormatMoney($price, 'en'); // €1,234,567.89 // old method (before v2.2) $formattedPrice = $moneyFormatter->formatMoney($price); // 1 234 567,89 $formattedCurrency = $moneyFormatter->formatCurrency($price); // € } }
Twig集成
{{ $amount | money_localized_format('fr') }} => 1 234 567,89 € {{ $amount | money_localized_format('en_US') }} => €1,234,567.89 {{ $amount | money_localized_format }} => depends on your default locale {{ $amount | money_format }} {{ $amount | money_as_float }} {{ $amount.currency | currency_symbol }} {{ $amount | money_format_currency }}
MoneyManager:从浮点数创建货币对象
从浮点数创建货币对象可能有些棘手,因为存在舍入问题。
<?php $moneyManager = $this->get("coverd_money.money_manager"); $money = $moneyManager->createMoneyFromFloat('2.5', 'USD'); $this->assertEquals("USD", $money->getCurrency()->getCode()); $this->assertEquals(250, $money->getAmount());
在MoneyFormatter中自定义NumberFormatter
MoneyFormatter::localizedFormatMoney(服务'coverd_money.formatter.money_formatter')使用php NumberFormatter类(https://php.ac.cn/manual/en/numberformatter.formatcurrency.php)来格式化货币。
您可以将
- 自己的\NumberFormatter实例作为MoneyFormatter::localizedFormatMoney的参数
- 继承MoneyFormatter并重写getDefaultNumberFormater方法来设置应用程序范围的NumberFormatter