2017-01-30 15 views
2

Symfony 3.xでは、Doctrine EntitiesをJSON-Responses(JMSSerializerおよびFOSRestBundle)として提供するAPIレイヤーを使用しています。SymfonyのカスタムObjectNormalizersシリアライゼーションコンポーネント。コンテナ対応の抽象基底クラスでクラス継承を使用する

これらのAPIクラスのカップルは、コンテナを認識する必要があります。現在、グローバルな$kernelを使用しています。

これは私がこれまでのところ(非常に簡略化)しようとしたものです:

抽象クラス

abstract class ApiWrapper implements ContainerAwareInterface 
{ 
    use ContainerAwareTrait; 

    protected $container; 

    public function setContainer(ContainerInterface $container = null) 
    { 
     $this->container = $container 

    } 
} 

BaseClassの

protected class BaseApi extends ApiWrapper 
{ 
    //...some stuff 
} 

RealApiClass1

protected class MyApi1 extends BaseApi 
{ 
    protected $entity; 

    public function __construct(SomeEntityClass $entity) { 
     $this->entity = $entity; 

    } 
} 

RealApiClass2

protected class MyApi2 extends BaseApi 
{ 
    protected $entity; 

    public function __construct(AnotherEntityClass $entity) { 
     $this->entity = $entity; 
    } 
} 

services.yml

services: 
    bundle.api_wrapper: 
     class: ApiWrapper 
     abstract: true 
     shared: false // to make sure to get a new instance everytime it's called 
     calls: 
      - [ setContainer, [ @service_container ] ] 
    bundle.base_api: 
     class: BaseApi 
     parent: api_wrapper 
    bundle.my_api: 
     class: MyApi 
     parent: base_api 

コントローラ

$myApi = new MyApi1($myEntity); 

$myApiにはプロパティコンテナがありますが、それはnullです。 このシナリオでコンテナを共有する方法はありますか?あなたは一例として、コンテナ経由でAPIを取得する必要がありますコントローラで

+0

私はあなたが達成しようとしていることを知りませんが、コンテナの初期設計を破るのではなく、なぜそれをして適切な解決策を見つけるのかを正しく説明したいと思うかもしれません。ここのすべては中期的にも非常に悪いものです。サイクリック依存関係の問題が発生していますか? –

+0

既に指摘したように、新しい演算子はSymfonyコンテナに関する知識がありません。 1つの可能性は、APIの工場クラスを作ることです。しかし実際には、完全な容器を注入する理由はほとんどありません。 – Cerad

+0

@Ceradに感謝、あなたは工場のクラスのためのいくつかの方向を教えてくれますか?定義されたサービスのカップル(実際には現時点では2)を注入できるかどうかは問題ありません。 – LBA

答えて

3

彼らのAPIクラスに。これを行う方法の1つは、実際にAPIクラスを作成するためのファクトリを使用することです。これには設定が少し簡単になるという利点があります。

このコードはテストされていないため、簡単に構文エラーが発生する可能性があります。

class ApiFactory 
{ 
    $container; 
    public function __construct($container) { 
     $this->container = $container; 
    } 
    public function create($entity) { 
     $api = null; 
     switch(get_class($entity)) { // Map entity to api class 
      case MyEntity1::class : 
       $api = new MyApi1($entity); 
       break; 
      case MyEntity2::class : 
       $api = new MyApi2($entity); 
       break; 
      default: 
       throw new Exception('Oops'); 
     } 
     // Steal a trick from the controller resolver 
     if ($api instanceof ContainerAwareInterface) { 
      $api->setContainer($this->container); 
     } 
     return $api; 
    } 
} 

抽象的なApiWrapperクラスが本当に必要ないことに注意してください。特定のAPIがコンテナを必要とする場合は、コンテナ認識インタフェースを実装してその特性を追加するだけです。

// Usage in a controller 
$apiFactory = $this->get('my_api_factory'); 
$api = $apiFactory->create($myEntity); 

// services.yml 
services: 
    my_api_factory: 
     class: ApiFactory 
     arguments: ['@service_container'] 

さまざまなバリエーションがあります。私はそれが各apiのためのサービスを定義し、コンテナの代わりに必要な正確な依存関係を注入する方が良いと思う。 apiのクラス名を使用して各apiサービスに名前を付けることができます。あなたのAPI工場は、エンティティクラス名を使用してキーを生成するために、コンテナから完全に構成された完全なapiを取り出すだけです。

+0

は非常にきれいに見えますが、醜い依存関係(私たちは後で早急に取り除く必要があります)を受けても、かなりデカップリングされた解決策です。私はそれを試してみましょう - 私は答えを受け入れる前にそれをプロトタイプにしてください。そしてもちろんそれはテストされていません - 私の仕事をさせてください;-) – LBA

1

コントローラ

かかわらず、あなたはそれが実体をマッピングするための痛みを少しすることができ、サービスを設定する方法の
$myApi = $this->get('bundle.my_api'); 
+0

ありがとうございます - これらのクラスをすべて「標準」サービスとして定義して使用しない他のオプションはありますか? – LBA

+0

こんにちは@LBA私は知らないが、あなたは自動ワイヤサービスの機能を試すことができます。もっと助けが必要な場合は教えてください! – Matteo

関連する問題