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するところなどポイントは多々ありますが、テンプレを作って動くサンプルを作ることがポイントね。