Symfony 2.7 - 从先前存储的会话值预填充实体表单

时间:2016-03-02 11:09:12

标签: php ajax forms symfony entity

在我的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 Action我在用户选择材料后加载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验证吗?

热烈欢迎任何有关解决方案的提示或如何做得更好。 感谢

1 个答案:

答案 0 :(得分:0)

我终于找到了一个有效的解决方案。

问题的快速摘要:

  • 带有实体的动态表单,用于选择尺寸(P10,P20等)
  • 如果选择了一个尺寸,您现在应该看到一个带有一些endterms的新选择字段(例如leftTerm,rightTerm)
  • 用户现在提交表单,然后在表格中查看他以前的配置
  • 在此结果页面上,他现在可以选择一个编辑选项来更改其设置
  • 提交时,值存储在会话
  • 在编辑时,用户应该看到已经使用他的配置选择的表格(然后可以从P10更改为P20等)。

给我很多帮助的提示是:   - Symfony2 Setting a default choice field selection

现在代码......

  

在导致配置表格的行动中,我添加了一些会话预先配置

// create session cart
$request->getSession()->set('token', []); // token reset per configuration
if (!$request->getSession()->has('cart')) {
    $request->getSession()->set('cart', []);
}
  • 现在,在表单操作中,我设置PersistentObject以在FormType和依赖EventSubscribers
  • 中使用它
  • 此外,我扩展了我的createForm调用的选项参数。
  • 稍后在提交条件中,我只更新购物车会话数组

    public function materialDetailsAction(Request $request)
    {
        // back to start if session empty
        if ($request->getSession()->get('token/product') == null) {
            return $this->redirectToRoute('configurator_product');
        }
        $product = $request->getSession()->get('token/product');
    
        // persistence manager
        PersistentObject::setObjectManager($this->getDoctrine()->getManager());
    
        $material = new Material();
        $form = $this->createForm(new MaterialType($product), $material, [
            'locale' => $request->getLocale(),
            'sessionCart' => ($request->getSession()->has('editId')) ? $request->getSession()->get('token') : null,
        ]);
    
        // ... validation etc.
    
        // update session for shopping cart
        $shoppingCart = $request->getSession()->get('cart');
        if ($request->getSession()->has('editId')) {
            $shoppingCart[$request->getSession()->get('editId') -1] = $request->getSession()->get('token');
        } else {
            $shoppingCart[] = $request->getSession()->get('token');
        }
    
        $request->getSession()->set('cart', $shoppingCart);
    
        // ... redirect
    }
    
  • 表单类型中,我使用'sessionCart' => null,默认值扩展configureOptions数组

  • 然后有data选项,它是假的(如果会话值为空)或者我会得到这样的对象:

$defaultData = ($options['sessionCart'] != null) ? PersistentObject::getObjectManager()->getRepository('AppBundle:Material') ->find($options['sessionCart']['size']->getId()) : false;

  

按下编辑按钮

按钮> ajax
// get selected leaflet id and current session
$id = $request->request->get('id');
$session = $request->getSession();

// get selected configuration (table ID != array ID)
$selectedToken = $session->get('cart')[$id - 1];

// reset token
$request->getSession()->set('token', []);
$request->getSession()->set('editId', $id);

// set token from selected configuration
foreach ($selectedToken as $key => $value) {
    $session->set('token/'.$key, $value);
}

return new JsonResponse();

希望这可以帮助将来的某个人,或者如果有人有一些美分可以添加(增强等),我们热烈欢迎您!