管理货币类型以编辑实体

Managing currency type to edit Entity

我正在使用包含 价格 信息的费用实体,为此我选择将金额 (int) 从货币 (字符串) 中分离出来。

/**
 * @var integer
 * 
 * @ORM\Column(name="price_amount", type="integer")
 */
private $priceAmount;

/**
 * @var string
 * 
 * @ORM\Column(name="price_currency", type="string", length=10)
 */
private $priceCurrency;

我正在使用 MoneyBundle(通过 TBBC 捆绑包)让 creation 表单显示支持的货币列表并让用户选择正确的货币。表单验证后,价格货币作为字符串存储在数据库中。

         // ExpenseType.php
         [...]
         use Tbbc\MoneyBundle\Form\Type\CurrencyType;
         [...]
         $builder
            ->add('priceAmount', NumberType::class, array(
                'label' => 'Amount spent',
                'attr' => array(
                    'placeholder' => "Amount",
                    'autocomplete' => 'off'
            )))
            ->add('priceCurrency', CurrencyType::class, array(
                'label' => 'Currency'
            ))

我正在尝试创建另一种表单类型 ExpenseEditType(扩展上面的 ExpenseType),这将帮助用户修改 金额(金额本身 + 其货币);显然,当我加载 ExpenseEditType 表单时,symfony 试图从我的学说实体创建一个 CurrencyType,但它只在数据库中找到一个字符串(例如 "CAD"、"EUR" 等)。

    $form = $this->createForm(new ExpenseEditType(), $expense);

引发异常:

Expected argument of type "Currency", "string" given

我的问题是:我怎样才能创建与创建表单相同类型的表单,并要求 symfony 显示相同的货币列表,并选择它在我的 price.currency 中找到的默认值场地?

我正在考虑 2 个选项(但我可能完全错了): - 使用 DataTransformer,但只是从 Symfony 开始,我真的对这类东西一无所知 - 在我的 Expense 实体中有一个额外的 Money 字段,它将在我的 2 个独立字段(金额/货币)之上的一个 Money 字段中存储金额+货币信息;我想坚持使用这两个单独的字段,以便更好地查询数据库中的可能性和易用性。

非常感谢您的帮助和建议! 文森特

感谢 Heah 和 Jason 的建议,我采用了 DataTransformer 解决方案并且运行良好 :) 我的代码基于 official documentation

查找下面的结果:

StringToCurrencyTransformer.php

<?php

namespace VP\AccountsBundle\Form\DataTransformer;

// some uses

class StringToCurrencyTransformer implements DataTransformerInterface {

    private $manager;

    public function __construct(ObjectManager $manager) {
        $this->manager = $manager;
    }

    /**
     * Transforms a String (currency_str) to a Currency
     * 
     * @param String|null $currency_str
     * @return Currency The Currency Object
     * @throws UnknownCurrencyException if Currency is not found
     */
    public function transform($currency_str) {
        if (null === $currency_str) {
            return;
        }
        try {
            $currency = new Currency($currency_str);
        } catch (UnknownCurrencyException $ex) {
            throw new TransformationFailedException(
            sprintf(
                    'The currency "%s" does not exist', $currency_str
            ));
        }
        return $currency;
    }

    /**
     * Transforms a Currency (currency) to a String
     * @param Currency $currency
     * @return String|null The ISO code of the currency
     * @throws TransformationFailedException if currency is not found
     */
    public function reverseTransform($currency) {
        // if no currency provided
        if (!$currency) {
            return;
        }
        $currency_str = $currency->getName();
        return $currency_str;
    }

}

我的新ExpenseEditType.php

<?php

// some uses

class ExpenseEditType extends ExpenseType   {

    private $manager;

    public function __construct(ObjectManager $manager) {
        $this->manager = $manager;
    }

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options) {
        parent::buildForm($builder, $options);
        $builder->remove('submitnew')
                ->remove('priceCurrency')
                ->add('priceCurrency', CurrencyType::class, array(
                    'label' => 'Devise',
                    'invalid_message' => 'Currency not found'
                ))
                ->add('submitnew', SubmitType::class, array(
                    'label' => 'Edit expense',
                    'attr' => array(
                        'class' => 'btn btn-primary',
                    )
        ));
        $builder->get('priceCurrency')
                ->addModelTransformer(new StringToCurrencyTransformer($this->manager));
    }

    /**
     * @return string
     */
    public function getName() {
        return 'vp_accountsbundle_expenseedit';
    }

我的service.yml:

services:
    app.form.type.expenseedit:
        class: VP\AccountsBundle\Form\ExpenseEditType
        arguments: ["@doctrine.orm.entity_manager"]
        tags:
            - { name: form.type }

我来自控制器的呼叫:

$form = $this->createForm(ExpenseEditType::class, $expense);

再次感谢大家!