Symfony POST_SUBMIT 更新底层对象的数据

问题描述 投票:0回答:1

我正在开发一个 symfony 6.4 项目,其中我有一个包含 2 个字段的 ProductType 表单,这两个字段都是 EntityType。仅在创建项目时,我需要能够根据默认值设置禁止的国家/地区并根据用户输入更新默认值。

->add('series', EntityType::class, [
    'label' => 'Collection',
    'placeholder' => 'Choisir une collection',
    'class' => Series::class,
    'choice_label' => 'name',
    'query_builder' => function (EntityRepository $repository) use ($product): QueryBuilder {
        return $repository->createQueryBuilder('s')
            ->andWhere('s.brand =' . $product->getBrand()->getId());
    }
])
->add('forbiddenCountries', EntityType::class, [
    'attr' => [
        'class' => 'searchable-select-countries'
    ],
    'data' => $product->getForbiddenCountries(),
    'class' => Country::class,
    'choice_label' => 'name',
    'choice_value' => 'alpha2',
    'multiple' => true
])

禁止的国家是这样预设的:

public function updateForbiddenCountries(FormInterface $form, Collection $forbiddenCountries): void
{
    $form
        ->add('forbiddenCountries', EntityType::class, [
            'attr' => [
                'class' => 'searchable-select-countries'
            ],
            'data' => $forbiddenCountries,
            'class' => Country::class,
            'choice_label' => 'name',
            'choice_value' => 'alpha2',
            'multiple' => true
        ]);
}
->addEventListener(FormEvents::PRE_SET_DATA, function (PreSetDataEvent $event) {
    /** @var Product $product */
    $product = $event->getData();

    if (null !== $product->getId()) {
        return;
    }

    $this->updateForbiddenCountries($event->getForm(), $product->getBrand()->getForbiddenCountries());
})

第一部分工作正常,这是预期的输出: enter image description here

我还需要能够根据系列字段的变化来更改预设。它应该看起来像这样:

->get('series')->addEventListener(FormEvents::POST_SUBMIT, function (PostSubmitEvent $event) {
    /** @var Product $product */
    $product = $event->getForm()->getParent()->getData();

    if (null !== $product->getId()) {
        return;
    }

    /** @var Series $series */
    $series = $event->getForm()->getData();

    $forbiddenCountries = $series === null ? $product->getBrand()->getForbiddenCountries() : $series->getForbiddenCountries();

dump($forbiddenCountries->toArray());

    $this->updateForbiddenCountries($event->getForm()->getParent(), $forbiddenCountries);
})

当我更改系列字段时,尽管禁止国家变量已正确更新,但我没有得到预期的视图:

enter image description here

如你所见,我期望有 3 个值而不是 2 个。

我尝试在表单本身上添加 POST_SUBMIT 事件侦听器(没有

->get('series')
),如下所示:

->addEventListener(FormEvents::POST_SUBMIT, function (PostSubmitEvent $event) {
    /** @var Product $product */
    $product = $event->getForm()->getData();

    if (null !== $product->getId()) {
        return;
    }

    /** @var Series $series */
    $series = $event->getForm()->get('series')->getData();
    $product->setSeries($series);

    $forbiddenCountries = $series === null ? $product->getBrand()->getForbiddenCountries() : $series->getForbiddenCountries();

    $this->updateForbiddenCountries($event->getForm(), $forbiddenCountries);
})

触发

You cannot add children to a submitted form.
异常

我什至尝试更新我的对象以设置禁止国家并从事件中设置数据:

->addEventListener(FormEvents::POST_SUBMIT, function (PostSubmitEvent $event) {
    /** @var Product $product */
    $product = $event->getForm()->getData();

    if (null !== $product->getId()) {
        return;
    }

    /** @var Series $series */
    $series = $event->getForm()->get('series')->getData();
    $product->setSeries($series);

    $forbiddenCountries = $series === null ? $product->getBrand()->getForbiddenCountries() : $series->getForbiddenCountries();

    foreach ($forbiddenCountries as $forbiddenCountry) {
        $product->addForbiddenCountry($forbiddenCountry);
    }

    $event->setData($product);
})

这不会有任何影响。请注意,这里 setData 已被弃用。

尝试在表单本身上设置数据(

$event->getForm()->setData($product);
)会按预期触发异常:
You cannot change the data of a submitted form.

我猜我正在做的事情中有一个我没有看到的小错误。如果我能得到一些帮助那就太好了。

symfony symfony-forms event-listener symfony6
1个回答
0
投票

经过很多麻烦和大量时间处理文档和不同的论坛,我终于明白这是不可能完成的。问题是提交的表单有错误,symfony 需要重新显示表单的先前状态,这就是为什么无论您做什么来更改数据,symfony 都需要重新显示表单的先前状态。这是有道理的。

因此,我决定不使用 symfony 执行此操作,而是使用 api 来处理它,该 api 将返回我将在 ajax 中调用的下一个元素列表,并使用 js 更新第二个字段。

这不是一个很好的解决方案,因为我们增加了维护的麻烦,但在服务器端做这样的事情将是处理具有未映射字段的非规范化数据,您需要自己规范化这些数据,这是一项大量的工作,但没有多大价值,而且它仍然不是一个好的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.