web-dev-qa-db-ja.com

Symfony2を使用してコントローラーの外部のサービスにアクセスするにはどうすればよいですか?

サードパーティのAPIにかなり依存しているサイトを構築しているので、APIラッパーをサービスとしてパッケージ化することは理にかなっていると思いましたが、アクセスできると便利なインスタンスを見つけ始めていますエンティティリポジトリ内など、コントローラの外部。また、これに関連して、コントローラーの外部(エンティティリポジトリ内など)の構成値にアクセスできると便利です。

これが可能かどうか、そして可能でない場合、この種のことを行うための推奨されるアプローチはありますか?

助けてくれてありがとう

51
pogo

Symfonyディストリビューションは依存性注入に大きく依存しています。つまり、通常、依存関係はコンストラクター、セッター、または他の手段(プロパティのリフレクションなど)を介してオブジェクトに直接注入されます。 APIラッパーサービスは、アプリケーションの他のオブジェクトの依存関係になります。

とは言っても、このサービスはすでに他のパラメーターを必要としているため、エンティティリポジトリのコンストラクターにこのサービスを注入することはかなり難しく、エンティティのリポジトリを要求する方法が原因でそれらを注入することは不可能だと思います。

あなたができることは、エンティティー・リポジトリーで実行しようとしている作業を実行する責任がある別のサービスを作成することです。このようにして、エンティティリポジトリを取得するために使用されるエンティティマネージャ、カスタムサービス、および構成値を保持する別のサービスを挿入できます(構成値を共有する他の方法があります)。

私の使用例では、Facebook API呼び出しをラップするFacebookヘルパーサービスを使用しています。このサービスは、必要な場所に挿入されます。私のエンティティー・リポジトリーは、データベース呼び出しの実行のみを担当するため、依存関係全体ではなく、必要な引数のみを受け取ります。したがって、ヘルパーを受け取るのではなく、リクエストを実行するために必要な引数(FacebookユーザーIDなど)のみを受け取ります。私の意見では、エンティティリポジトリにそのようなヘルパーオブジェクトへの依存関係があってはならないので、これがその方法です。

以下は、設定としてYAMLを使用した小さな例です。

# app/config/config.yml
services:
  yourapp.configuration_container:
    class: Application/AcmeBundle/Common/ConfigurationContainer
    # You could inject configurations here      

  yourapp.api_wrapper:
    class: Application/AcmeBundle/Service/ApiWrapperService
    # Inject other arguments if needed and update constructor in consequence    

  yourapp.data_access:
    class: Application/AcmeBundle/Data/Access/DatabaseAccessService
    arguments: 
      entityManager: "@doctrine.orm.entity_manager"
      apiWrapperService: "@yourapp.api_wrapper"
      configuration: "@yourapp.configuration_container"

# Application/AcmeBundle/Common/ConfigurationContainer.php
public ConfigurationContainer
{
   public function __construct()
   {
       // Initialize your configuration values or inject them in the constructor
   }
}        

# Application/AcmeBundle/Service/ApiWrapperService.php
public ApiWrapperService
{
   public function __construct()
   {
       // Do some stuff
   }
}

# Application/AcmeBundle/Data/Access/DatabaseAccessService.php
public DatabaseAccessService
{
    public function __construct(EntityManager $entityManager, ApiWrapperService $apiWrapperService, ConfigurationContainer $configuration)
    {
        ...
    }
}

Config.ymlファイルのアットマーク(@)は、Symfonyが別のサービスを注入する必要があることを意味し、アットマークの後にIDが定義されており、単純な文字列ではありません。構成値については、前に述べたように、パラメーターやバンドル拡張を使用するなど、同じ目標を達成する他の方法があります。バンドル拡張を使用すると、構成値をconfig.ymlに直接定義して、バンドルがそれらを読み取ることができます。

結論として、これはサービスを注入することの一般的な考えを与えるはずです。この件に関するドキュメントの小さなリストです。多くのリンクはYAML定義の代わりにXMLサービス定義を使用していますが、それらを簡単に理解できるはずです。

  1. symfony公式DI
  2. Fabien PotencierのDIに関する記事
  3. Richard MillerのDIに関する記事 (他のDI記事については彼のブログを確認してください)

私が与えている設定がSymfony2のBeta1で機能していることに注意してください。私はまだBeta2に更新していなかったので、Beta2バージョンのように機能していないものがあるかもしれません。

これが問題の最終的な解決策を定義するのに役立つことを願っています。説明やその他のことをしたい場合は、遠慮なく他の質問をしてください。

よろしく、マット

74
Matt

私はこのような振る舞いを(マネージャーのような)Symfonyサービスにラップします。これらは主にオブジェクトマネージャーのクエリを使用してデータをフェッチするために使用する必要があるため、エンティティリポジトリにパラメーターやロジックを挿入しません。私はサービスにロジックを入れ、サービスがデータベースアクセスを必要とする場合、エンティティリポジトリを呼び出してデータをフェッチします。

0
shacharsol