在表单验证之前设置实体参数

Set entity parameter before form validation

[设置]

[问题]

目前,创建新糖果时,我必须选择一个盒子作为父实体。
问题是,我希望这个选择是自动化的。
该盒子已在数据库中注册,会话保存当前盒子参数以便轻松找到它。
但是我不知道如何在数据发布后将其应用于糖果实体。

[文件]

AppBundle/Controller/CandyController.php

public function newAction(Request $request) {
    $$candy= new Candy();
    $form = $this->createForm('AppBundle\Form\CandyType', $conference);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($candy);
        $em->flush();

        return $this->redirectToRoute('candy_show', array('id' => $candy->getId()));
    }

    return $this->render('candy/new.html.twig', array(
        'candy' => $candy,
        'form' => $form->createView(),
    ));
}

AppBundle/Form/CandyType.php

public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('nom')
            ->add('box'); //Remove from form, and set manually
}

我做了 read this page,但不知道如何正确地做。
如果有人能给我一个完整的例子来解决我的问题,我将不胜感激。

您有多种选择来执行您想要的操作。您可以在表单提交后设置值:

public function newAction(Request $request)
{
    $em = $this->getDoctrine()->getManager();

    $candy = new Candy();
    $box = $em->find('AppBundle\Entity\Box', $this->get('session')->get('boxId'));

    $form = $this->createForm('AppBundle\Form\CandyType', $candy);
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        // add the box entity to the candy
        $candy->setBox($box);

        $em->persist($candy);
        $em->flush();

        return $this->redirectToRoute('candy_show', array('id' => $candy->getId()));
    }

    return $this->render('candy/new.html.twig', array(
        'candy' => $candy,
        'form' => $form->createView(),
    ));
}

您可以在将它传递给 createForm() 调用之前将其设置在 Candy 实体上,尽管它在执行表单 handleRequest() 调用后可能不会留在实体上:

    $em = $this->getDoctrine()->getManager();

    $candy = new Candy();
    $box = $em->find('AppBundle\Entity\Box', $this->get('session')->get('boxId'));

    $candy->setBox($box);

    $form = $this->createForm('AppBundle\Form\CandyType', $candy);
    $form->handleRequest($request);

您可以按照您尝试的方式在表单事件中完成。您想要做的是将实体管理器和会话注入您的表单并将您的表单视为服务:

public function CandyType extends AbstractType
{
    private $em;
    private $session;

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

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // ... build the form

        $builder->addEventListener(
            FormEvents::PRE_SET_DATA,
            function (FormEvent $event) {
                $form = $event->getForm();

                $candy = $event->getData();
                $box = $this->em->find('AppBundle\Entity\Box', $this->session->get('boxId');

                $candy->setBox($box);
            }
        );
    }
}

您可能需要在 POST_SET_DATAPOST_SUBMIT 事件上执行此操作,但我不确定。我也在控制器中使用了 $this->get('session'),但是根据您的 Symfony 版本(> 3.3),您也可以将其作为服务注入到您的控制器中。

无论哪种方式,主要概念是使用 Doctrine 使用会话中存储的盒子 ID 从会话本身获取您的 Box 实体,然后将其设置在您的 Candy 实体上。您甚至可以使用 hidden 字段来获得相同的结果。正如我之前所说,有很多方法可以解决您的问题。