首页 > 解决方案 > Symfony Forms - 获取多个未映射的集合以合并并提交到单个实体

问题描述

我有一个 WholesaleRuleset 实体 ( https://pastebin.com/PYjHmGi1 ) 与 WholesaleRuleQuantityStep ( https://pastebin.com/JLrQfQV7 ) 有 M2M关系

这种关系是正确建立的。它在 WholesaleRulesetType ( https://pastebin.com/VGCdABb9 )中完美运行。这是提交的规则集的“编辑”页面及其数量步骤规则集合。

这就是我的要求变得棘手的地方。如您所见,管理员可以使用不同的选项卡在分类、产品和分类范围内添加数量步骤。

我正在尝试将多个单独的集合提交给同一个实体。:

WholesaleRulesetType 最终看起来像这样(甚至在这个 trait https://pastebin.com/F5B97xgW​​ 中添加了必要的收集方法)。所需的表格类型:

            ->add(
                'quantityStepRulesByTaxon',
                CollectionType::class,
                [
                    'entry_type' => WholesaleRuleQuantityStepByTaxonType::class,
                    'allow_add' => true,
                    'allow_delete' => true,
                    'by_reference' => false,
                ]
            )
            ->add(
                'quantityStepRulesByProduct',
                CollectionType::class,
                [
                    'entry_type' => WholesaleRuleQuantityStepByProductType::class,
                    'allow_add' => true,
                    'allow_delete' => true,
                    'by_reference' => false,
                ]
            )
            ->add(
                'quantityStepRulesByProductVariant',
                CollectionType::class,
                [
                    'entry_type' => WholesaleRuleQuantityStepByProductVariantType::class,
                    'allow_add' => true,
                    'allow_delete' => true,
                    'by_reference' => false,
                ]
            );

并且在请求数据中它们都结合起来提交给 WholesaleRuleQuantityStep。它必须是单独的集合,因为您不能同时多次使用同一个表单域。我已经坚持了一个月。Sylius 或 Symfony 休闲裤没有回应。请。帮助。

标签: phpsymfonydoctrine-ormsymfony-formssylius

解决方案


(好的,我希望我现在能得到这个,为了简洁(和懒惰)我已经缩短了所有的类名和字段名,因为你的 MWE 非常广泛而且不必要地冗长。所以,你必须将我的实体 RuleSet 映射到你的 WholesaleRuleset和我对您 WholesaleRuleQuantityStep 的规则。)

我相信您有两个实体 RuleSet 和 Rule,通过多对多连接。这些规则基本上具有三种类型的产品、变体和分类单元。

现在你想在不同的表单字段中显示这些规则,你试图通过你的 trait 在你的对象上创建新属性来缓解这些规则,但据我所知,这些根本没有连接到多对多场地。

为了以后也能够编辑您的实体,我提出以下建议: 使您的“字段”完全虚拟化。对于 Symfony 表单,“字段”实际上是属性访问器可以访问以进行读取和写入的东西(获取和设置,或者在集合的情况下获取和添加和删除)。

我已经这样做了几次,并且我喜欢这个概念,因为您的每种类型的规则都这样做:

// in class RuleSet
protected $rules; // <-- collection containing *all* rules.

public function getTaxonRules(): array {
    // extract the rules of type taxon
    return array_filter(function($rule) {
        return $rule->getType() == 'taxon';
    }, $this->rules->toArray());
}
public function addTaxonRule(Rule $rule) {
    // you might even set the type here ;o)
    if (!in_array($rule, $this->getTaxonRules()) && $rule->getType() == 'taxon') {
        $this->rules->add($rule);
    }
}
public function removeTaxonRule(Rule $rule) {
    if (in_array($rule, $this->getTaxonRules()) && $rule->getType() == 'taxon') {
        $this->rules->removeElement($rule);
    }
}
// add these functions:
// public function getVariantRules() ...
// public function addVariantRule(Rule $rule) ...
// public function removeVariantRule(Rule $rule) ...
// public function getProductRules() ...
// public function addProductRule(Rule $rule) ...
// public function removeProductRule(Rule $rule) ...

这样,实体就好像它有一个字段一样taxonRules,因为如果不是它与外部世界的接口(即 getter 和 setter),什么才是真正的字段。外部并不关心内部的实现细节。

注意:$rule->getType() == ...真的不需要测试。此外,不需要任何表单事件或其他花哨的东西,您现在可以继续使用三个表单字段。

旁注:我真的不喜欢将Collections 暴露在我的实体之外。对集合的任何更改都应该通过 setter/adders/removers 发生。返回一个数组也会byReference => false过时。在我看来,在这种情况下,收藏是不值得的。你也许可以让它工作,但代码量会更大(没有任何收获,恕我直言)。

(边烧:尤达条件已经过时了!另外:尝试向您的 Rule 添加一个函数isTaxonRule(): bool,不要在您的代码中使用“魔术”字符串,它们不支持自动完成,至少在您的 Rule 类上使用常量,$rule->getType() === Rule::TAXON但是,不要直接使用字符串。错字会弄乱您的代码,您可能只会在生产中注意到;o) )


推荐阅读