Symfony:一种形式的多个货币领域

时间:2014-03-17 20:14:12

标签: php forms symfony currency

想象一下,你有一个物品实体。在此商品实体中,有一种获取该商品价格的方法。价格以3种不同的格式保存:欧元,美元和英镑。

实体看起来像这样:

实体WebshopItem.php

class WebshopItem
{

    /**
     * @var integer
     */
    private $id;

    /**
     * @Gedmo\Translatable
     * @var string
     */
    private $title;

    ......

    /**
     * @var \Doctrine\Common\Collections\Collection
     */
    private $prices;
}

实体WebshopItemPrice.php

class WebshopItemPrice
{

    /**
     * @var integer
     */
    private $id;

    /**
     * @var string
     */
    private $currency;

    /**
     * @var string
     */
    private $price;

    /**
     * @var \WebshopItem
     */
    private $webshopItem;
}

现在我想创建一个表单,其中包含3个输入字段。为此,我认为最好使用金钱领域。所以我正在创建这样的表单:

public function buildForm(FormBuilderInterface $builder, array $options)
{
     $builder
         ->add('title')
         ....
         ->add('prices', new WebshopPricesType());
}

webshopPricesType如下所示:

public function buildForm(FormBuilderInterface $builder, array $options)
{
     $builder
         ->add('eur', 'money', array('currency' => 'EUR', 'data_class' => 'bundlePath\Entity\WebshopItemPrice'))
         ->add('usd', 'money', array('currency' => 'USD', 'data_class' => 'bundlePath\Entity\WebshopItemPrice'))
          ->add('gbp', 'money', array('currency' => 'GBP', 'data_class' => 'bundlePath\Entity\WebshopItemPrice'));
}

现在渲染3个正确的字段。我只需要在编辑时填写它们,保存时我必须确保它们已保存。我正在考虑使用数据转换器来找到正确的实体,但这不起作用。

如何在编辑时确保正确预填充所有3个字段,单击保存时,会保存3个价格?

或者我应该以完全不同的方式做到这一点?

谢谢!

1 个答案:

答案 0 :(得分:1)

我从来不喜欢DataTransformers因此我不会在这里使用它们,但它们可能很有用。

在这种特殊情况下,我会选择FormEvents并根据您实体所包含的数据动态构建表单。

<强> WebShopItemType

public function buildForm(FormBuilderInterface $builder, array $options)
{
     $builder
         ->add('title')
         .....
         ->add('prices', 'collection', array(
            'type' => new WebshopPricesType()
         ));
}

WebshopPricesType

class WebshopPricesType extends AbstractType{
    .....

    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        // Dynamically build form fields, **after** the data has been set
        $builder->addEventListener(FormEvents::POST_SET_DATA, function(FormEvent $event) use ($builder){
            /** @var $data WebshopItemPrice **/
            $data = $event->getData(); 

            $builder->add('price', 'money', array('currency' => $data->getCurrency()));
        });
    }

    public function setDefaults(OptionsResolverInterface $resolver){
        $resolver->setDefault(array(
            'data_class' => 'bundlePath\Entity\WebshopItemPrice'
        ));
    }

    .....
}

鉴于此,让我们完全粘合它:

public class SomeController extends Controller{
    public function insertAction(){
        $item = new WebshopItem();

        // be sure to initialize the $prices with new `ArrayCollection` 
        // in order to avoid NullPointerException
        // Also, be sure to bind WebshopItemPrice::$item
        $item
            ->addPrice(new WebshopItemPrice('EUR', 0))
            ->addPrice(new WebshopItemPrice('USD', 0))
            ->addPrice(new WebshopItemPrice('GBP', 0));

        // this is where POST_SET_DATA gets fired
        $form = $this->createForm(new WebShopItemType(), $item);

        // form is ready
    }

    public function editAction(){
        $item = ... // fetch or whatever, be sure to fetch prices as well

        // this is where POST_SET_DATA gets fired
        $form = $this->createForm(new WebShopItemType(), $item);

        // form is ready
    }
}

我把它放在Notepad ++中我不知道我是否做了一些拼写错误,但就逻辑问题而言 - 它应该有效;)