Symfony2验证组和映射

时间:2013-10-31 09:44:23

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

现在我已经成功使用了验证组,但现在我遇到了验证组和嵌套映射实体。

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

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

/**
 * @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为true时,我想验证地址。

出了什么问题?

我对Damage的责任是真的,而且设备toRepair是假的,表格确实会在负责的地址上给出验证错误,但也会在设备地址上给出验证错误。

对于arround的另一种方式相同:当设备地址无效(toRepar为true)时,trustedAddress也无效(即使负责人为假)。

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

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

我使用的是Doctrine和Symfony 2.3.6。

3 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:1)

italic 适用于一般情况,粗体适用于此问题的特定情况。

  

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

是的,您在损坏类型中的validation_group回调为所有表单设置了validation_group,并且当您使用cascade_validation时,对于表单包含的所有嵌入AddressType。没有理由它应该理解你只想为负责任的地址设置它。

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

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

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

答案 2 :(得分:1)

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

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