【问题标题】:How to set the choices of a Symfony EntityType form field after the form has been created and handled?创建和处理表单后,如何设置 Symfony EntityType 表单字段的选项?
【发布时间】:2019-11-14 16:06:09
【问题描述】:

我正在与Symfony 3.4 合作,并想创建一个简单的表单,其中显示可以使用复选框选择删除的列表实体:

  • 创建和处理表单的控制器从数据库中加载实体列表,然后将其添加到表单中。
  • 控制器使用一些附加参数来提供分页,例如如果数据库中有 10.000 个实体,则用户可以选择仅加载前 50 个。

问题是,“前 50 个实体”取决于实体是否已被删除/表单是否已被处理。

  • 要在控制器中处理表单,我必须先创建它
  • 要创建表单,我需要从数据库中加载实体列表以将它们设置为choises
  • 此列表将包含前 50 个实体
  • 如果用户选择删除前 10 个实体,则在处理表单时完成。

class SomeController
{
    public function deleteUsersAction(Request $request)
    {
        $users = $this->loadUsersFromDB(50);

        $form = $this->creatFormBuilder()
            ->add('users', EntityType::class, [
                'class' => 'AppBundle:User',
                'choices' => $users,                  // $users are added here
                'multiple' => true,
                'expanded' => true,
            ])
            ->getForm();

        $form->handleRequest($request);
        if ($form->isSubmitted() && $form->isValid()) {
            $users = $form->getData();
            $this->deleteUsers($user);

            // Load the now first 50 users
            $users = $this->loadUsersFromDB(50);

            // How to add these users to the form??
        }

        return $this->render('AppBundle::user_list.html.twig', ['form' => $form->createView()]);
    }
}

提交的用户被删除后如何为表单设置正确的用户?


编辑

为了回答来自 cmets 的问题,我提供了一个小例子:

  • 假设表单显示前 5 个用户。
  • 第一次调用页面时,表单未提交。控制器加载以下第一个用户,使用它们创建表单并显示页面:
  • 鲍勃
  • 爱丽丝
  • 迈克
  • 约翰
  • 比尔
  • 在页面上,用户选择 BobAlice 进行删除并提交表单。
  • 再次调用控制器,加载前 5 个用户的列表以创建表单。此列表与之前完全相同。
  • 但是,由于现在提交了表单,因此处理了数据并删除了 Bob 和 Alice。
  • 现在我们无法返回创建的表单,因为它仍然包含 Bob 和 Alice 的条目...
  • 我们必须再次运行$users = $this->loadUsersFromDB(5) 才能得到正确的结果,比如
  • 迈克
  • 约翰
  • 比尔
  • 吉姆
  • 汤姆

问题:

  • 用户列表必须在创建表单之前加载,因为我们需要这个列表来创建表单。
  • 必须创建表单以便我们处理它
  • 处理表单确实会更改用户列表
  • 因此,在处理完表单后,我们需要再次加载用户列表。

所以:在处理表单之前加载用户列表是必要的工作,因为处理表单时列表会发生变化。

如何避免这项工作?

当然,在示例中加载 5 个用户没什么大不了的,但在实际代码中,这可能是数百个大量实体,并且两次运行相同的代码可能会对性能产生重大影响。

【问题讨论】:

  • 最简单的解决方案是重新创建表单。
  • 什么是“提交表单后设置正确的用户”是什么意思?如果你打算加载接下来的 50 个用户,这真的很容易,只需 return $this->redirectToRoute(YOUR_ROUTE);在 iIF 语句中,您将拥有一个包含新数据的干净页面。
  • @AlexanderDimitrov 在处理表单之前加载用户列表是完全不必要的工作,因为处理表单时此列表会发生变化。我在编辑问题时试图澄清。

标签: php forms symfony


【解决方案1】:

我认为您没有理解我在评论中的建议,所以我将在这里更详细地解释/现在我也是从笔记本电脑上写的:)/

class SomeController {
    public function deleteUsersAction(Request request) {
        $users = $this->loadUsersFromDB(50);        

        $form = $this->creatFormBuilder()
            ->add('users', EntityType::class, [
                'class' => 'AppBundle:User',
                'choices' => $users,                  // $users are added here
                'multiple' => true,
                'expanded' => true,
            ])
            ->getForm();

         $form->handleRequest($request);
         if ($form->isSubmitted() && $form->isValid()) {
             $users = $form->getData();
             $this->deleteUsers($user);

             // Load the now first 50 users
             $users = $this->loadUsersFromDB(50); <-- you don't need this

             // Q: How to add these users to the form??
             // A: When you return a redirect response to the same page /you can also pass any query parameters if you had any filters and etc../
             //    This will ensure that the page is loaded properly with the new list of the users and Bob and Alice will NOT be in the list
             //    If you don't do it with a redirect and the user submits the form the browser remembers the data and if the users hits the refresh button of the browser it will resubmit the form and with your approach it may delete next 2 users /Mike and John/.
             return $this->redirectToRoute('YOUR_ROUTE', $request->query->all());
         }

         return $this->render('AppBundle::user_list.html.twig', ['form' => $form->createView()]);
    }
}```

【讨论】:

  • 感谢您的澄清,但这会导致我试图描述的相同问题:如何避免两次加载用户列表?您写的我不需要重新- 处理表单后加载用户列表,但应重定向到同一页面而不是获取新数据。这当然可以,但重新加载页面只是重新加载数据的另一种方式。因此,用户列表仍然会被加载两次,而重新加载页面会增加额外的工作量。还是我错过了什么?
  • 如果您删除列表语句中的行并进行重定向,则列表将在每个页面请求时仅加载一次。这意味着:用户加载页面(1 次加载列表)-> 提交表单(1 次加载列表)-> 页面被重定向(1 次加载列表)
  • 没错!如果未提交表单(页面的第一次加载),则列表仅加载一次。但是当表单被提交时,列表被加载了两次。第一次处理表单,第二次处理重定向请求。 表单提交时如何避免两次加载列表?
  • 您需要在那里走不同的路线...使用您当前的设置,我没有看到更好的方法,因为无论如何您都需要从列表中加载所有这 3 个。第 1 次:将列表加载为源 第 2 次:处理列表 第 3 次:加载新列表 就我个人而言,我没有使用 symfony 表单进行任何批处理/删除/,因为有很多事情可能会出错,比如如果有会发生什么是交易之间的新实体,如果发生错误等会发生什么。
  • 好的,所以我们同意您的提议不是解决“如何避免在提交表单时两次加载列表”问题的解决方案。简而言之,您的答案是“您不能/不应该避免两次加载列表,因为两次加载列表对性能不利,但仍然是最干净的方法”。对? :-)
猜你喜欢
  • 1970-01-01
  • 2021-11-02
  • 1970-01-01
  • 1970-01-01
  • 2011-03-29
  • 1970-01-01
  • 2021-11-08
  • 2021-11-30
  • 1970-01-01
相关资源
最近更新 更多