情况
我有一种带有子表单的表单类型,我使用选项卡在前端呈现,因此一次只能显示一个子表单(作为选项卡)。因此,当不同选项卡上发生错误时,我会弹出一个显示错误的对话框。通过递归循环最终请求处理的表单对象。
验证约束写在表单类型中。这会产生一个我可以循环的最终表单对象,当确实发生错误时,子表单将指示为 valid=false 。
目标
我想将所有验证约束外包到实体的 ORM 映射中。
问题
当我将所有验证错误外包到 ORM 映射中时,最终的表单对象包含所有 valid=true 的子表单,甚至其内部表单小部件在提交时都带有验证错误。只有最上面的表单级别有效=false。
在构建所有不带事件订阅者的子表单以及带事件订阅者的子表单时,都会发生这种现象。
我希望子表单在最终表单对象上也被设置为无效,当出现错误时,我该如何实现这一点?
编辑
使用 error_bubbling 对我来说不起作用。也许我没有正确使用它?
使用此输入:
form
{{ dump(form) }}
form.vars.valid
{{ dump(form.vars.valid) }}
form.vars.errors
{{ dump(form.vars.errors) }}
form.children.sections.vars.errors
{{ dump(form.children.sections.vars.errors) }}
form.children.sections.vars.valid
{{ dump(form.children.sections.vars.valid) }}
form.children.sections.children.general.vars.errors
{{ dump(form.children.sections.children.general.vars.errors) }}
form.children.sections.children.general.vars.valid
{{ dump(form.children.sections.children.general.vars.valid) }}
form.children.sections.children.general.children.lang.vars.valid
{{ dump(form.children.sections.children.general.children.lang.vars.valid) }}
form.children.sections.children.general.children.lang.vars.errors
{{ dump(form.children.sections.children.general.children.lang.vars.errors) }}
我收到此输出:
form
FormView {#12833 ▼
+vars: array:28 [▶]
+parent: null
+children: array:3 [▶]
-rendered: false}
form.vars.valid
false
form.vars.errors
FormErrorIterator {#12832 ▼
-form: Form {#5652 ▶}
-errors: array:1 [▶]
}
form.children.sections.vars.errors
FormErrorIterator {#12837 ▼
-form: Form {#5649 ▶}
-errors: []
}
form.children.sections.vars.valid
true
form.children.sections.children.general.vars.errors
FormErrorIterator {#12841 ▼
-form: Form {#5498 ▶}
-errors: []
}
form.children.sections.children.general.vars.valid
true
form.children.sections.children.general.children.lang.vars.valid
true
form.children.sections.children.general.children.lang.vars.errors
FormErrorIterator {#12851 ▼
-form: Form {#2009 ▶}
-errors: []
}
我在 form.children.sections.children.general.children.lang 中生成的错误。我希望从这个位置来看,递归父母有 ...valid=false。
我在以下情况下尝试了error_bubbling=true,具有相同的转储结果。
我做错了什么,或者我需要其他解决方法?
编辑2
所以现在我在以下情况下尝试了error_bubbling = false,并且仍然相同的转储结果。
这里有一些片段
实体
/**
* @ORM\Entity(repositoryClass="Myvendor\CoreBundle\Entity\MyItemRepository")
* @ORM\Table(name="myitem")
*/
class MyItem
{
/**
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var \Myvendor\CoreBundle\Entity\Language
*
* @Assert\Type("Myvendor\CoreBundle\Entity\Languag")
* @ORM\ManyToOne(targetEntity="Myvendor\CoreBundle\Entity\Language")
* @ORM\JoinColumn(name="language_id", nullable=true, referencedColumnName="langid")
*/
private $lang;
/**
* Set lang
*
* @param \Myvendor\CoreBundle\Entity\Language $lang
*
* @return MyItem
*/
public function setLang(\Myvendor\CoreBundle\Entity\Language $lang = null)
{
$this->lang = $lang;
return $this;
}
/**
* Get lang
*
* @return \Myvendor\CoreBundle\Entity\Language
*/
public function getLang()
{
return $this->lang;
}
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
}
初始表单类型
class MyItemType extends AbstractMyvendorType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$sections = $builder->create('sections', 'form', array(
'mapped' => false,
'label' => false,
'attr' => array(
'data-sections' => '1'
),
'error_bubbling' => false
));
$builder->add($sections);
$builder->addEventSubscriber(new DynamicSubforms());
}
public function configureOptions(OptionsResolver $resolver)
{
parent::configureOptions($resolver);
$resolver->setDefaults(array(
'error_bubbling' => false
));
}
}
事件订阅者
class DynamicSubforms implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(
FormEvents::PRE_SET_DATA => 'onPreSetData'
);
}
/**
* Adding subtypes, depending on the myitem type.
*
* @author FPI
* @param FormEvent $event
*/
public function onPreSetData(FormEvent $event)
{
/**
*
* @var $data \Myvendor\CoreBundle\Entity\MyItem
* @var $form \Symfony\Component\Form\Form
*/
$data = $event->getData();
$steptype = $data->getType();
$form = $event->getForm();
$options = $form->getConfig()->getOptions();
$sections = $form->get('sections');
$default_section_options = array(
'mapped' => false,
'data' => $data
);
// Every steptype has section "general"
$sections->add('general', GeneralType::class, array_merge($default_section_options, array(
'label' => 'general',
'error_bubbling' => false
)));
}
}
子表单类型
class GeneralType extends AbstractType
{
protected $em;
protected $choiceOption;
public function __construct(EntityManager $em, ChoiceOption $choice_option)
{
$this->em = $em;
$this->choiceOption = $choice_option;
}
/*
* Here are set the static options for each widget.
* The dynamic options on specific widgets are specified in the event subscriber.
* {@inheritdoc}
*
* @author FPI
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
/* Language */
$builder->add('lang', 'entity', array(
'label' => 'language',
'class' => 'MyvendorCoreBundle:Language',
'error_bubbling' => false
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'error_bubbling' => false
));
}
}
如果您不希望将错误传递给表单父级,则应将
error_bubbling
设置为 false,因为默认情况下 error_bubbling
为 false 除非表单是复合表单 (error_bubbling)。