Do You PHP はてブロ

Do You PHPはてなからはてブロに移動しました

データベースからデータを取得するカスタムFormTypeをサービスに登録して使う

前のエントリの続き。
カスタムFormTypeのコンストラクタ引数にDoctrine\ORM\EntityManagerオブジェクトを渡せばOK。
以下、都道府県を選択するカスタムFormTypeを作る場合の例。

手順1:Symfony\Component\Form\AbstractTypeのサブクラスを作成する

引数がDoctrine\Common\Persistence\ObjectManagerインターフェースとなっているが、EntityManagerクラスはObjectManagerインターフェースを実装している。
MPrefは都道府県一覧を格納したテーブル(m_pref)に対するEntityクラス。

<?php

namespace Acme\FormTypeBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Doctrine\Common\Persistence\ObjectManager;
use Acme\FormTypeBundle\Form\DataTransformer\PrefToIdTransformer;

/**
 * 都道府県FormType
 */
class PrefType extends AbstractType
{
    private $om;

    public function __construct(ObjectManager $om)
    {
        $this->om = $om;
    }

    public function getDefaultOptions(array $options)
    {
        $prefs = $this->om->getRepository('AcmeFormTypeBundle:MPref')
                            ->createQueryBuilder('a')
                            ->where("a.deleteFlag = '0' ")
                            ->orderBy("a.id ")
                            ->getQuery()->execute();
        $choices = array();
        foreach ($prefs as $pref) {
            $choices[$pref->getId()] = $pref->getPrefName();
        }

        return array(
            'choices' => $choices,
            'label' => '都道府県',
            'empty_value' => '選択してください',
            'property' => 'prefName',
            'multiple' => false,
            'expanded' => false,
        );
    }

    public function getName()
    {
        return 'acme_formtypebundle_preftype';
    }

    public function getParent(array $options)
    {
        return 'choice';
    }
}

手順2:Bundle/Resources/config/services.xml(もしくはservices.yml)

services.service.argument.typeにdoctrine.orm.entity_managerを指定すると、適切なEntityManagerオブジェクトが渡されるようになる。

<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

  <services>
    <service id="acme_formtype.type.pref" class="Acme\FormTypeBundle\Form\Type\PrefType">
      <argument type="service" id="doctrine.orm.entity_manager"/>
      <tag name="form.type" alias="pref" />
    </service>
  </services>

</container>

手順3:FormTypeで呼び出す

前のエントリと同様。

<?php

namespace Acme\FormTypeBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Acme\FormTypeBundle\Entity\MPrefRepository;

/**
 * formtype登録用Formクラス
 *
 * @version $Id$
 */
class FormtypeType extends AbstractType
{
    public function buildForm(FormBuilder $builder, array $options)
    {
        $builder
            /**
             * サービスに登録したFormType"pref"を利用する
             */
            ->add('prefecture', 'pref',
                array(
                    'required' => false,
                ))
        ;
    }

    public function getName()
    {
        return 'acme_formtypebundle_formtypetype';
    }
}

こんな感じでいろいろなカスタムFormTypeを作ってサービスに登録し、フォームを表示する際に必要なサービスを組み合わせていく、という使い方が良いんじゃないだろうか?と思った。

一応、ソースをgithubに入れといた。