gpt4 book ai didi

php - Symfony2 表单事件和模型转换器

转载 作者:IT王子 更新时间:2023-10-28 23:50:03 25 4
gpt4 key购买 nike

我在试图与 Symfony2 的表单构建器、事件和变形器搏斗时陷入困境……希望这里的人更有经验并能提供帮助!

我有一个表单字段(选择下拉菜单),其中包含一些映射到实体的值(候选列表)。这些选项之一是“其他”。假设现在没有 AJAX,当用户提交表单时,我想检测他们是否选择了“其他”(或不在候选名单中的任何其他选项)。如果他们选择了其中一个选项,则应显示完整的选项列表,否则仅显示候选名单。应该很容易吧? ;)

所以,我有我的表单类型,它可以很好地显示基本的候选名单。代码如下所示:

namespace Company\ProjectBundle\Form\Type;

use ...

class FancyFormType extends AbstractType {
private $fooRepo;

public function __construct(EntityManager $em, FooRepository $fooRepo)
{
$this->fooRepo = $fooRepo;
}

public function buildForm(FormBuilderInterface $builder, array $options) {
/** @var Bar $bar */
$bar = $builder->getData();
$fooTransformer = new FooToStringTransformer($options['em']);

$builder
->add($builder
->create('linkedFoo', 'choice', array(
'choices' => $this->fooRepo->getListAsArray(
$bar->getLinkedfoo()->getId()
),
))
->addModelTransformer($fooTransformer)
)
;

// ...

}

// ...
}

现在,我想检查提交的值,所以我使用了一个表单事件监听器,如下所示。

public function buildForm(FormBuilderInterface $builder, array $options) {
// ... This code comes just after the snippet shown above

$builder->addEventListener(FormEvents::PRE_SUBMIT, function(FormEvent $event) {
/** @var EntityManager $em */
$em = $event->getForm()->getConfig()->getOption('em');

$data = $event->getData();
if (empty($data['linkedFoo'])) return;
$selectedFoo = $data['linkedfoo'];

$event->getForm()->add('linkedFoo', 'choice', array(
'choices' => $em
->getRepository('CompanyProjectBundle:FooShortlist')
->getListAsArray($selectedFoo)
,
));
//@todo - needs transformer?
});
}

但是,它失败并显示如下错误消息:

Notice: Object of class Proxies\__CG__\Company\ProjectBundle\Entity\Foo could not be converted to int in \path\to\project\symfony\symfony\src\Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList.php line 458 

我认为这个错误是因为当 linkedFoo 被覆盖时,它删除了 modelTransformer?我尝试了各种在事件关闭时访问构建器的方法,但这似乎不起作用(返回值出乎意料)。除了 $event->getForm()->add() 之外,我还应该在事件中使用其他方法吗?还是我的方法存在更根本的问题?

基本上我不想弄乱 linkedFoo 字段的 config/transformers/labels except 来更改可用的选择...还有其他方法吗那?例如。类似于 $form->getField()->updateChoices()?

提前感谢您提供的任何帮助!

C

附:有没有比 Symfony 网站上更好的形式、事件等的文档或讨论?例如。 PRE_SET_DATA、PRE_SUBMIT、SUBMIT 等有什么区别?他们什么时候被解雇?它们应该用来做什么?继承如何与自定义表单字段一起工作?什么是 Form 和 Builder,它们如何交互以及何时应该处理它们?您应该如何、何时以及为什么使用可以通过 $form->getConfig()->getFormFactory() 访问的 FormFactory?等等。


编辑:为了回应弗洛里安的建议,这里有一些关于尝试但不起作用的事情的更多信息:

如果您尝试像这样在事件中获取 FormBuilder:

/** @var FormBuilder $builder */
$builder = $event->getForm()->get('linkedFoo')->getConfig();

$event->getForm()->add($builder
->create('linkedFoo', 'choice', array(
'choices' => $newChoices,
'label' =>'label',
))
->addModelTransformer(new FooToStringTransformer($em))
);

然后你得到错误:

FormBuilder methods cannot be accessed anymore once the builder is turned
into a FormConfigInterface instance.

然后你尝试像弗洛里安建议的那样,即

$event->getForm()->add('linkedFoo', 'choice', array(
'choices' => $newChoices,
));
$event->getForm()->get('linkedFoo')->getConfig()->addModelTransformer(new FooToStringTransformer($em));

...但是您会收到此错误:

Notice: Object of class Proxies\__CG__\Company\ProjectBundle\Entity\Foo could not be converted to int 
in C:\path\to\vendor\symfony\symfony\src\Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceList.php line 458

这似乎表明第二行(添加 ModelTransformer)永远不会被调用,因为 ->add() 调用在您到达那里之前就失败了。

最佳答案

感谢 sstok(在 github 上)的想法,我想我现在已经开始工作了。关键是创建一个自定义的表单类型,然后使用它来添加 ModelTransformer。

创建自定义表单类型:

namespace Caponica\MagnetBundle\Form\Type;

use ...

class FooShortlistChoiceType extends AbstractType {
protected $em;

public function __construct(EntityManager $entityManager)
{
$this->em = $entityManager;
}

public function buildForm(FormBuilderInterface $builder, array $options) {
$fooTransformer = new FooToStringTransformer($this->em);

$builder
->addModelTransformer($fooTransformer)
;
}

public function getParent() {
return 'choice';
}

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

为新类型创建服务定义:

company_project.form.type.foo_shortlist:
class: Company\ProjectBundle\Form\Type\FooShortlistChoiceType
tags:
- { name: form.type, alias: fooShortlist }
arguments:
- @doctrine.orm.entity_manager

主窗体的代码现在看起来像这样:

namespace Company\ProjectBundle\Form\Type;

use ...

class FancyFormType extends AbstractType {
private $fooRepo;

public function __construct(FooRepository $fooRepo)
{
$this->fooRepo = $fooRepo;
}

public function buildForm(FormBuilderInterface $builder, array $options) {
/** @var Bar $bar */
$bar = $builder->getData();
$fooTransformer = new FooToStringTransformer($options['em']);

$builder
->add('linkedFoo', 'fooShortlist', array(
'choices' => $this->fooRepo->getListAsArray(
$bar->getLinkedfoo()->getId()
),
))
;

$builder->addEventListener(FormEvents::PRE_SUBMIT, function(FormEvent $event) {
/** @var EntityManager $em */
$em = $event->getForm()->getConfig()->getOption('em');

$data = $event->getData();
if (empty($data['linkedFoo'])) return;
$selectedFoo = $data['linkedFoo'];

$event->getForm()->add('linkedFoo', 'fooShortlist', array(
'choices' => $em->getRepository('CaponicaMagnetBundle:FooShortlist')->getListAsArray($selectedFoo),
'label' => 'label'
));
});

// ...

}

// ...
}

关键是该方法允许您将 ModelTransformer 嵌入自定义字段类型中,这样,每当您添加此类型的新实例时,它会自动为您添加 ModelTransformer 并防止之前的“无法添加”循环没有变压器的字段并且不能添加没有字段的变压器”

关于php - Symfony2 表单事件和模型转换器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19382017/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com