【问题标题】:Symfony 4 - Forms CollectionType get specific dataSymfony 4 - Forms CollectionType 获取特定数据
【发布时间】:2019-09-13 11:39:18
【问题描述】:

我有两种实体:“Affaire”和“Pointage”。我的 Affaire Entity 与我的 Pointage Entity 有 OneToMany 关系:

//App\Entity\Affaire.php

/**
 * @ORM\OneToMany(targetEntity="App\Entity\Pointage", mappedBy="numAffaire")
 */
    private $pointages;
//App\Entity\Pointage.php

/**
 * @ORM\ManyToOne(targetEntity="App\Entity\Affaires", inversedBy="pointages")
 * @ORM\JoinColumn(nullable=false)
 */
    private $numAffaire;

我为我的 Affaire 实体创建了一个表单,它获取与“Affaire”相关的“Pointages”。

//App\Form\AffaireType.php

class AffaireType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('numAffaire');
        $builder->add('descAffaire');
        $builder->add('pointages', CollectionType::class, [
            'entry_type' => PointageType::class,
            'entry_options' => ['label' => false, 'pointages' => $options['pointages']],
        ]);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setRequired(['pointages']);
        $resolver->setDefaults([
            'data_class' => Affaires::class,
        ]);
    }

}

//App\Form\PointageType.php

class PointageType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('heurePointage');
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setRequired(['pointages']);
        $resolver->setDefaults([
            'data_class' => Pointage::class,
        ]);
    }
}

我的问题是:如何过滤我的 AffaireType 类中的“Pointages”?例如,我想获取与我的 Affaire 相关联的所有积分,其中我的积分 id 小于 100。是否可以在某处进行查询?

【问题讨论】:

    标签: php forms symfony collections formbuilder


    【解决方案1】:

    !!!我强烈建议您不要在那里做什么!!!

    原因:

    您的表单类型的数据类设置为实体(据我所知)。该表单旨在修改它所提供的对象(您的实体)。现在,如果您过滤该表单类型的字段,然后表单尝试设置“新”值,则所有不在表单提交中的 Pointage 对象(特别是所有被过滤out em>) 可能会被删除。如果表单调用 setPointages,您将丢失数据 - 我不太确定,是否总是调用它,即使 allow_add/allow_remove 设置为 false。如果你忘记了,这会让你的生活变得悲惨。我相信这总是被称为标准CollectionType

    阅读一些代码后更新:关于setPointages的调用:如果addPointage/removePointage存在,它们将被调用。但是,PropertyAccessor(属性访问组件)从目标对象(!)读取先前的值,并且将计算差异并相应地调用 add/remove -> 删除不在新集合中的任何实体

    可能的解决方法

    • 大量使用数据映射器/数据转换器/表单事件来以某种方式隐藏存在更多Pointage 实体的事实。这可能非常效果很好,但它使事情复杂化了很多,但仍然可能成为一个干净的解决方案。

      总体思路是:

      • 表单渲染:从实体获取(事务,所有积分)-> 你的转换器/映射器/表单事件处理程序(事务,所有 -> 过滤 积分)-> 表单(事务,过滤积分)
      • form submit: form (affaire, filter pointages) -> 你的transformer/mapper/form事件处理器(affaire, filtered -> "new all" pointages) -> 设置实体(affaire,所有积分)

      但是,您可能需要花费大量时间了解表单组件的内部结构才能正确安全地执行此操作……(一个指针是MergeCollectionListener,您可能能够适应您的需要, 你也可以看看ResizeFormListener, 它根据给定的数据添加和删除子表单。记住如果你过滤你的数据,你可能应该创建自己的集合类型并添加一个新的表单侦听器来优雅地处理所有事情)

    • 不要将其集成到AffaireType 中,而是添加另一个表单类型AffairePointageType,其中包含两个字段:affaireAffaireType 不带pointages)和pointagesCollectionType),并将其称为

      $filteredPointages = someFilterFunction($affaire->getPointages());
      $this->createForm(AffairePointageType::class, [
           'affaire' => $affaire,
           'pointages' => $filteredPointages,
      ], [
           'pointages' => ... //the option you provide for the CollectionType
      ]);
      

      您显然可以提供任何积分,由您喜欢的任何过滤器过滤,并且只会编辑您提供的那些,而与$affaire 相关的任何其他内容都保持不变。但是请注意,您必须自己处理添加或删除的积分。 (这可能会破坏关注点分离)

      本质上,这是以前解决方法的一个更易于理解的版本,其中所有过滤器逻辑都​​是外部的,但是由于表单没有传达“您可以编辑事务的积分”,而是“您可以同时编辑事务和一组可能相关或不相关的积分”,它在语义上很清楚,不会让未来的用户(包括你在内)感到惊讶。

    但是,我认为您的方法可能存在缺陷......但由于不清楚您实际想要达到的目标,因此很难提出适当的解决方案。

    如果只是“显示的(子)表单太多” - 那么它更多的是显示问题,可以并且可能应该通过 javascript 或 css (display:none) 或两者来修复。 (这是恕我直言更好的方法,不会与表单逻辑和/机制混淆)。

    【讨论】:

    • 感谢您的建议,我会尝试您的解决方法! :)
    猜你喜欢
    • 1970-01-01
    • 2020-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-06
    • 1970-01-01
    • 1970-01-01
    • 2017-01-15
    相关资源
    最近更新 更多