【问题标题】:Complex data structure using only the Form component仅使用 Form 组件的复杂数据结构
【发布时间】:2013-01-29 22:40:27
【问题描述】:

我正在开发一个包含可定制产品的电子商务系统。每个产品可能有一些选项,就其本身而言,可能具有消费者选择的一个或多个值。由于我的用户的高度定制(某些产品可能有超过 1M 的变体),我不能使用变体方法,所以我需要坚持客户选择的选项组合。

一旦每个产品可能有不同的选项,表单选项就会动态组合。这种形式应该将用户选择转换为关系数据库的可存储结构。

基本上,这是我的方案(我的尝试):

  • 产品
  • 选项
  • 选项值
  • 产品选项
  • 订购
  • 订单项
  • OrderItemOption

夹具:

  • 选项: 1#沙拉
    • 价值观: 1#番茄、2#生菜、3#泡菜、3#胡萝卜
  • 产品:汉堡包
  • 产品选项: 1#Salad
    • 价值观: 1#番茄、2#生菜、Picles

我的目标是这样的:

class OrderItemType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $field = $builder->create('options', new OptionPickerType(), ['options' => $options['product']->getOptions()]);
        $field->addModelTransformation(new FixOptionIndexTransformer());
        $builder->add($field);
    }
}

class OptionPickerType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        foreach ($options['options'] as $productOption) {
            $name = $productOption->getId();
            $builder->add($name, 'choice', array(
                'choice_list'   => new ObjectChoiceList($productOption->getValues(), 'label', array(), null, 'id'),
                'multiple' => true,
                'cascade_validation' => true,
                'property_path' => '['.$name.']'
            ));
        }
    }
}

$form = $factory->create(new OrderItemType(), ['product' => $product]);

if ($request->isMethod('POST')) {
    $form->bind($request);

    if ($form->isValid()) {
        $item = $form->getItem(); // A collection of ItemOption filled with the OptionValue picked out from Choice field
    }
}

此配置将按预期返回 OptionValue 数组的集合。事实上,这对我的目的来说是不够的。我真正需要的是一个扁平的集合,其中包含所有选择的值以及一些额外的数据:

class ItemOption
{
    protected $item;
    protected $productOption;
    protected $option; // $productOption->getName()
    protected $optionValue;
    protected $value; // / $optionValue->getLabel()
}

如您所见,Choice 字段的值实际上在 ItemOption 内部。

经过几天的尝试,我无法弄清楚如何做到这一点,甚至无法思考其他方法。

你能帮帮我吗?

【问题讨论】:

  • 这里是使用框架的真正痛苦之处。您的问题急需一个 NoSQL 解决方案,而这并不是 Symfony 的设计初衷。
  • @MikeBrant Symfony 是一个可以与许多不同后端一起工作的框架。它没有附带特定的数据持久性后端。它通常与 Doctrine2 一起使用,但也可以与 Propel 一起使用,或者配置为使用您想要的任何其他后端。此外,Doctrine2 提供了一个 ODM,这对于从未使用过像 Mongo 这样的 nosql 数据库做过任何事情的人来说是微不足道的。总之,Symfony 不是问题。他所询问的表单组件是可用于进行表单数据操作的最复杂的类之一,并且可以与纯 PHP 类一起使用。
  • @MikeBrant,感谢您的考虑。是的,我同意这是 NoSQL 的情况,但我们不能使用这个。 Symfony2 表单组件是一个强大的工具,可能还有一些更复杂的解决方案(比如从头开始创建一个新的字段类型),但我不知道。
  • 你已经用 symfony-2.1 和 symfony-2.2 标记了这个问题。您使用的是哪个版本?我问的原因是,在 2.2 中,一个新的 PropertyAccess 组件是从 2.1 中 Form 组件中存在的类创建的,解决方案可能在于利用这些类。

标签: php symfony symfony-2.1 symfony-forms symfony-2.2


【解决方案1】:

首先,当我发现很难将表单映射到我的模型时,我通常会发现模型过于复杂。简化模型以在必要时具有清晰的关系和中间对象(在不必要的情况下没有)通常会有所帮助。

话虽如此,在我看来,您的选项选择器上的模型转换器应该可以完成这项工作:

foreach ($options['options'] as $productOption) {
    // ...
}

$builder->addModelTransformer(new CallbackTransformer(
    // model to normalized
    // needed when setting default values, not sure if required in your case
    function ($modelData) {
    },
    // normalized to model
    // converts the array of arrays of OptionValues to an array of ItemOptions
    function ($normalizedData) {
        $itemOptions = array();

        foreach ($normalizedData as $optionValues) {
            foreach ($optionValues as $optionValue) {
                $itemOption = new ItemOption();
                $itemOption->setProductOption($optionValue->getProductOption());
                $itemOption->setOptionValue($optionValue);
                $itemOptions[] = $itemOption;
            }
        }

        return $itemOptions;
    }
));

【讨论】:

  • 谢谢,Bernhard,我会试试你的建议。
猜你喜欢
  • 1970-01-01
  • 2012-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多