如何在Symfony中创建动态级联表单?

时间:2017-08-09 07:59:41

标签: forms symfony dynamic symfony-forms

我一直在使用Symfony 3,直到现在我只生成了简单的表单。现在,我想生成一个更复杂,更动态的形式,我们将不胜感激。

我的网站引用与类别相关联的产品。因此,我创建了一个 ProductCategory 实体,该实体依赖于Doctrine扩展 Tree 。因此,实际产品是树结构的叶子,其他节点(即至少有一个孩子的节点)只是产品类别。

这种结构的一个例子是:

Food
      Fruits
           Apple
           Pear
      Vegetables
           Pepper
           Zucchini
 Vehicle
      Car
      Bike

在这个例子中,产品是Apple,Pear,Pepper,Zucchini,Car和Bike。

我想生成一个旨在选择产品的表单。预期的行为将是这一个:

  • 最初,用户会看到一个包含根类别(此处为食物和车辆)的下拉列表
  • 当用户选择一个类别时,新的下拉列表会显示在上一个类别下方,并填充与之前选择的类别对应的子类别(例如,如果选择了食物,则为水果和蔬菜)
  • 此过程应重新启动,直到用户选择了产品,即树形结构的叶子。

为了使表单有效,用户必须选择一个产品(叶子)。

目前,我已经能够使用列出根类别的下拉列表生成初始表单。以下是用于执行此操作的代码。

use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use AppBundle\Entity\ProductCategory;
use AppBundle\Repository\ProductCategoryRepository;
 
class ProductType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
            $builder->add('productCategory',EntityType::class,array(
                'class'         => 'AppBundle:ProductCategory',
                'query_builder' => function(ProductCategoryRepository $repository){
                        return $repository->getRootNodesQueryBuilder();
                },
                'label'         => 'product category',
                'choice_label'  => 'name',
                'choice_value'  => 'name',
                'multiple'      => false,
                'expanded'      => false,
                'required'      => true
            ));
    }
 
 
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Product::class,
            'method' => 'POST',
        ));
    }
}

由此,我们的想法是使用AJAX和jQuery:

  • 使用"更改"将(当前)所选类别发送到服务器下拉列表中的事件
  • 使用足够的
  • 生成并显示上一个下方的新下拉列表

但是,我不知道如何修改 ProductType 类以便根据当前选定的类别生成新的 EntityType 字段,然后发回更新的表单以便通过jQuery显示它。

因此,任何帮助或建议都会受到欢迎,以便在构建这种动态形式方面取得进展!

1 个答案:

答案 0 :(得分:0)

如果我理解你的问题是正确的,那么你需要获得给定类别的子类别。您可以将其作为选项传递给ProductType

use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use AppBundle\Entity\ProductCategory;
use AppBundle\Repository\ProductCategoryRepository;
 
class ProductType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
            $category = $options['category'];

            $builder->add('productCategory',EntityType::class,array(
                'class'         => 'AppBundle:ProductCategory',
                'query_builder' => function(ProductCategoryRepository $repository) use ($category){
                        return $repository->getRootNodesQueryBuilder($category);
                },
                'label'         => 'product category',
                'choice_label'  => 'name',
                'choice_value'  => 'name',
                'multiple'      => false,
                'expanded'      => false,
                'required'      => true
            ));
    }
 
 
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Product::class,
            'method' => 'POST',
            'category' => null
        ));
    }
}

getRootNodesQueryBuilder()中,您可以根据传递的类别解析子类别。在控制器中(您收到AJAX请求),您可以像

一样使用它
$form = $this->createForm(ProductType::class, $product, [
        'category' => $request->get('category')
]);