【发布时间】: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 来归档以下内容:
- 仅使用 AJAX 在 Select2 中加载成分(我已经这样做了,但我不确定我是否以正确的方式进行)
- 防止 Symfony 在加载时加载 Select2 中的所有成分(成分表可能包含数十万种成分,我猜这可能是一个主要的性能问题)。
- 允许最终用户在成分表中不存在的成分字段中插入新成分,然后在提交表单后创建新成分作为成分表的记录。 (我也做过,但是不知道表格提交后如何保存成分。)。
目前,我为产品表单所做的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 将它们限制为当前产品。你能粘贴你的数据转换器的代码吗?