Symfony:选择类型字段填充了对象数组
Symfony3 : choice type field filled with array of objects
我有一个实体 Product
。我的产品可以有多个不同语言的名称。法文名,英文名等。我不想使用自动翻译。
用户必须在产品表单中填写名称和select相应的语言。多亏了“添加”按钮,他可以添加任意多个名字。
所有语言都是管理员用户创建的(以另一种形式)。因此,Language
也是一个具有名称(例如:英语)和代码(例如:EN)的实体。
我创建了实体 ProductName
,它有一个名称和一种语言(符合用户在产品表单中所写的内容)。
在那种情况下,我不需要将实体 ProductName
与实体 Language
相关联。我只想要语言代码。所以,在我的 ProductName
实体中,我有这个 属性 :
/**
* @ORM\Column(name="Language_Code", type="string", length=2)
*/
private $language;
我的产品表单 (ProductType) 有一个 CollectionType 字段,以便添加多个名称。
// Form/ProductType.php
->add('infos', CollectionType::class, array(
'entry_type' => ProductInfosType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'label' => false,
'mapped' => false
))
ProductInfosType 表单有 2 个字段:
// Form/ProductInfosType.php
->add('name', TextType::class, array(
'attr' => array('size' => 40)
))
->add('language', EntityType::class, array(
'placeholder' => '',
'class' => 'AppBundle:Language',
'choice_label' => 'code',
'attr' => array('class' => 'lang'),
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('l')->orderBy('l.code', 'ASC');
}
))
因此,当我进入我的表单页面时,我有一个块,其中包含一个输入文本字段(名称)和一个 select 字段(语言)。 select 字段是这样的:
<select id="product_infos_0_language" required="required" name="product[infos][0][language]">
<option value=""></option>
<option value="DE">DE</option>
<option value="EN">EN</option>
<option value="ES">ES</option>
<option selected="selected" value="FR">FR</option>
</select>
至此,一切正常。我创建了一个添加按钮,以便用户可以添加其他名称等...
但是,当我提交表单时,当我检查我的 ProductController 中的表单数据时,我注意到它与我想要存储在数据库中的内容不对应。
print_r($form->get('infos')->getData());
// returns :
Array
(
[0] => AppBundle\Entity\ProductName Object
(
[language:AppBundle\Entity\ProductName:private] => AppBundle\Entity\Language Object
(
[code:AppBundle\Entity\Language:private] => FR
[name:AppBundle\Entity\Language:private] => Français
)
[name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin
)
)
我想要的是:
Array
(
[0] => AppBundle\Entity\ProductName Object
(
[language:AppBundle\Entity\ProductName:private] => FR
[name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin
)
)
我不需要语言对象,而是直接需要语言代码 !
这就是为什么我认为我不应该在 ProductNameType 表单中使用 EntityField
而应该使用 ChoiceType
字段。
如何在选择字段中加载数据库中存储的所有语言?
我希望这个解释更容易理解 ;-)
您应该使用 choice_value 的 EntityType。
'choice_value' => function ($language) {
return $language->getCode();
},
编辑: 阅读您的编辑后,您确实是对的,不要使用 EntityType
但 ChoiceType
。要填充 choices
,我认为您应该使用 DependencyInjection 在您的表单中注入 LanguageRepository
,然后在您的存储库中创建一个查询以获取所有语言代码。
多亏了这个 post 我找到了解决方案:
ProductController.php : 在 createForm()
方法中将自定义数据作为选项传递。
// ...
// build the form
$em = $this->getDoctrine()->getManager();
$product = new Product();
$languages = $em->getRepository('AppBundle:Language')->findAllOrderedByCode();
$form = $this->createForm(ProductType::class, $product, array(
'languages' => $languages
));
ProductType 形式 : 在选项解析器中传递自定义数据
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Product',
'languages' => null
));
}
然后,在 buildForm()
函数中,在 CollectionType 字段中添加一个 entry_options
选项:
$builder->add('infos', CollectionType::class, array(
'entry_type' => ProductInfosType::class,
'entry_options' => array('languages' => $options['languages']),
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'label' => false,
'by_reference' => false
));
ProductInfosType 表单 : 在选项解析器中传递自定义数据(与 ProductForm 中的完全相同)
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\ProductName',
'languages' => null
));
}
现在,您有两种选择:您想要表单 returns 实体或简单字符串。
在我的示例中,我只需要语言代码(如 FR、EN 等)。
案例 1:return 仅当表单 posted 时的语言代码:
// Form/ProductInfosType.php
// ...
// Convert array of objects in an array of strings
$choices = array();
foreach ($options['languages'] as $lang) {
$code = $lang->getCode();
$choices[$code] = $code;
}
$builder->add('language', ChoiceType::class, array(
'placeholder' => '',
'choices' => $choices
));
// returns :
Array
(
[0] => AppBundle\Entity\ProductName Object
(
[name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin
[language:AppBundle\Entity\ProductName:private] => FR
)
)
案例 2:return 形式 posted 时的语言实体:
// Form/ProductInfosType.php
// ...
$builder->add('language', ChoiceType::class, array(
'placeholder' => '',
'choices' => $options['languages'],
'choice_label' => 'code',
'choice_value' => 'code'
));
// returns :
Array
(
[0] => AppBundle\Entity\ProductName Object
(
[name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin
[language:AppBundle\Entity\ProductName:private] => AppBundle\Entity\Language Object
(
[code:AppBundle\Entity\Language:private] => FR
[name:AppBundle\Entity\Language:private] => Français
)
)
)
使用此解决方案,我们无需将表单创建为服务即可将实体管理器作为参数传递。一切都在控制器和表单选项中进行管理。
我有一个实体 Product
。我的产品可以有多个不同语言的名称。法文名,英文名等。我不想使用自动翻译。
用户必须在产品表单中填写名称和select相应的语言。多亏了“添加”按钮,他可以添加任意多个名字。
所有语言都是管理员用户创建的(以另一种形式)。因此,Language
也是一个具有名称(例如:英语)和代码(例如:EN)的实体。
我创建了实体 ProductName
,它有一个名称和一种语言(符合用户在产品表单中所写的内容)。
在那种情况下,我不需要将实体 ProductName
与实体 Language
相关联。我只想要语言代码。所以,在我的 ProductName
实体中,我有这个 属性 :
/**
* @ORM\Column(name="Language_Code", type="string", length=2)
*/
private $language;
我的产品表单 (ProductType) 有一个 CollectionType 字段,以便添加多个名称。
// Form/ProductType.php
->add('infos', CollectionType::class, array(
'entry_type' => ProductInfosType::class,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'label' => false,
'mapped' => false
))
ProductInfosType 表单有 2 个字段:
// Form/ProductInfosType.php
->add('name', TextType::class, array(
'attr' => array('size' => 40)
))
->add('language', EntityType::class, array(
'placeholder' => '',
'class' => 'AppBundle:Language',
'choice_label' => 'code',
'attr' => array('class' => 'lang'),
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('l')->orderBy('l.code', 'ASC');
}
))
因此,当我进入我的表单页面时,我有一个块,其中包含一个输入文本字段(名称)和一个 select 字段(语言)。 select 字段是这样的:
<select id="product_infos_0_language" required="required" name="product[infos][0][language]">
<option value=""></option>
<option value="DE">DE</option>
<option value="EN">EN</option>
<option value="ES">ES</option>
<option selected="selected" value="FR">FR</option>
</select>
至此,一切正常。我创建了一个添加按钮,以便用户可以添加其他名称等...
但是,当我提交表单时,当我检查我的 ProductController 中的表单数据时,我注意到它与我想要存储在数据库中的内容不对应。
print_r($form->get('infos')->getData());
// returns :
Array
(
[0] => AppBundle\Entity\ProductName Object
(
[language:AppBundle\Entity\ProductName:private] => AppBundle\Entity\Language Object
(
[code:AppBundle\Entity\Language:private] => FR
[name:AppBundle\Entity\Language:private] => Français
)
[name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin
)
)
我想要的是:
Array
(
[0] => AppBundle\Entity\ProductName Object
(
[language:AppBundle\Entity\ProductName:private] => FR
[name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin
)
)
我不需要语言对象,而是直接需要语言代码 !
这就是为什么我认为我不应该在 ProductNameType 表单中使用 EntityField
而应该使用 ChoiceType
字段。
如何在选择字段中加载数据库中存储的所有语言? 我希望这个解释更容易理解 ;-)
您应该使用 choice_value 的 EntityType。
'choice_value' => function ($language) {
return $language->getCode();
},
编辑: 阅读您的编辑后,您确实是对的,不要使用 EntityType
但 ChoiceType
。要填充 choices
,我认为您应该使用 DependencyInjection 在您的表单中注入 LanguageRepository
,然后在您的存储库中创建一个查询以获取所有语言代码。
多亏了这个 post 我找到了解决方案:
ProductController.php : 在 createForm()
方法中将自定义数据作为选项传递。
// ...
// build the form
$em = $this->getDoctrine()->getManager();
$product = new Product();
$languages = $em->getRepository('AppBundle:Language')->findAllOrderedByCode();
$form = $this->createForm(ProductType::class, $product, array(
'languages' => $languages
));
ProductType 形式 : 在选项解析器中传递自定义数据
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Product',
'languages' => null
));
}
然后,在 buildForm()
函数中,在 CollectionType 字段中添加一个 entry_options
选项:
$builder->add('infos', CollectionType::class, array(
'entry_type' => ProductInfosType::class,
'entry_options' => array('languages' => $options['languages']),
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'label' => false,
'by_reference' => false
));
ProductInfosType 表单 : 在选项解析器中传递自定义数据(与 ProductForm 中的完全相同)
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\ProductName',
'languages' => null
));
}
现在,您有两种选择:您想要表单 returns 实体或简单字符串。
在我的示例中,我只需要语言代码(如 FR、EN 等)。
案例 1:return 仅当表单 posted 时的语言代码:
// Form/ProductInfosType.php
// ...
// Convert array of objects in an array of strings
$choices = array();
foreach ($options['languages'] as $lang) {
$code = $lang->getCode();
$choices[$code] = $code;
}
$builder->add('language', ChoiceType::class, array(
'placeholder' => '',
'choices' => $choices
));
// returns :
Array
(
[0] => AppBundle\Entity\ProductName Object
(
[name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin
[language:AppBundle\Entity\ProductName:private] => FR
)
)
案例 2:return 形式 posted 时的语言实体:
// Form/ProductInfosType.php
// ...
$builder->add('language', ChoiceType::class, array(
'placeholder' => '',
'choices' => $options['languages'],
'choice_label' => 'code',
'choice_value' => 'code'
));
// returns :
Array
(
[0] => AppBundle\Entity\ProductName Object
(
[name:AppBundle\Entity\ProductName:private] => Ceinture lombaire LombaSkin
[language:AppBundle\Entity\ProductName:private] => AppBundle\Entity\Language Object
(
[code:AppBundle\Entity\Language:private] => FR
[name:AppBundle\Entity\Language:private] => Français
)
)
)
使用此解决方案,我们无需将表单创建为服务即可将实体管理器作为参数传递。一切都在控制器和表单选项中进行管理。