Issei.M's Techlog

Web/iOS エンジニアの僕が技術関連のメモ等をつらつらと。主に Symfony について書いています。

[Symfony][Doctrine] Fixtures からサービスコンテナを取得する

Fixtures 内で、サービスコンテナを呼び出したくなる事はしばしばあります。

例えば User エンティティクラスが Security コンポーネントの UserInterface を実装している場合、PasswordEncoder を使いたくなりますね。 しかしそのままでは AbstractFixture クラス内でサービスコンテナが取得できないので、PasswordEncoder の取りようがありません。

そんな時は、AbstractFixture に ContainerAwareInterface を実装してしまいましょう。

// src/Acme/UserBundle/DataFixtures/ORM/LoadUserClassData.php

namespace Acme\UserBundle\DataFixtures\ORM;

use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Acme\UserBundle\Entity\User;

// ↓追加
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

class LoadUserClassData extends AbstractFixture
    implements OrderedFixtureInterface, ContainerAwareInterface // ←追加
{
    ///**
     * @var ContainerInterface
     */
    private $container;

    /**
     * {@inheritDoc}
     */
    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }

    // ~
}

これで load が実行される前にサービスコンテナが格納されます。
実際に load 時に使用する場合は次の様な感じです。

public function load(ObjectManager $manager)
{
    $factory = $this->container->get('security.encoder_factory');

    $user1 = new User();
    $user1->setUserName('issei');
    $user1->setSalt(hash('sha512', mt_rand(111111, 999999)));

    $encoder = $factory->getEncoder($user1);
    $user1->setPassword($encoder->encodePassword('hogehoge', $user1->getSalt()));
}

詳しくは公式のドキュメントを参照
http://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html#using-the-container-in-the-fixtures