【发布时间】:2016-03-02 11:09:12
【问题描述】:
在我的 Symfony 2.7.10 项目中,我有一个实体表单,它通过 queryBuilder 从数据库加载一个实体对象。
$builder
->add('size', 'entity', [
'class' => 'AppBundle\Entity\Material',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('m')
->select('m')
->where('m.idproduct = :idproduct')->setParameter('idproduct', $this->product->getIdProduct())
->groupBy('m.size')
->orderBy('m.id');
},
'choice_label' => 'size',
'expanded' => true,
'constraints' => new NotBlank(),
]);
此外,我预先设置了一个表单字段,该字段在用户选择材料尺寸后动态加载。 这是通过 EventSubscriber 完成的
$builder->addEventSubscriber(new AddEndTermsSubscriber('size', $options['locale']));
类如下所示:
...
class AddEndTermsSubscriber implements EventSubscriberInterface
{
private $propertySize;
private $locale;
public function __construct($propertySize, $locale)
{
$this->propertySize = $propertySize;
$this->locale = $locale;
}
public static function getSubscribedEvents()
{
return [
FormEvents::PRE_SET_DATA => 'preSetData',
];
}
private function addFormField(FormInterface $form, Material $material)
{
$form->add('endterm', 'entity', [
'class' => 'AppBundle\Entity\MaterialT',
'query_builder' => function (EntityRepository $er) use ($material) {
return $er->createQueryBuilder('t')
->select('mt')
->from('AppBundle:MaterialT', 'mt')
->leftJoin('mt.m', 'm')
->where('m.size = :size')
->setParameter('size', $material->getSize());
},
'expanded' => true,
'mapped' => false,
'required' => false,
'placeholder' => false,
'choice_label' => 'name'.$this->locale,
]);
}
public function preSetData(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();
if ($data === null) {
return;
}
$accessor = PropertyAccess::createPropertyAccessor();
$formMaterial = $accessor->getValue($data, $this->propertySize);
$material = ($formMaterial) ? $formMaterial : new Material();
$this->addFormField($form, $material);
}
}
在用户选择材料后,我正在通过 ajax 操作为 endTerms 加载表单字段。
提交表单后,我将材料实体和选定的 endTerm 存储在会话中并重定向到下一个表单步骤:
if ($form->get('size')->getData() != null &&
$request->request->get('endterm') != null) {
$request->getSession()->set('token/size', $form->get('size')->getData());
$idEndterm = $request->request->get('endterm');
$endterm = $this->getDoctrine()->getRepository('AppBundle:MaterialT')
->createQueryBuilder('mt')
->leftJoin('mt.m', 'm')
->where('m.id = :id')
->setParameter('id', $idEndterm)
->getQuery()
->getSingleResult();
$request->getSession()->set('token/endterm', $endterm);
//...
}
问题: 用户应该可以编辑他的配置,所以在下一步他可以“编辑他的配置”并返回,我通过表单重定向到上述操作来做到这一点。
public function materialDetailsAction(Request $request)
{
$material = new Material();
$product = $request->getSession()->get('token/product');
$form = $this->createForm(new MaterialType($product), $material, ['locale' => $request->getLocale()]);
//...
}
我怎样才能实现存储的会话值被预填充到表单中?
最好的做法是通过 $options 参数将它们路由到表单,然后做一些 if else 验证?
任何关于解决方案的提示或如何做得更好都受到热烈欢迎。 谢谢
【问题讨论】:
-
考虑将您的预填充内容从侦听器移至控制器。然后,您可以在您的控制器中检查会话是否已设置,如果未预填充。
-
感谢您的建议,但监听器是动态调用的 - 那么我该如何组合呢?
-
我基本上是建议你完全摆脱表单监听器。我不完全理解你的问题,但似乎没有必要。
-
稍微抽象一下问题:我有一个表单实体,您可以在其中选择材料的大小(单选按钮)。当您选择大小时,有一个 ajax 函数可以根据您选择的大小(oneToMany 关系)动态加载另一个基于实体的单选字段元素。在结果页面上(提交后),您应该能够“编辑”您之前的选择并可以跳回表单。系统知道您选择的材料尺寸(存储在会话中),因此当您尝试编辑配置时,应该预先填充。希望这更容易理解
标签: php ajax forms symfony entity