【问题标题】:Symfony2 (>= 2.3): How to listen to parent form event from child?Symfony2 (>= 2.3):如何从子级监听父表单事件?
【发布时间】:2015-03-10 05:56:04
【问题描述】:

我有一个自定义的FormType,当父Form持续存在时,需要将自己添加到父Entity中。

在 Symfony

class FooType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        parent::buildForm($builder, $options);
        ...
        $builder->getParent()->addEventSubscriber(new FooSubscriber)
    }
}

class FooSubscriber implements EventSubscriberInterface
{
    static function getSubscribedEvents()
    {
        return array(
            FormEvents::POST_SUBMIT => 'postSubmit'
        );
    }
}

但在升级到 Symfony 2.6 后,我发现 $builder->getParent() 已被删除。但是现在我不能听父母提交了。

所以我将侦听器添加到我的构建器并从订阅者中引用父级。但这并没有真正起作用,因为我检查了父表单是否有效 - 它不是,因为它还没有提交:

function postSubmit(FormEvent $e)
{
    if ($e->getForm()->getParent()->getRoot()->isValid()) {
        //this gives 'false'

这个false是下一段代码造成的:

// Symfony\Component\Form\Form.php @ line 744
public function isValid()
{
    if (!$this->submitted) {
        return false;
    }

而且由于父表单首先循环遍历所有子表单并提交,然后在自身上设置$this->submitted = true...我不确定父表单是否有效。


TL;DR

如何在我的父表单中添加事件监听器,而无需调整我的父表单?我希望我的 FooType 可以添加到所有表单中,而不必知道/记住为特定的 FooType 做一些逻辑。

【问题讨论】:

  • 如您所说,getParent 在 2.3 中已被删除。你能更详细地描述用例吗?可能是更好的解决方案。
  • 这是一个可以添加到另一个实体的实体。在这种情况下,它是一个 MenuItem,它是在持久化 Page 时创建的。这个 MenuItem 基于页面的标题,因此它需要它的父级进行输入。但我不希望页面“知道”有一个依赖于他的 MenuItem。所以在此之前,我只需向 PageAdmin 添加一个 MenuItem 即可。现在我必须在管理员中添加一个订阅者 - 这感觉
  • 遇到同样的问题,我想知道 Root 表单是否有效,我在 2.6 中找不到方法 :(

标签: forms symfony events


【解决方案1】:

我需要相同的功能,因为我有一个自定义表单字段,在更新所有映射字段后需要父实体。不幸的是,子表单的 POST_SUBMIT 在父表单的 SUBMIT 运行之前被调用。

我最终将 eventDispatcher 传递给孩子,并将我的侦听器绑定在那里。我需要两个侦听器来完成工作:一个用于获取处理后的值,另一个用于更新主实体。通过引用将 $generatedPassword 传递给闭包允许您将数据从子事件共享给父事件。

父级::buildForm

$builder->add('generate_password', GeneratePasswordType::class, [
    'event_dispatcher' => $builder->getEventDispatcher(),
]);

子::buildForm

//first listed to submit even to get current field value
$generateNewPassword = false;
$builder->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) use (&generateNewPassword) {
    $generateNewPassword = null !== $event->getData();
});

//then run updater after parent entity has been updated
$parentDispatcher = $options['event_dispatcher'];
$parentDispatcher->addListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use (&$generateNewPassword) {
    $user = $event->getData();
    if(true === $generateNewPassword){
        //update password & email user new credentials
    }
}

(自定义字段是用户管理模块标记为“保存时生成新密码”的复选框。它将生成的密码通过电子邮件发送给用户,这就是为什么我需要主实体的最新电子邮件地址)

【讨论】:

  • 这是一个想法,但还是需要修改父表单。和 OP 一样,我无法修改它。
猜你喜欢
  • 2018-10-21
  • 1970-01-01
  • 1970-01-01
  • 2018-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-30
  • 1970-01-01
相关资源
最近更新 更多