我有一个具有属性的实体,该属性被设置为一个数组
/**
* @ORMColumn(type="array")
*/
private $labels = [];
此数组的数据存储
等标签的翻译[
'en' => 'foo-in-English',
'de' => 'foo-in-German',
'ru' => 'foo-in-Russian'
]
我有一个类型的表格,用于标签:
$builder
->add('labels', CollectionType::class);
请注意,entry_type
在此处默认为TextType
。左,模板将使用文本字段显示,例如:
Labels: en: _____FOO IN ENGLISH____
de: _____FOO IN GERMAN_____
ru: _____FOO IN RUSSIAN____
但是,我希望以实际语言 name 而不是两字母 code 作为标签显示这些字段,所以类似:
Labels: English: _____FOO IN ENGLISH____
German: _____FOO IN GERMAN_____
Russian: _____FOO IN RUSSIAN____
我还想确保显示我的所有选择/支持的语言,即使它们当前没有价值。
因此,这似乎是DataTransFormer的合适地方,但是请尝试我无法在表单类中在中工作。似乎试图改变收集类型的数据比像文本这样的简单类型更困难(或不可能?(。
,我通过在将控制器的数据提交到表单之前和在持久之前处理表单后将其转换为控制器中的数据来克服这一方法。例如
$this->transformTranslations($fooEntity);
$form = $this->createForm(FooType::class, $fooEntity);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$fooEntity = $form->getData();
$this->reverseTransformTranslations($fooEntity);
$this->getDoctrine()->getManager()->persist($fooEntity);
$this->getDoctrine()->getManager()->flush();
...
我想知道是否有人有更好的方法(例如如何使用普通数据或模型变压器(。我似乎找不到有关使用带有收集类型的数据变压器的在线网上。tia!
我之前没有亲自使用学说数组值,但是您可以为每个翻译选项定义"默认"表单类,例如:
appbundle form languagestringitytype.php
class LanguageStringEditorType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('en', TextareaType::class, ['label' => 'English'])
->add('de', TextareaType::class, ['label' => 'German'])
->add('ru', TextareaType::class, ['label' => 'Russian'])
;
}
}
如果您将命名('en','de'和'ru(保持与数据阵列键的名称相同,例如具有这样的(学说(实体:
AppBundle Entity languagestring.php
class LanguageString {
private $identifier;
private $translations; // this is the doctrine array type
// however I didn't feel like setting up a database for this
// test so I'm manually filling it see the next bit
... Getter and setter things ...
并为此创建一种类型:
appbundle form languagestringtype.php
class LanguageStringType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('identifier')
->add('translations', LanguageStringEditorType::class, ['label' => 'Translations'])
;
}
}
我们可以在控制器中使用它
$data = new LanguageString();
// fill some dummy content (not using database)..
$data->setIdentifier('hello_world');
$data->setTranslations([
'en' => 'Hello world!',
'de' => 'Hallo Welt!',
'ru' => 'Привет мир'
]);
$form = $this->createForm(LanguageStringType::class, $data);
return $this->render('default/index.html.twig', [
'form' => $form->createView()
]);
剩下的是通过魔术完成的,无需变形金刚。数据放在表单字段中。并在使用HandleRequest时设置为实体。请记住,数据键值与形式构建器名称相同。
作为奖励,您已在语言diportype类中定义了所有默认语言字段(填充与否(。
所以,我了解到我需要将两个需求分为不同的解决方案。首先,我创建了一种新的表单类型,而不是我默认使用的文本类型:
$builder
])
->add('labels', CollectionType::class, [
'entry_type' => TranslationType::class
])
此类非常简单,只是常规文本类型的扩展:
class TranslationType extends AbstractType
{
/**
* @var LocaleApiInterface
*/
private $localeApi;
/**
* TranslationType constructor.
* @param LocaleApiInterface $localeApi
*/
public function __construct(LocaleApiInterface $localeApi)
{
$this->localeApi = $localeApi;
}
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['label'] = array_search($view->vars['name'], $this->localeApi->getSupportedLocaleNames());
}
public function getParent()
{
return TextType::class;
}
}
这满足了标签问题。其次,为了确保我的数据中有所有受支持的语言环境,我使用了一个formEventListener:
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$supportedLocales = $this->localeApi->getSupportedLocales();
$data = $event->getData();
$labels = $data['labels'];
foreach ($supportedLocales as $locale) {
if (!array_key_exists($locale, $labels)) {
$labels[$locale] = $labels['en'];
}
}
$data['labels'] = $labels;
$event->setData($data);
});
如果尚未存在数据,这将为数据添加所需的键。