【问题标题】:Symfony3 + Select2 tags like listSymfony3 + Select2 类似列表的标签
【发布时间】:2018-02-13 08:19:54
【问题描述】:

我正在尝试使用一种表格来负责在我的数据库中注册食品。对于每种产品,我还想注册产品包装上写的成分。

对于这两个实体,我有以下两个类:

成分:

class Ingredient {

    // ...

    /**
     * @var string
     *
     * @Assert\NotBlank()
     * @Assert\Type("string")
     *
     * @ORM\Column(name="name", type="string", length=255, unique=false)
     */
    private $name;

    /**
     * @ORM\ManyToMany(targetEntity="NutritionBundle\Entity\Product", mappedBy="ingredients")
     */
    private $products;

    // ...

    public function __toString() {
        return $this->getName();
    }

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Ingredient
     */
    public function setName( $name ) {
        $this->name = $name;
        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName() {
        return $this->name;
    }

    // ...

    /**
     * @return Product
     */
    public function getProducts() {
        return $this->products;
    }

    /**
     * @param Product $products
     *
     * @return Ingredient
     */
    public function setProducts( Product $products ) {
        $this->products = $products;

        return $this;
    }

    // ...

}

产品:

class Product {
    // ...

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=255)
    */
    private $name;

    // ...

    /**
     * @ORM\ManyToMany( targetEntity="NutritionBundle\Entity\Ingredient", inversedBy="products" )
     * @ORM\JoinTable(name="ingredients_products")
     */
    private $ingredients;

    // ...

    public function __construct() {
        $this->ingredients = new ArrayCollection();
    }

    // ...

    /**
     * Set name
     *
     * @param string $name
     *
     * @return Product
     */
    public function setName( $name ) {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName() {
        return $this->name;
    }

    // ...

    /**
     * @return mixed
     */
    public function getIngredients() {
        return $this->ingredients;
    }

    /**
     * @param mixed $ingredients
     *
     * @return Product
     */
    public function setIngredients( $ingredients ) {
        $this->ingredients = $ingredients;

        return $this;
    }

    // ...
}

然后,在树枝方面,我需要创建表单并利用 Select2 来归档以下内容:

  1. 仅使用 AJAX 在 Select2 中加载成分(我已经这样做了,但我不确定我是否以正确的方式进行)
  2. 防止 Symfony 在加载时加载 Select2 中的所有成分(成分表可能包含数十万种成分,我猜这可能是一个主要的性能问题)
  3. 允许最终用户在成分表中不存在的成分字段中插入新成分,然后在提交表单后创建新成分作为成分表的记录。 (我也做过,但是不知道表格提交后如何保存成分。)

目前,我为产品表单所做的ProductType 类如下所示:

class ProductType extends AbstractType {
    public function buildForm( FormBuilderInterface $builder, array $options ) {
        $builder
            ->add( 'name' )
            ->add( 'company' )
            ->add( 'front_picture' )
            ->add( 'back_picture' )
            ->add( 'weight' )
            ->add( 'unit' )
            ->add( 'barcode' )
            ->add( 'product_url' )
            ->add( 'ingredients' );
    //          ->add(
    //              'ingredients',
    //              EntityType::class,
    //              array(
    //                  'class'        => 'NutritionBundle\Entity\Ingredient',
    //                  'choice_label' => function ( $ingredient ) {
    //                      return sprintf(
    //                          '%2$s [E%1$s]',
    //                          $ingredient->getCode(),
    //                          $ingredient->getName()
    //                      );
    //                  },
    //                  'choice_value' => 'id',
    //                  'multiple'     => true,
    //              )
    //          );

    // $builder->get( 'ingredients' )->addModelTransformer( $this->ingredients_transformer );
    }

    public function configureOptions( OptionsResolver $resolver ) {
        $resolver->setDefaults(
            array(
                'data_class' => 'NutritionBundle\Entity\Product',
            )
        );
    }

    public function getBlockPrefix() {
        return 'nutritionbundle_product';
    }
}

正如您在注释掉的代码中看到的那样,我也尝试了EntityType 选项,但可能不符合我的要求。

最后在树枝中,Ingredients 字段的代码如下:

<div
    class="form-group {% if product_form.ingredients.vars.errors|length %}has-error{% endif %}"
>
    <label
        for="{{ product_form.ingredients.vars.id }}"
        class="control-label"
    >
        Ingredients
    </label>
    <select
        name="{{ product_form.ingredients.vars.full_name|e('html_attr') }}"
        id="{{ product_form.ingredients.vars.id }}"
        multiple="multiple"
        class="form-control"
        data-values="{{ product_form.ingredients.vars.value|join(',') }}"
    ></select>
    <span class="help-block">
        <small>Enter the product ingredients as they appear in the ingredients list.</small>
        </span>
        {% if product_form.ingredients.vars.errors|length %}
        <span class="help-block">
            {{ form_errors( product_form.ingredients ) }}
        </span>
        {% endif %}
</div>

我必须以这种方式呈现 Ingredients 字段的原因是为了实现我需要的自定义,以便仅使用 AJAX 加载已分配给给定产品的成分。

最后一个问题是,由于这个自定义的字段渲染,Symfony 仍然使用默认控件渲染Ingredients 字段:

如您所见,按钮上方是我自定义的渲染字段,按钮下方是 Symfony 强制的字段。

在我当前的表单状态下,如果我尝试创建数据库中尚不存在的新成分,则会出现错误,因为这些成分不在数据库中,当然它们不能分配给产品。

【问题讨论】:

  • @Nefro 感谢您的回复。但我不明白这有什么帮助。该类已经有了 setter 和 getter。为什么这个改变会解决我上面的问题?
  • 您不应该使用 AJAX 来加载成分,而只需使用 EntityType 中的 query_builder 将它们限制为当前产品。你能粘贴你的数据转换器的代码吗?

标签: php ajax forms symfony


【解决方案1】:

要不再渲染Ingredients 字段,您可以使用阻止渲染

{% do product_form.ingredients.setRendered %}

但我建议你使用 https://github.com/tetranz/select2entity-bundle

那么你就不需要阻止渲染了。使用该 Bundle,您必须在控制器中定义一个远程路由,该路由将返回选项列表。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-07
    • 2016-10-22
    • 2023-03-13
    • 2015-10-31
    • 1970-01-01
    • 2011-11-05
    • 2014-05-01
    • 1970-01-01
    相关资源
    最近更新 更多