Symfony2 サービスにEntityManagerを注入します(Dependency Injection)

データベース操作を伴うサービス(ビジネスロジック)を開発する際、エンティティマネージャをどうやって求めれば良いでしょうか?
呼出側から都度もらう?自前でコンテナ経由で取得(ハードコード)する?
んー、サービス呼出時にコンテナから注入してもらいましょうか。実験します。

テストデータ

mysql> select * from products where id = 2;
+----+-----------------+--------+--------------------------+
| id | name            | price  | description              |
+----+-----------------+--------+--------------------------+
|  2 | ドイツパン      | 380.00 | 美味しいけど高い         |
+----+-----------------+--------+--------------------------+
1 row in set (0.00 sec)

サービスの実装クラス

コンストラクタでエンティティマネージャをもらって、メンバとして保持しておきます。

use Doctrine\ORM\EntityManager;

class FooBar
{
    protected $em;

    public function __construct(EntityManager $em)
    {
        $this->em = $em;
    }

    public function findProduct($id)
    {
        $repository = $this->em->getRepository('XxxxSampleBundle:Product');

        return $repository->find($id);
    }
}

サービスの定義

エンティティマネージャは、 doctrine.orm.entity_managerdoctrine.orm.entity_manager でコンテナに登録されています。
エンティティマネージャをサービスの実装クラスに注入します。(コンストラクタ経由)

services:
    foo_bar:
        class: Xxxx\SampleBundle\Domain\FooBar
        arguments:
            em: "@doctrine.orm.entity_manager"

$ php app/console container:debug foo_bar
[container] Information for service foo_bar

Service Id       foo_bar
Class            Xxxx\SampleBundle\Domain\FooBar
Tags             -
Scope            container
Public           yes
Synthetic        no
Required File    -

サービス利用側コード

コンテナからサービスを取得して使います。コンテナにより、サービスにエンティティマネージャが注入されます。

use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class TestDoctrineEntityManagerCommand extends ContainerAwareCommand
{

    protected function configure()
    {
        $this->setName('sample:entity-manager');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $fooBar = $this->getContainer()->get('foo_bar');

        print_r($fooBar->findProduct(2));

    }
}

実行結果

$ php app/console sample:entity-manager
Xxxx\SampleBundle\Entity\Product Object
(
    [id:protected] => 2
    [name:protected] => ドイツパン
    [price:protected] => 380.00
    [description:protected] => 美味しいけど高い
)

テストコード

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class FooBarTest extends WebTestCase
{
    static protected $kernel;
    static protected $container;

    protected $fooBar;

    protected function setUp()
    {
        parent::setUp();

        static::$kernel = static::createKernel();
        static::$kernel->boot();
        static::$container = static::$kernel->getContainer();

        $this->fooBar = static::$container->get('foo_bar');
    }

    public function testFindProduct()
    {
        $actual = $this->fooBar->findProduct(2);
        $this->assertInstanceOf('Xxxx\SampleBundle\Entity\Product', $actual);
    }
}