symfgenus/money-bundle

此包已被废弃,不再维护。作者建议使用tbbc/money-bundle包。

这是一个集成了moneyphp/money库(Fowler模式)的Symfony扩展包:https://github.com/moneyphp/money

安装次数: 1,236

依赖者: 0

建议者: 0

安全: 0

星标: 0

关注者: 0

分支: 70

类型:symfony-bundle

5.0 2022-05-16 11:26 UTC

README

Build Status PHP Symfony Downloads Latest Stable Version license

SensioLabsInsight

此扩展包用于将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'。

此包包含三个汇率提供者

您可以在 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存储,货币汇率将使用默认的实体管理器,并将数据存储在tbbc_money_doctrine_storage_ratios

在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

贡献

  1. 查看问题列表
  2. 分支
  3. 编写测试(无论是新功能还是错误)
  4. 提交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个比率提供者)
  • 货币比率的记录