Symfony3 + Select2标签,如list

时间:2018-02-13 08:19:54

标签: php ajax forms symfony

我试图建立一个负责在我的数据库中注册食品的表格。对于每种产品,我还要注册产品包装上的成分。

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

成分:

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中的所有成分(成分表可能有成千上万的成分,我想这可能是一个主要的性能问题)。< / LI>
  3. 允许最终用户在配料表中插入新配料,但尚未在配料表中存在,然后,一旦提交表格以创建新配料作为配料表的记录。 (我也已经这样做了,但是一旦表格被提交,我就不知道如何保存这些成分。)
  4. 目前,我为产品表单执行的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字段:

    enter image description here

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

    在我目前的形式状态下,如果我尝试创建在DB中尚未存在的新成分,我会收到错误,因为成分不在数据库中,并且当然不能指定它们到产品。

1 个答案:

答案 0 :(得分:1)

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

阻止渲染
{% do product_form.ingredients.setRendered %}

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

然后您不需要阻止渲染。使用该Bundle,您必须在控制器中定义远程路由,该路由将返回选项列表。