Forms Symfony2嵌入表单无效,尽管cascade_验证为假

Forms Symfony2嵌入表单无效,尽管cascade_验证为假,forms,symfony,Forms,Symfony,在FormContractType中,我需要与客户的关联,客户本身与公司和账单地址有关联。但是这3个嵌套实体的数据本身在合同视图中根本不应该是可编辑的。这就是为什么合同中的customer Manytone关系字段是隐藏的 但是,出于显示目的,我需要表单中的整个customer对象,包括基础公司和账单地址,但为只读。这就是为什么我在合同表单类型中添加了一个额外的字段customerFullObject——它没有映射=>false。因为它是一个未映射的字段,所以我通过表单事件设置数据 现在,当我编

在FormContractType中,我需要与客户的关联,客户本身与公司和账单地址有关联。但是这3个嵌套实体的数据本身在合同视图中根本不应该是可编辑的。这就是为什么合同中的customer Manytone关系字段是隐藏的

但是,出于显示目的,我需要表单中的整个customer对象,包括基础公司和账单地址,但为只读。这就是为什么我在合同表单类型中添加了一个额外的字段customerFullObject——它没有映射=>false。因为它是一个未映射的字段,所以我通过表单事件设置数据

现在,当我编辑合同数据时,客户的公司地址和账单地址数据将无效。 如果我删除/注释整个customerFullObject部分,则一切正常

我不明白,未映射字段如何/为什么会更改实体的数据。 我怎样才能防止Symfony这样做?还是有更好的模式/方式来实现我的目标?我在文件里找不到任何东西

以下是为简洁起见从模型中删除名称空间的一些代码片段:

Contract.php Customer.php ContractType.php CustomerType.php
我对这种嵌入式表单没有太多经验,但您是否尝试过在这里传递克隆客户对象:$form->get'customerFullObject'->setData$event->getData->getCustomer;与其是未映射的客户,不如映射客户并显示为只读。或者,如果您不想显示,客户可能是一个隐藏字段。然后,控制器可以为合同设置客户,所有内容都应该很好地持久化。@lackovic10这会起作用,但对象相当大,克隆会产生相当大的影响overhead@geoB我已经为客户设置了一个映射字段,该字段被隐藏以设置合同和客户之间的关系。但是隐藏字段只有关于Id的信息。但是我还需要其余的信息,因为我想显示一些附加信息。
/**
 * @ORM\Entity
 */
class Contract {
    /**
     * @var Customer
     * @ORM\ManyToOne(targetEntity="Customer", inversedBy="contracts")
     * @Assert\Type(type="Customer")
     * @Assert\NotBlank(message = "customer.notBlank")
     **/
    private $customer;

    // Other fields left out as irrelevant.
}
/**
 * @ORM\Entity
 */
class Customer {
    /**
     * @var Company
     * @ORM\OneToOne(targetEntity="Company")
     * @Assert\NotBlank(message="company.notBlank")
     **/
    private $company;

    /**
     * @var Address
     * @ORM\OneToOne(targetEntity="Address")
     * @Assert\NotBlank(message="billingAddress.notBlank")
     **/
    private $billingAddress;

    /**
     * @var ArrayCollection
     * @ORM\OneToMany(targetEntity="Contract", mappedBy="customer", orphanRemoval=true, cascade={"all"})
     **/
    private $contracts;

    // Other fields left out as irrelevant.
}
class ContractType extends AbstractType {
    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder->add(
            'customer',
            'customerHiddenType',
            array(
                'label' => 'contract.customer',
            )
        );

        $builder->add(
            'customerFullObject',
            'customerType',
            array(
                'cascade_validation' => false,
                'mapped' => false
            )
        );

        $builder->addEventListener(FormEvents::POST_SET_DATA, function (FormEvent $event) {
                $form = $event->getForm();
                $editMode = $form->getConfig()->getOption('editMode');
                if (!empty($editMode) && $editMode === RequestAction::CREATE()) {
                    $form->remove('customerFullObject');
                } else {
                    $form->get('customerFullObject')->setData($event->getData()->getCustomer());
                }
            }
        );

        // Other children left out as irrelevant.
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver) {
        $resolver->setDefaults(
             array(
                 'data_class' => 'Contract',
                 'cascade_validation' => true
             )
        );
    }

    public function getName() {
        return 'contractType';
    }
}
class CustomerType extends AbstractType {
    public function buildForm(FormBuilderInterface $builder, array $options) {
        $builder->add(
            'company',
            'companyType',
            array(
                'cascade_validation' => false,
                'label' => 'customer.company'
            )
        );

        $builder->add(
            'billingAddress',
            'addressType',
            array(
                'cascade_validation' => false,
                'label' => 'customer.billingAddress'
            )
        );

        // Other children left out as irrelevant.
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver) {
        $resolver->setDefaults(
             array(
                 'data_class' => 'Customer',
                 'cascade_validation' => true
             )
        );
    }

    public function getName() {
        return 'customerType';
    }
}