4

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

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

我的实体:地址、损坏、电器

/**
 * @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 为真),那么责任地址也无效(即使责任为假)。

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

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

我正在使用 Doctrine 和 Symfony 2.3.6。

4

3 回答 3

1

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

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

/**
 * @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;
}
于 2014-01-24T06:45:00.160 回答
1

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

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

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

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

您必须将验证回调放在 AddressType 中,以便为每个地址表单调用它。当然,为了做到这一点,每个 Adress 实体都必须知道它的所有者。

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

于 2014-01-28T22:16:12.070 回答
1

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

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

于 2017-01-05T12:42:34.233 回答