我正在使用symfony 2.3,显然,我不能使用here讨论的'allow_extra_fields'选项。
我有一个主要的表单类型,RegistrationStep1UserType:
/**
* Class RegistrationStep1UserType
* @package Evo\DeclarationBundle\Form\Type
*/
class RegistrationStep1UserType extends AbstractType
{
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('customer', new RegistrationStep1CustomerType(), [
'label' => false,
'data_class' => 'Evo\UserBundle\Entity\Customer',
'cascade_validation' => true,
])
->add('declaration', 'evo_declaration_bundle_registration_step1_declaration_type', [
'label' => false,
'cascade_validation' => true,
])
;
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Evo\UserBundle\Entity\User',
'validation_groups' => false,
));
}
/**
* @return string
*/
public function getName()
{
return 'evo_declaration_bundle_registration_step1_user_type';
}
}
此表单类型包括嵌入式表单类型(在“声明”字段中),RegistrationStep1DeclarationType,注册为服务:
/**
* Class RegistrationStep1DeclarationType
* @package Evo\DeclarationBundle\Form\Type
*/
class RegistrationStep1DeclarationType extends AbstractType
{
/**
* @var EntityManagerInterface
*/
private $em;
/**
* @var EventSubscriberInterface
*/
private $addBirthCountyFieldSubscriber;
/**
* RegistrationStep1DeclarationType constructor.
* @param EntityManagerInterface $em
* @param EventSubscriberInterface $addBirthCountyFieldSubscriber
*/
public function __construct(EntityManagerInterface $em, EventSubscriberInterface $addBirthCountyFieldSubscriber)
{
$this->em = $em;
$this->addBirthCountyFieldSubscriber = $addBirthCountyFieldSubscriber;
}
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('birthLastname', null, [
'label' => 'Nom de naissance',
'attr' => [
'required' => true,
],
])
->add('nationality', 'entity', [
'label' => 'Nationalité',
'class' => 'Evo\GeoBundle\Entity\Country',
'property' => 'nationalityFr',
'attr' => [
'required' => true,
'class' => 'selectpicker',
],
'preferred_choices' => $this->fillPreferredNationalities(),
])
->add('birthCountry', 'entity', [
'label' => 'Pays de naissance',
'class' => 'Evo\GeoBundle\Entity\Country',
'property' => 'nameFr',
'empty_value' => '',
'empty_data' => null,
'attr' => [
'required' => true,
'class' => 'trigger-form-modification selectpicker',
],
'preferred_choices' => $this->fillPreferredBirthCountries(),
])
->add('birthCity', null, [
'label' => 'Ville de naissance',
'attr' => [
'required' => true,
],
])
;
$builder->get("birthCountry")->addEventSubscriber($this->addBirthCountyFieldSubscriber);
}
/**
* @return array
*/
private function fillPreferredNationalities()
{
$nationalities = $this->em->getRepository("EvoGeoBundle:Country")->findBy(["isDefault" => true]);
return $nationalities;
}
/**
* @return array|\Evo\GeoBundle\Entity\Country[]
*/
private function fillPreferredBirthCountries()
{
$countries = $this->em->getRepository("EvoGeoBundle:Country")->findBy(["isDefault" => true]);
return $countries;
}
/**
* @param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'required' => false,
'data_class' => 'Evo\DeclarationBundle\Entity\Declaration',
'validation_groups' => false,
));
}
/**
* @return string
*/
public function getName()
{
return 'evo_declaration_bundle_registration_step1_declaration_type';
}
}
此嵌入式表单类型在“birthCountry”字段上添加了订阅服务器(也注册为服务,因为它需要注入EntityManager)。
目标是根据birthCountry选择列表的值动态添加或删除一个额外的字段(称为“birthCounty”)(注意这里的2个字段不同,“birthCountry”和“birthCounty”)。
以下是订阅者:
/**
* Class AddBirthCountyFieldSubscriber
* @package Evo\CalculatorBundle\Form\EventListener
*/
class AddBirthCountyFieldSubscriber implements EventSubscriberInterface
{
/**
* @var EntityManagerInterface
*/
private $em;
/**
* AddBirthCountyFieldSubscriber constructor.
* @param EntityManagerInterface $em
*/
public function __construct(EntityManagerInterface $em)
{
$this->em = $em;
}
/**
* @return array
*/
public static function getSubscribedEvents()
{
return array(
FormEvents::POST_SET_DATA => 'postSetData',
FormEvents::POST_SUBMIT => 'postSubmit',
);
}
/**
* @param FormEvent $event
*/
public function postSetData(FormEvent $event)
{
$birthCountry = $event->getData();
$form = $event->getForm()->getParent();
$this->removeConditionalFields($form);
if ($birthCountry instanceof Country && true === $birthCountry->getIsDefault()) {
$this->addBirthCountyField($form);
}
}
/**
* @param FormEvent $event
*/
public function postSubmit(FormEvent $event)
{
$birthCountry = $event->getData();
$form = $event->getForm()->getParent();
if (!empty($birthCountry)) {
$country = $this->em->getRepository("EvoGeoBundle:Country")->find($birthCountry);
$this->removeConditionalFields($form);
if ($country instanceof Country && true === $country->getIsDefault()) {
$this->addBirthCountyField($form);
}
}
}
/**
* @param FormInterface $form
*/
private function addBirthCountyField(FormInterface $form)
{
$form
->add('birthCounty', 'evo_geo_bundle_autocomplete_county_type', [
'label' => 'Département de naissance',
'attr' => [
'required' => true,
],
])
;
}
/**
* @param FormInterface $form
*/
private function removeConditionalFields(FormInterface $form)
{
$form->remove('birthCounty');
}
}
在视图中,当“birthCountry”选项列表发生更改时,它会触发对控制器的AJAX请求,控制器会处理请求并再次呈现视图(如documentation about dynamic form submission中所述):
$form = $this->createForm(new RegistrationStep1UserType(), $user);
if ($request->isXmlHttpRequest()) {
$form->handleRequest($request);
} elseif ("POST" == $request->getMethod()) {
[...]
}
问题如下:
当我对birthCountry选项列表进行更改并选择一个应该隐藏“birthCounty”字段的国家/地区时,表单会在没有该字段的情况下正确呈现,但会显示错误消息:
Ce formulaire ne doit pas contenir des champs supplémentaires.
或
this form should not contain extra fields (in english)
我尝试了很多不同的解决方案:
'mapped' => false,
添加到birthCounty字段会触发错误。非常令人惊讶如果我在$form->getExtraData()
$form->handleRequest($request);
为空
但是在vendor \ symfony \ symfony \ src \ Symfony \ Component \ Form \ Extension \ Validator \ Constraints \ FormValidator中,我可以看到一个额外的字段
array(1) {
["birthCounty"]=>
string(0) ""
}
这里:
// Mark the form with an error if it contains extra fields
if (count($form->getExtraData()) > 0) {
echo '<pre>';
\Doctrine\Common\Util\Debug::dump($form->getExtraData());
echo '</pre>';
die();
$this->context->addViolation(
$config->getOption('extra_fields_message'),
array('{{ extra_fields }}' => implode('", "', array_keys($form->getExtraData()))),
$form->getExtraData()
);
}
我是否想念表单动态额外字段?
答案 0 :(得分:0)
我没有分析所有问题但是,我想,你可以反转逻辑:总是添加该字段并在不满足条件时将其删除。
这样您就不需要在postSubmit
执行操作(问题出在哪里)