DoctrineなどのQueryBuilderで取得した項目をフォームで利用するなど当たり前の事なのですが、これがSymfony2ではインジェクションをしないことには実装できません。意外とややこしいのです。
例えば
class ExampleType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('AcmeUserBundle:user')->findAll();
$choices = array();
foreach($entities as $entity)
{
$choices[$entity->getId()] = $entity->getName();
}
$builder
->add('column_name', 'choice', array( 'choices' => $choices )))
;
}
なんて事ができればいいのですが、インジェクションしないとこれは動きません。で!どのようにするかというと、service.yml に インジェクションするコンストラクタを設定定義してます。この定義した内容を formTypeをnewする際にコントローラー側から getします。コード見ないときっとわかりにくいかと思います。
まずは service.yml ですが、各bundle内でも構いませんし、appの中でも構いません。bundleの中に記述したほうが分かりやすいと思ってます。
service.yml の内容
services:
acme_user.user.form.type:
class: Acme\UserBundle\Form\UserType
arguments: ["@doctrine.orm.entity_manager", "@service_container"]
tags:
- { name: form.type, alias: app_user_user }
@doctrine.orm.entity_manager
@service_container
は php app/console container:debug で一覧表示できますが、細かい動作の内容についてはsensioのソースの中を調べることになります。自分で書いたservice.ymlも同じようにコンストラクタとしてインジェクション出来ます。便利ですね。
続いてformTypeクラスのコンストラクタを記述します。先の動作しないformTypeを書き換えます。__construct を実装している所がポイントです。
class ExampleType extends AbstractType
{
private $doctrine, $service_container;
// private $user;
public function __construct($doctrine, $service_container)
{
$this->doctrine = $doctrine;
$this->service_container = $service_container;
/* 下記のように予め書いておくことでUserにもアクセスできます。 */
// $this->user = $service_container->get('security.context')->getToken()->getUser();
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$entities = $this->doctrine->getRepository('AcmeUserBundle:user')->findAll();
$choices = array();
foreach($entities as $entity)
{
$choices[$entity->getId()] = $entity->getName();
}
$builder
->add('column_name', 'choice', array( 'choices' => $choices )))
;
}
public function getName()
{
return 'app_user_user'; /* service.ymlのalias名を入力 */
}
このformTypeをコントローラーからアクセスします。
$form = $this->createForm($this->get('acme_user.user.form.type'), $entity, array(
'action' => $this->generateUrl('user_create'), // you should fix
'method' => 'POST',
));
という感じで $this->get(‘service.ymlで定義した名前’); という風に クラスを new します。すると service.yml 経由で目的のクラスをインジェクションすることが出来ます。
多用するの結構面倒なんですよね。service.ymlの記述とコンストラクタをつくるところや、formtypeをnewするところなどポイントは多々ありますが、テンプレを作って動くサンプルを作ることがポイントね。