【问题标题】:Symfony2 validation groups and mappingSymfony2 验证组和映射
【发布时间】:2013-11-11 06:03:09
【问题描述】:

目前我已经成功使用了验证组,但现在我被验证组和嵌套映射实体困住了。

我将通过一个简化的例子来解释这个问题。

我的实体:地址、损坏、设备

/**
 * @ORM\Entity()
 */
class Address extends ...
{
    /**
     * @var string
     * @ORM\Column(type="string", name="postcode", nullable=true)
     * @Assert\NotBlank(
     *     groups={
     *     "damage_responsible_address",
     *     "appliance_repairer_address",
     *     })
     */
    private $postcode;

    ...


/**
 * @ORM\Entity()
 */
class Damage extends ...
{
    /**
     * @var boolean
     * @ORM\Column(type="boolean", name="responsible", nullable=true)
     * @Assert\NotBlank(groups={"damage"})
     */
    private $responsible;

    /**
     * @ORM\OneToOne(targetEntity="Address", cascade={"persist","remove"})
     * @ORM\JoinColumn(name="responsible_address_id", referencedColumnName="id")
     * @Assert\Valid()
     */
    private $responsibleAddress;

    /**
     * @ORM\ManyToMany(targetEntity="Appliance", orphanRemoval=true, cascade={"persist", "remove"})
     * @ORM\JoinTable(name="coronadirect_cuzo_home_damage_appliances",
     *      joinColumns={@ORM\JoinColumn(name="damage_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="appliance_id", referencedColumnName="id")}
     *      )
     */
    private $appliances;

    ...


/**
 * @ORM\Entity()
 */
class Appliance extends ...
{
    /**
     * @var boolean
     * @ORM\Column(type="boolean", name="to_repair", nullable=true)
     * @Assert\NotBlank(groups={"appliance"})
     */
    private $toRepair;

     /**
     * @ORM\OneToOne(targetEntity="Address", cascade={"persist","remove"})
     * @ORM\JoinColumn(name="repairer_address_id", referencedColumnName="id")
     * @Assert\Valid()
     */
    private $repairAddress;

    ...

为了定义我的表单,我使用了 AddressType、DamageType 和 ApplianceType:

class DamageType extends ...
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
         $builder->add('appliances', 'collection', array(
            'type' => 'home_damage_appliance_type',
            'allow_add' => true,
            'allow_delete' => true,
            'prototype' => true,
            'options' => array(
                'cascade_validation' => true,
            )
        ));

        $builder->add('responsible', 'choice', array(
            'choices' => $this->getYesNoChoiceArray(),
            'expanded' => true,
            'multiple' => false,
        ));

        $builder->add('responsibleAddress', 'address_type', array(
            'required' => true
        ));

        ...
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
                'data_class' => 'Damage',
                'cascade_validation' => true,
                'validation_groups' =>
                    function(FormInterface $form) {

                        $groups = array('damage');

                        if ($form->getData()->getResponsible() == true) {
                            $groups[] = 'damage_responsible_address';
                        }

                        return $groups;
                    }
        ));
    }

当在表单中将责任设置为 true 时,我将添加damage_responsible_address 组。 否则我不希望验证地址。

class ApplianceType extends ...
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        $builder->add('toRepair', 'choice', array(
            'choices' => $this->getYesNoChoiceArray(),
            'expanded' => true,
            'multiple' => false,
        ));

        $builder->add('repairAddress', 'address_type', array(
            'required' => true
        ));

        ...
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
                'data_class' => 'Appliannce',
                'cascade_validation' => true,
                'validation_groups' =>
                    function(FormInterface $form) {

                        $groups = array('appliance');

                        if ($form->getData()->getToRepair() == true) {
                            $groups[] = 'appliance_repairer_address';
                        }

                        return $groups;
                    }
        ));
    }

同上,当 toRepair 为真时,我要验证地址。

出了什么问题?

我负责的损坏是真的,而要维修的设备是假的,表格确实在负责的地址上给出了验证错误,但也在设备地址上给出了验证错误。

反之亦然:当设备地址无效(toRepar 为真)时,responsibleAddress 也无效(即使责任为假)。

地址验证组不查看它们定义的表单,而只是将它们附加到表单中的每个地址项。

是否可以仅为表单定义特定的验证组?

我正在使用 Doctrine 和 Symfony 2.3.6。

【问题讨论】:

  • 成功了吗?
  • 如果您能针对如此重要的问题提供反馈,那就太好了。
  • 我通过对希望地址有效的每个实体使用类内约束来修复它。因为其中一些不需要验证。正如@forgottenbas 已经说过的那样,它是 OR 验证不能使这项工作。如果该组一旦应用于地址,它将用于表单中的所有地址实体。

标签: forms validation symfony symfony-forms symfony-2.3


【解决方案1】:

问题在于 symfony 使用 OR-logic 来验证组。因此,您应用其中一个组来形成它将在两种情况下验证地址。

如果将组移动到父实体,它不会解决问题吗?

/**
 * @ORM\Entity()
 */
class Damage extends ...
{
    /**
     * @ORM\OneToOne(targetEntity="Address", cascade={"persist","remove"})
     * @ORM\JoinColumn(name="responsible_address_id", referencedColumnName="id")
     * @Assert\Valid(
     *     groups={
     *     "damage_responsible_address"
     *     })
     * )
     */
    private $responsibleAddress;
}

【讨论】:

  • 他们不使用 OR 逻辑,问题不在于他们在两种情况下都验证,而是所有地址 invalidate,非 ?
【解决方案2】:

斜体 表示一般情况,粗体 表示此问题的特殊情况。

地址验证组不查看它们定义的表单,而只是将它们附加到表单中的每个地址项。

没错,您在 DamageType 中的validation_group 回调为所有表单设置了validation_group,并且当您使用cascade_validation 时,为表单包含的所有嵌入地址类型。它没有理由应该理解您只想将其设置为负责的地址。

通常,通过回调为父表单设置验证组,将级联验证设置为 true,将使所有子表单都针对该验证组进行验证。如果我们想为每个孩子设置不同的验证组,我们必须在children formtype中放置一个验证组回调。

您必须将验证回调放在 AddressType 中,以便为每个地址表单调用它。当然,为此,每个地址实体都必须知道其所有者。 p>

验证回调的替代方法是Group Sequence Provider。但是在任何情况下,您仍然必须在每个 Address 实体中设置验证组,而不是在 Damage 中,因此您的 Adress 必须仍然知道它的所有者。

【讨论】:

  • 顺便问一下@gremo,你打算奖励你的赏金吗?
  • 这篇文章对我很有帮助。我为父表单设置了组,即使在表单中设置了默认验证组,也会强制对子表单进行错误验证。解决方案是将简单的验证移到相关表单类中的约束中,或者在子表单类型中使用特定的回调。
【解决方案3】:

我知道这已经有一段时间了,但这里是可以回答 symfony v3 问题的文档:

http://symfony.com/doc/current/form/data_based_validation.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-17
    • 1970-01-01
    • 1970-01-01
    • 2014-11-01
    • 2011-03-06
    • 1970-01-01
    • 2020-05-25
    • 2013-10-01
    相关资源
    最近更新 更多