3228


自作クラスからDoctrineを呼びたいのですが、サービスコンテナとして定義してDIする他に方法は無いのでしょうか。

追記

この自作クラスは、Doctrineのエンティティクラスではない、普通のクラスです。

Acme/AppBundle/BuilderにSubscriberDirector.phpとSubscriberBuilder.phpを用意して、Controllerから

[code]

    $builder = new SubscriberBuilder();
    $director = new SubscriberDirector($builder);
    $subscriber = $director->getSubscriber();
    
[/code]

というようにBuilderパターンを適用したいです。

SubscriberBuilderクラス内でSubscriberのプロパティにDBより読み込んだ値をセットしたいのですが、可能でしょうか。

また、現在はServiceにscope:
prototypeとしてSubscriberBuilderとSubscriberDirectorを登録してDoctrineをDIして

[code]

    subscriber_builder:
        class: Acme\AppBundle\Builder\Subscriber\SubscriberBuilder
        scope: prototype
        arguments: [@doctrine]
    
[/code]

Controllerからは

[code]

    $builder = $this->get('subscriber_builder');
    $director = $this->get('subscriber_director');
    $director->initialize($builder);
    $subscriber = $director->getSubscriber();
    
[/code]

として使っていますが、Serviceのスコープは本来このような使い方をするものではないのではないかともやもやしています。


CC BY-SA 3.0
2015-01-06T12:36:29.917
3195
2015-01-07T03:35:47.717
2015-01-06T16:06:16.377
30
6059
question
symfony2 doctrine2
Symfonyで自作クラス内からDoctrineを呼ぶ方法


PHPなので、欲しいサービスをどこかでグローバル変数にでも保存してしまえば、自由にどこからでもそれを使うことはできますが、これは希望する方法ではありませんよね。OOPの設計原則などから外れない方向でコードを整理していくのならば、Symfonyが提供するアーキテクチャに沿う形をとっておく方が良いです。

Symfonyは基盤にすばらしいサービスコンテナを有しており、自作のクラスなどもサービスコンテナの管理下におく方が素直です。今回質問されている「DoctrineのEntityManagerを使いたい」という目的の場合にかぎらず、サービスコンテナの管理下にすることで、自然とすべてがDependencyInjection可能な世界に属することになり、そこでは[DIP（依存関係逆転の原則）](http://d.hatena.ne.jp/asakichy/20090128/1233144989)などOOPの設計原則などを有効活用したプログラミングスタイルをとることができます。

## サービスコンテナから何を受け取るか？

質問で提示されたコードのサービス定義では、`@doctrine` を注入しています。この名前のサービスは
`Doctrine\Bundle\DoctrineBundle\Registry`
クラスのインスタンスで、利用する側では、次のようにEntityManager、Repositoryを順に取得して使われていると思います。

[code]

    $em = $doctrine->getManagerForClass(get_class($entity));
    $repository = $em->getRepository(get_class($entity));
    $entityList = $repository->findBy〜
    
[/code]

これで動作に問題はありませんが、目的が「レコードの取得のみ」であって、特に更新などのトランザクションを必要としないのであれば、EntityManagerではなくRepositoryだけあれば十分です。ですので、サービス定義で
`@doctrine` ではなくて、必要なリポジトリだけを注入するよう設定します。

ただし、Repository
はデフォルトではサービス定義されていないため、こちらも別途サービス定義しておく必要があります。やや特殊な記述になりますが、以下のページにあるようなお決まりの書き方になります。

  * [Doctrine の Repository をサービスコンテナに登録する](http://issei-m.hatenablog.jp/entry/2013/12/12/170528)

## サービスの scope

サービスの `scope` については、デフォルトである `container` のままで良いことがほとんどかと思います。`prototype`
は、取得のたびに新しいインスタンスが必要な場合に使います。今回のように依存しているサービスが固定であり、コンストラクタなどに特に実行時依存のパラメータを含まないサービスであれば、毎回新しいインスタンスを作る必要はないのではないでしょうか。
（`prototype` を指定された理由が何かあったのだと思いますが、質問にあるコードを見る限りでは、不要ではないかと思います。）

  * [How to Work with Scopes (The Symfony CookBook)](http://symfony.com/doc/current/cookbook/service_container/scopes.html)


CC BY-SA 3.0
2015-01-07T03:29:49.663
3228
2015-01-07T03:35:47.717
2015-01-07T03:35:47.717
5444
5444
3195
answer