Php 仅使用表单组件的复杂数据结构
我正在开发一个带有可定制产品的电子商务系统。每个产品都可能有一些选项,消费者可以选择这些选项中的一个或多个值。我不能使用变体方法,因为我的用户定制程度很高(有些产品可能有超过100万个变体),所以我需要坚持客户选择的选项组合 一旦每个产品可能有不同的选项,表单选项就会动态组合。此表单应将用户选择转换为关系数据库的可存储结构 基本上,这是我的场景(我的尝试):Php 仅使用表单组件的复杂数据结构,php,symfony,symfony-2.1,symfony-forms,symfony-2.2,Php,Symfony,Symfony 2.1,Symfony Forms,Symfony 2.2,我正在开发一个带有可定制产品的电子商务系统。每个产品都可能有一些选项,消费者可以选择这些选项中的一个或多个值。我不能使用变体方法,因为我的用户定制程度很高(有些产品可能有超过100万个变体),所以我需要坚持客户选择的选项组合 一旦每个产品可能有不同的选项,表单选项就会动态组合。此表单应将用户选择转换为关系数据库的可存储结构 基本上,这是我的场景(我的尝试): 产品 选择权 期权价值 产品选项 命令 订单项 OrderItemOption 固定装置: 选项:1#沙拉 值:1个番茄、2个生菜
- 产品
- 选择权
- 期权价值
- 产品选项
- 命令
- 订单项
- OrderItemOption
- 选项:1#沙拉
- 值:1个番茄、2个生菜、3个泡菜、3个胡萝卜
- 产品:汉堡包
- 产品选项:1#沙拉
- 值:1#番茄、2#莴苣、苦瓜
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()
}
如您所见,选择值字段实际上位于ItemOption内
经过几天的尝试,我不知道如何做到这一点,甚至想不出其他方法
你能帮我吗?首先,当我发现很难将表单映射到模型时,我后来发现模型过于复杂。在这方面,简化模型以在必要时具有清晰的关系和中间对象(在不必要时没有中间对象)通常会有所帮助 也就是说,在我看来,您的选项选择器上的模型转换器应该完成以下工作:
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;
}
));
首先,当我发现很难将表单映射到模型时,我后来发现模型过于复杂。在这方面,简化模型以在必要时具有清晰的关系和中间对象(在不必要时没有中间对象)通常会有所帮助 也就是说,在我看来,您的选项选择器上的模型转换器应该完成以下工作:
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;
}
));
在这里,使用框架可能是一个真正的痛苦。您的问题迫切需要一个NoSQL解决方案,而Symfony并不是专门设计来解决的。@MikeBrant Symfony是一个可以处理许多不同后端的框架。它没有特定的数据持久性后端。它通常与Doctrine2一起使用,但也可以与spreep一起使用,或者配置为使用您想要的任何其他后端。此外,Doctrine2提供了一个ODM,对于从未使用过像Mongo这样的nosqldb的人来说,它是微不足道的。简而言之,Symfony不是问题所在。他询问的表单组件是可用于表单数据操作的最复杂的类之一,可以与纯PHP类一起使用。@MikeBrant,感谢您的考虑。是的,我同意这是NoSQL的一个例子,但我们不能使用这个。Symfony2表单组件是一个功能强大的工具,可能有更复杂的解决方案(比如从头创建一个新的字段类型),但我不知道。您已经用symfony-2.1和symfony-2.2标记了这个问题。您使用的是哪个版本?我提出这个问题的原因是,在2.2中,一个新的PropertyAccess组件是从2.1中表单组件中存在的类创建的,解决方案可能在于利用这些类。在这里,使用框架可能是一个真正的难题。您的问题迫切需要一个NoSQL解决方案,而Symfony并不是专门设计来解决的。@MikeBrant Symfony是一个可以处理许多不同后端的框架。它没有特定的数据持久性后端。它通常与Doctrine2一起使用,但也可以与spreep一起使用,或者配置为使用您想要的任何其他后端。此外,Doctrine2提供了一个ODM,对于从未使用过像Mongo这样的nosqldb的人来说,它是微不足道的。简而言之,Symfony不是问题所在。他询问的表单组件是可用于表单数据操作的最复杂的类之一,可以与纯PHP类一起使用。@MikeBrant,感谢您的考虑。是的,我同意这是NoSQL的一个例子,但我们不能使用这个。Symfony2表单组件是一个功能强大的工具,可能有更复杂的解决方案(比如从头创建一个新的字段类型),但我不知道。您已经用symfony-2.1和symfony-2.2标记了这个问题。您使用的是哪个版本?我问这个问题的原因是,在2.2中,一个新的PropertyAccess组件是从2.1中表单组件中存在的类创建的,解决方案可能在于利用这些类。谢谢,Bernhard,我会试试你的建议。谢谢,Bernhard,我会试试你的建议。