symfgenus / money-bundle
这是一个集成了moneyphp/money库(Fowler模式)的Symfony扩展包:https://github.com/moneyphp/money。
Requires
- php: >=8.0
- ext-curl: *
- ext-intl: *
- ext-simplexml: *
- moneyphp/money: ^3.0|^4.0
- symfony/console: ^5.4|^6.0
- symfony/dom-crawler: ^5.4|^6.0
- symfony/event-dispatcher: ^5.4|^6.0
- symfony/form: ^5.4|^6.0
- symfony/http-client: ^5.4|^6.0
- symfony/templating: ^5.4|^6.0
- symfony/twig-bundle: ^5.4|^6.0
Requires (Dev)
- ext-sqlite3: *
- doctrine/doctrine-bundle: ^1.12|^2.0
- doctrine/orm: ^2.7|^3.0
- florianv/exchanger: ^2.0
- php-http/guzzle6-adapter: ^2.0
- php-http/message: ^1.0
- phpunit/phpunit: ^9.5
- symfony/browser-kit: ^5.4|^6.0
- symfony/phpunit-bridge: ^5.4 | ^6.0
- symfony/yaml: ^5.4|^6.0
- vimeo/psalm: ^4.13
Suggests
- doctrine/doctrine-bundle: ~1.1
- doctrine/orm: ~2.7
- florianv/exchanger: Exchanger is a PHP framework to work with currency exchange rates from various services.
This package is auto-updated.
Last update: 2022-06-16 17:08:22 UTC
README
此扩展包用于将mathiasverraes的Money库集成到Symfony项目中。
此库基于Fowler的Money模式。
- 此扩展包已在Symfony 3.4、4.3、4.4、5.0、6.0版本上进行了测试,运行稳定。
快速开始
use Money\Money; use Tbbc\MoneyBundle\Form\Type\MoneyType; // the money library $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))); // a service that stores conversion ratios $pairManager = $this->get('tbbc_money.pair_manager'); $usd = $pairManager->convert($tenEur, 'USD'); // a form integration $formBuilder->add('price', MoneyType::class);
特性
- 集成了mathiasverraes的Money库
- 在模板中提供货币和货币单位的Twig过滤器及PHP助手
- 货币比率的存储系统
- 从外部API获取比率的ratioProvider系统
- Symfony表单集成
- 用于不同操作的命令行工具
- 用于指定网站使用的货币的配置解析器
- 访问获取的货币比率的记录
- Money格式化i18n
目录
安装
使用Composer并安装:
$ composer require tbbc/money-bundle
如果使用Symfony 3,请将此扩展包添加到AppKernel
public function registerBundles() { $bundles = array( // ... new Tbbc\MoneyBundle\TbbcMoneyBundle(), ); }
对于Symfony 4及以上版本,请将扩展包添加到config/bundles.php(如果在安装包时未自动添加)
return [ // ... Tbbc\MoneyBundle\TbbcMoneyBundle::class => ['all' => true], ];
对于Symfony 3,在config.yml中添加您希望使用的货币和参考货币。对于Symfony 4及以上版本,创建一个如config/packages/tbbc_money.yml的文件并将其添加到其中。
tbbc_money: currencies: ["USD", "EUR"] reference_currency: "EUR" decimals: 2
在config.yml或config/packages/tbbc_money.yml中添加表单字段展示
twig: form_themes: - '@TbbcMoney/Form/fields.html.twig'
您还应注册自定义Doctrine Money类型
doctrine: dbal: types: money: Tbbc\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))); $pair = new CurrencyPair(new Currency('EUR'), new Currency('USD'), 1.2500); $usd = $pair->convert($tenEur); $this->assertEquals(Money::USD(1250), $usd);
表单集成
您有3个新的表单类型(位于Tbbc\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), //EUR 10 ]) ->add('save', SubmitType::class) ->getForm();
操作表单
使用MoneyType
,您可以使用以下方式操作表单元素:
amount_options
用于金额字段,currency_options
用于货币字段,例如,如果您想更改标签。
$form = $this->createFormBuilder() ->add('price', MoneyType::class, [ 'data' => Money::EUR(1000), //EUR 10 'amount_options' => array( 'label' => 'Amount', ), 'currency_options' => array( 'label' => 'Currency', ), ]) ->getForm();
在 CurrencyType
的情况下只能使用 currency_options
,而在 SimpleMoneyType
的情况下只能使用 amount_options
。
使用 Doctrine 保存货币
解决方案 1:数据库中的两个字段
注意数据库表中有两个列:$priceAmount 和 $priceCurrency,只有一个 getter/setter:getPrice 和 setPrice。
get/setPrice 方法处理这两个列是透明的。
- 优点:您的数据库干净,您可以在数据库的两个不同列中使用金额和货币进行 sql sum、group by、sort 等...
- 缺点:实体中看起来很丑。
<?php namespace App\AdministratorBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Money\Currency; use Money\Money; /** * TestMoney * * @ORM\Table("test_money") * @ORM\Entity */ class TestMoney { /** * @var integer * * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var integer * * @ORM\Column(name="price_amount", type="integer") */ private $priceAmount; /** * @var string * * @ORM\Column(name="price_currency", type="string", length=64) */ private $priceCurrency; /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * get Money * * @return Money */ public function getPrice() { 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)); } /** * Set price * * @param Money $price * @return TestMoney */ public function setPrice(Money $price) { $this->priceAmount = $price->getAmount(); $this->priceCurrency = $price->getCurrency()->getCode(); return $this; } }
解决方案 2:使用 Doctrine 类型
您的数据库表中只有一个字符串列。货币对象通过新的 Doctrine 类型手动序列化。
1.25€ 在您的数据库中以 'EUR 125' 的形式序列化。此格式是稳定的。未来版本中不会更改。。
新的 Doctrine 类型名称是 "money"。
- 优点:实体易于创建和使用
- 缺点:在 SQL 中直接请求数据库更困难。
<?php namespace App\AdministratorBundle\Entity; use Doctrine\ORM\Mapping as ORM; use Money\Money; /** * TestMoney * * @ORM\Table("test_money") * @ORM\Entity */ class TestMoney { /** * @var integer * * @ORM\Column(type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @var Money * * @ORM\Column(name="price", type="money") */ private $price; /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * get Money * * @return Money */ public function getPrice() { return $this->price; } /** * Set price * * @param Money $price * @return TestMoney */ public function setPrice(Money $price) { $this->price = $price; return $this; } }
转换管理器
将金额转换为另一种货币
$pairManager = $this->get("tbbc_money.pair_manager"); $usd = $pairManager->convert($amount, 'USD');
将转换值保存到数据库中
use Money\Money; $pairManager = $this->get("tbbc_money.pair_manager"); $pairManager->saveRatio('USD', 1.25); // save in ratio file in CSV $eur = Money::EUR(100); $usd = $pairManager->convert($amount, 'USD'); $this->assertEquals(Money::USD(125), $usd);
货币格式化器
<?php namespace My\Controller\IndexController; use Money\Money; use Money\Currency; class IndexController extends Controller { public function myAction() { $moneyFormatter = $this->get('tbbc_money.formatter.money_formatter'); $price = new Money(123456789, new Currency('EUR')); // best method (added in 2.2+ version) \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 | money_get_currency | currency_symbol }} {{ $amount | money_get_currency | currency_name }} {{ $amount | money_convert("USD") | money_format }} {{ $amount | money_format_currency }}
PHP 模板集成
<span class="price"><?php echo $view['tbbc_money']->format($price) ?></span> <span class="money"><?php echo $view['tbbc_money_currency']->formatCurrencyAsSymbol($price->getCurrency()) ?></span>
从远程提供者获取汇率值
# save a ratio in the storage ./bin/console tbbc:money:ratio-save USD 1.25 # display ratio list ./bin/console tbbc:money:ratio-list # fetch all the ratio for all defined currencies from an external API ./bin/console tbbc:money:ratio-fetch
更改汇率提供者
默认情况下,汇率提供者基于服务 'tbbc_money.ratio_provider.ecb'。
此包包含三个汇率提供者
- tbbc_money.ratio_provider.ecb 基于此处提供的数据 https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml
- tbbc_money.ratio_provider.yahoo_finance 基于Yahoo finance API https://developer.yahoo.com/(Yahoo 已不再提供此 API)
- tbbc_money.ratio_provider.google 基于服务 https://www.google.com/finance/converter(Google 已不再提供此 API)
您可以在 config.yml 文件中更改要使用的服务。
tbbc_money:
[...]
ratio_provider: tbbc_money.ratio_provider.google
来自 Exchanger 的附加汇率提供者
此项目集成了 https://github.com/florianv/exchanger 库,以处理来自各种服务的货币汇率。
安装
composer require "florianv/exchanger" "php-http/message" "php-http/guzzle6-adapter"
配置
首先,您需要将您想要使用的服务添加到您的 services.yml 文件中,例如
ratio_provider.service.ecb:
class: Exchanger\Service\EuropeanCentralBank
其次,您需要更新 MoneyBundle 使用的汇率提供者在您的 config.yml 文件中
tbbc_money:
[...]
ratio_provider: ratio_provider.service.ecb
推荐
一些提供商专注于有限的货币种类,但提供更好的数据。您可以通过将它们捆绑成链来无缝地在项目中使用多个汇率提供商。如果某些提供商不支持某种货币,则会尝试链中的下一个提供商。
链式提供商的示例
ratio_provider.service.ecb:
class: Exchanger\Service\EuropeanCentralBank
ratio_provider.service.rcb:
class: Exchanger\Service\RussianCentralBank
ratio_provider.service.cryptonator:
class: Exchanger\Service\Cryptonator
ratio_provider.service.array:
class: Exchanger\Service\PhpArray
arguments:
-
'EUR/USD': 1.157
'EUR/AUD': 1.628
ratio_provider.service.default:
class: Exchanger\Service\Chain
arguments:
-
- "@ratio_provider.service.ecb"
- "@ratio_provider.service.rcb"
- "@ratio_provider.service.cryptonator"
- "@ratio_provider.service.array"
如您所见,将尝试4个提供商,一个接一个,直到找到转换率。查看此页面以获取支持的服务及其配置的完整列表:https://github.com/florianv/exchanger/blob/master/doc/readme.md#supported-services
然后您需要在config.yml文件上分配汇率提供商
tbbc_money:
[...]
ratio_provider: ratio_provider.service.default
创建您自己的汇率提供商
汇率提供商是实现Tbbc\MoneyBundle\Pair\RatioProviderInterface
的服务。我建议您阅读该接口的PHP文档,以了解如何实现新的汇率提供商。
新的汇率提供商必须注册为服务。
要使用新的汇率提供商,您应在config.yml中设置要使用的服务,并给出服务名称。
tbbc_money:
[...]
ratio_provider: tbbc_money.ratio_provider.google
自动货币汇率抓取
添加到您的crontab
1 0 * * * /my_app_dir/bin/console tbbc:money:ratio-fetch > /dev/null
MoneyManager:从浮点数创建货币对象
从浮点数创建货币对象可能有些棘手,因为存在舍入问题。
<?php $moneyManager = $this->get("tbbc_money.money_manager"); $money = $moneyManager->createMoneyFromFloat('2.5', 'USD'); $this->assertEquals("USD", $money->getCurrency()->getCode()); $this->assertEquals(250, $money->getAmount());
使用pairHistoryManager的货币汇率历史
使用此功能需要Doctrine。
为了获取汇率历史,您必须启用配置并使用Doctrine。
tbbc_money: currencies: ["USD", "EUR"] reference_currency: "EUR" enable_pair_history: true
然后您可以使用此服务
$pairHistoryManager = $this->get("tbbc_money.pair_history_manager"); $dt = new \DateTime("2012-07-08 11:14:15.638276"); // returns ratio for at a given date $ratio = $pairHistoryManager->getRatioAtDate('USD',$dt); // returns the list of USD ratio (relative to the reference value) $ratioList = $pairHistoryManager->getRatioHistory('USD',$startDate, $endDate);
RatioStorage
有两种存储比率的方式:CSV文件或Doctrine。默认情况下,TbbcMoneyBundle使用CSV文件。
如果您想切换到Doctrine存储,请编辑您的config.yml
tbbc_money: storage: doctrine
更新您的数据库模式
./bin/console doctrine:schema:update --force
使用Doctrine存储,货币汇率将使用默认的实体管理器,并将数据存储在
在MoneyFormatter中使用自定义NumberFormatter
MoneyFormatter::localizedFormatMoney(服务'tbbc_money.formatter.money_formatter')使用php NumberFormatter类(https://php.ac.cn/manual/en/numberformatter.formatcurrency.php)来格式化货币。
您可以
- 将您自己的\NumberFormatter实例作为MoneyFormatter::localizedFormatMoney的参数
- 子类化MoneyFormatter并重写getDefaultNumberFormater方法以设置应用程序范围的NumberFormatter
在不使用Doctrine的情况下使用TbbcMoneyBundle
为了在不使用Doctrine的情况下使用TbbcMoneyBundle,您必须禁用对偶历史服务。
tbbc_money:
enable_pair_history: true
注意:您可以考虑编写自己的PairHistoryManager以用于MongoDB或Propel,这很容易做到。请不要犹豫,提交包含您的代码和测试的PR。
优化
在您的config.yml中,您可以
- 选择要使用的模板引擎。默认情况下,仅加载Twig。
- 定义单位后的小数位数(例如:12.25€:2位小数;11.5678€:4位小数)
tbbc_money: currencies: ["USD", "EUR"] reference_currency: "EUR" decimals: 2 enable_pair_history: true ratio_provider: tbbc_money.ratio_provider.yahoo_finance
贡献
- 查看问题列表。
- 分支
- 编写测试(无论是新功能还是错误)
- 提交PR
需求
- PHP 5.3.9+
- Symfony 2.8+
作者
Philippe Le Van - kitpages.fr - twitter : @plv
Thomas Tourlourat - Wozbe - twitter: @armetiz
状态
稳定
什么是功能性的
- 货币库的集成
- 配置解析器
- 配对管理器
- Travis CI集成
- 表单集成
- 表单的Twig展示
- Twig过滤器
- 创建和显示比率的命令
- 自动获取比率(与2个比率提供者)
- 货币比率的记录