10分ぐらいで学べるSymfony2 〜DataFixturesの使い方編〜
Symfony2にはDoctrineFixturesBundleというデータを投入するバンドルが存在し、コマンドからデータを投入する方法はマニュアルに記載があります。
phpunitのsetUp処理でデータを「クリア→投入」したかったのですが、やり方が見当たらなかったので調べたメモとなります。
バンドルのインストールなどは「DoctrineFixturesBundle」を参照してください。
1.DoctrineFixturesBundleの簡単な使用例
1.1 Fixtureファイルの作成
Hoge/UserBundleにFixtureを作成する場合の例となります。
バンドルの「DataFixtures/ORM」の下にfixtureファイルを置きます
# mkdir -p src/Hoge/UserBundle/DataFixtures/ORM/ # vi src/Hoge/UserBundle/DataFixtures/ORM/LoadUser1Data.php namespace Hoge\UserBundle\DataFixtures\ORM; use Doctrine\Common\DataFixtures\FixtureInterface; use Hoge\UserBundle\Entity\User; class LoadUserData implements FixtureInterface { public function load($manager) { $user = new User(); $user->setEmail('admin'); $user->setPassword('test'); $user->setSalt('hoge'); $manager->persist($user); $manager->flush(); } }
1.2 コマンド実行
これでコマンドを実行することでデータは投入されます
(デフォルトだと投入前のデータは消去)
$ php app/console doctrine:fixtures:load
2. 複数fixtureのデータ連携
Userテーブルの情報を他テーブルのデータロードに利用するなど複数のfixtureファイル間でのデータの連携をしたい場合の例となります。
OrderedFixtureInterfaceをimplementsしつつ、AbstractFixtureを継承してます。
# vi src/Hoge/UserBundle/DataFixtures/ORM/LoadUser2Data.php <?php namespace Hoge\UserBundle\DataFixtures\ORM; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Hoge\UserBundle\Entity\User; class LoadUser2Data extends AbstractFixture implements OrderedFixtureInterface { public function load($manager) { $user = new User(); $user->setEmail('user1'); $user->setPassword('test1'); $user->setSalt('hoge1'); $manager->persist($user); $manager->flush(); $this->addReference('user1', $user); } public function getOrder() { return 1; // the order in which fixtures will be loaded } }
ApiTokenテーブルではUserテーブルのプライマリーキーをuser_idカラムに保持する構造になってます。
# vi src/Hoge/UserBundle/DataFixtures/ORM/LoadApiTokenData.php <?php namespace Hoge\UserBundle\DataFixtures\ORM; use Doctrine\Common\DataFixtures\AbstractFixture; use Doctrine\Common\DataFixtures\OrderedFixtureInterface; use Hoge\UserBundle\Entity\ApiToken; class LoadApiTokenData extends AbstractFixture implements OrderedFixtureInterface { public function load($manager) { $apiToken = new ApiToken(); $apiToken->setUserId($manager->merge($this->getReference('user1'))->getId()); $apiToken->setToken('hoge'); $apiToken->setExpired(new \DateTime()); $manager->persist($apiToken); $manager->flush(); } public function getOrder() { return 2; // the order in which fixtures will be loaded } }
LoadUser2Dataで「addReference('user1', $user)」する事でLoadApiTokenDataのgetReferenceで
セットしたオブジェクトをロードできます。
また、getOrderでは読込ファイルの順序を設定できます。
例えば、LoadUser2DataのgetOrderの戻値を10と指定するとLoadApiTokenDataを先にロードしようとして
user1が定義されてないとエラーになります。
3. fixtureでコンテナを使う
ContainerAwareInterfaceをimplementsしてsetContainerを実装することで
fixture内でコンテナを扱えるようになります。
# vi src/Hoge/UserBundle/DataFixtures/ORM/LoadUser3Data.php <?php namespace Hoge\UserBundle\DataFixtures\ORM; use Doctrine\Common\DataFixtures\FixtureInterface; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Hoge\UserBundle\Entity\User; class LoadUser3Data implements FixtureInterface, ContainerAwareInterface { private $container; public function setContainer(ContainerInterface $container = null) { $this->container = $container; } public function load($manager) { $user = new User(); $user->setEmail('user3'); $user->setSalt('hoge3'); $encoder = $this->container->get('security.encoder_factory')->getEncoder($user); $user->setPassword($encoder->encodePassword('test', $user->getSalt())); $manager->persist($user); $manager->flush(); } }
4. ソースコードからfixtureを呼び出し
テストファイルからfixtureを呼び出す際の処理となります。
LoadUser2Dataがテストのたびに「クリア→投入」されるようになります。
use Symfony\Bundle\DoctrineFixturesBundle\Common\DataFixtures\Loader; use Hoge\UserBundle\DataFixtures\ORM\LoadUser2Data; use Doctrine\Common\DataFixtures\Executor\ORMExecutor; use Doctrine\Common\DataFixtures\Purger\ORMPurger; public function setUp() { $kernel = static::createKernel(); $kernel->boot(); $loader = new Loader($kernel->getContainer()); $loader->addFixture(new LoadUser2Data); $fixtures = $loader->getFixtures(); $em = $kernel->getContainer()->get('doctrine.orm.entity_manager'); $purger = new ORMPurger($em); $purger->setPurgeMode(ORMPurger::PURGE_MODE_TRUNCATE); $executor = new ORMExecutor($em, $purger); $executor->execute($fixtures);