エンティティProduct
があります。私の製品は、異なる言語で複数の名前を持つことができます。フランス語の名前、英語の名前など。自動翻訳は使いたくありません。
ユーザーは製品フォームに名前を記入し、対応する言語を選択する必要があります。 [追加]ボタンのおかげで、彼は好きなだけ名前を追加できます。
すべての言語は、管理者ユーザーによって(別の形式で)作成されます。したがって、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 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
フィールドを使用する必要があると思います。
dbに格納されているすべての言語を選択フィールドにロードするにはどうすればよいですか?この説明がより理解しやすいことを願っています;-)
この投稿のおかげで解決策を見つけました: Symfony 2.8/3.0のbuildForm()にデータを渡す
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 form:オプションリゾルバーでカスタムデータを渡します
_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 form:オプションリゾルバーでカスタムデータを渡します(ProductFormとまったく同じです)
_public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\ProductName',
'languages' => null
));
}
_
ここで、2つの選択肢があります。フォームがエンティティを返すか、単純な文字列を返すかです。
私の例では、言語コード(FR、ENなど)が必要です。
ケース1:フォームが投稿されたときに言語コードのみを返します:
_// 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:フォームが投稿されたときに言語エンティティを返す:
_// 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
)
)
)
_
このソリューションでは、エンティティマネージャーを引数として渡すために、フォームをサービスとして作成する必要はありません。すべてはコントローラーとフォームオプションで管理されます。
EntityTypeの choice_value を使用する必要があります。
'choice_value' => function ($language) { return $language->getCode(); },
EDIT:編集内容を読んだ後は、確かに正しいです。EntityType
ではなくChoiceType
を使用してください。 choices
にデータを入力するには、DependencyInjectionを使用してフォーム内にLanguageRepository
を挿入し、リポジトリにクエリを作成してすべての言語コードをフェッチする必要があると思います。