2016-11-18 32 views
1

リポジトリパターンを使用してこの問題が発生しました。現在私はインターフェイスとそれを実現するためのカスタムクラスを使用し、それをコントローラの構造にヒントし、Laravelのためにリポジトリの依存関係を自動的かつ再帰的に解決します。Laravelの依存関係注入による抽象クラスの依存関係の解決

私はまた、サービスプロバイダで次の操作を行います。

$this->app->bind(path/to/repoInterface,path/to/implementationClass) 

しかし、私はこれらのリポジトリをコード化する方法のため、コードの重複を避けるために、私はすべてに共通するメソッドを持つ抽象クラスを作成しましたこれらのリポジトリ。

abstract class CommonRepo{ 

    public function __construct(SomeModelClass model){} 

    public function commonMethod(){//Code here} 

そして、私のリポジトリは以下の構造を有する:次のようにこのクラスはある

public class ExampleRepository extends CommonRepo implements ExampleRepositoryI{ 

    public function __construct(){ 
    parent::__construct(); 
    } 
} 

Laravelは、このエラーを与えるので、これを好きではない:

だから、
Argument 1 passed to path/to/repo/CommonRepo::__construct() must be an instance of path/to/model/SomeModelClass, none given, called in... 

、明らかにCommonRepoクラスの依存関係を解決していませんが、通常のリポジトリの依存関係を解決します。それが可能だ場合、私は、希望

、どのように私は、それから、そのクラスの依存関係を解決することができます 新しいオペレータ

に関連する何かをすることなく、タイプヒンティング(Laravelの道)を使用するには?

public class ExampleRepository extends CommonRepo implements ExampleRepositoryI 
{  
    public function __construct(SomeModelClass $model){ 
     parent::__construct($model); 
    } 
} 

または

public class ExampleRepository extends CommonRepo implements ExampleRepositoryI 
{  
    public function __construct(){ 
     parent::__construct(App::make(SomeModelClass::class)); 
    } 
} 
+1

あなたはこのhttp://meanderingsoul.com/dev/2015/04/dependency-injection-with-inherited-controllers-in-laravel-5 –

+0

でインスピレーションを得ることができますか親コンストラクタを呼び出すこと以外に何もする必要がない場合は、単にExampleRepositoryクラスからコンストラクタを削除してください。 –

+0

@MateuszDrost私はそれをタイプしませんでしたが、もっとする必要があります。それぞれのリポジトリは独自の依存関係を持っています(私はファサードの悪用を好まないので、たぶんEloquent Modelsです)。 – user2430929

答えて

2

親のコンストラクタは、依存リゾルバを触れることなく、通常の関数のように呼ばれています。私はこれがあなたが探しているものかどうかわからないけれども、いくつか微妙にやりました。しかし、リポジトリクラスに必要なEloquentモデルのインスタンスを動的に作成することができます。

さんがあなたのUserモデルクラスはapp\Models\User.phpに保存されているとしましょう:あなたは、あなたのリポジトリのすべてのクラスの基本抽象クラスを作成

<?php 

namespace App\Models; 

use Illuminate\Database\Eloquent\Model; 

class User extends Model 
{ 
    // 
} 

app\Repositories\BaseRepository.php。ここでは、リポジトリクラスのすべての共通機能を配置します。しかし、Eloquentインスタンスをコンストラクタに注入するのではなく、getModel()というメソッドを追加して、リポジトリ用のEloquentモデルのインスタンスを動的に作成することができます。

<?php 

namespace App\Repositories; 

use ReflectionClass; 
use RuntimeException; 
use Illuminate\Support\Str; 

abstract class BaseRepository 
{ 
    protected $modelNamespace = 'App\\Models\\'; 

    public function getById($id) 
    { 
     return $this->getModel()->find($id); 
    } 

    public function getModel() 
    { 
     $repositoryClassName = (new ReflectionClass($this))->getShortName(); 

     $modelRepositoryClassName = $this->modelNamespace . Str::replaceLast('Repository', '', $repositoryClassName); 

     if (! class_exists($modelRepositoryClassName)) { 
      throw new RuntimeException("Class {$modelRepositoryClassName} does not exists."); 
     } 

     return new $modelRepositoryClassName; 
    } 
} 

さて、あなたはUserモデルのリポジトリを作成したいとしましょう、とこのユーザーのリポジトリには、次のインタフェースを実装する必要があります。あなたはapp\Repositories\UserRepository.phpクラスを作成し、単にBaseRepositoryからそれを拡張app\Repositories\UserRepositoryInterface.php

<?php 

namespace App\Repositories; 

interface UserRepositoryInterface 
{ 
    public function getByEmail($email); 
} 

をクラス。また、UserRepositoryInterfaceに定義されているすべての実装を実装することを忘れないでください。

$this->app->bind(\App\Repositories\UserRepositoryInterface::class, \App\Repositories\UserRepository::class); 

最後に、あなたが自由に、コントローラのコンストラクターまたはメソッドにUserRepositoryInterfaceを注入することができます:あなたはそれにUserRepositoryInterfaceをバインドすることができ

<?php 

namespace App\Repositories; 

use App\Repositories\BaseRepository; 
use App\Repositories\UserRepositoryInterface; 

class UserRepository extends BaseRepository implements UserRepositoryInterface 
{ 
    public function getByEmail($email) 
    { 
     return $this->getModel()->where('email', $email)->firstOrFail(); 
    } 
} 

この方法はとてもような実装です。

$userRepository = App::make(App\Repositories\UserRepositoryInterface::class); 

$userRepository->getByEmail('[email protected]'); 

もちろん、このアプローチにキャッチがあります。リポジトリクラスは関連するモデルで開始する必要がありますので、InvoiceRepository.phpInvoice.phpモデルクラス専用です。

このヘルプが必要です。

+0

あなたの時間に感謝しますが、それは私が避けたいものです。なぜなら、parent :: __ construct(App :: make(SomeModelClass :: class))を書く必要があるからです。すべてのリポジトリ(現在のところ、私はその共通の親から拡張されている6つ)を持っているので、ComonRepoに依存関係を追加/削除/変更しなければならない場合、それは厄介になります。 – user2430929

2

素敵な質問: PD:あなたは二つの可能性のいずれかを実行する必要がありますので使用してはLaravel 5.2

+0

お返事ありがとうございました。私が望んでいたものではありませんが、将来私はモデルを注入したり、レポの名前と一致することがあるので、これを将来的に使うことは間違いありません。 getModel()メソッドをキャッシュするべきではありませんか?それをコンストラクタで呼び出すのと同じですか? – user2430929

0

これは役に立ちます。オブジェクトが解決して属性を設定するときに、耳を傾けることができます。

$this->app->resolving(CommonRepo::class, function ($object, $app) { 
    // Called when container resolves object of any type... 
    $object->commonObject = app(CommonObject::class); 
}); 

ドキュメント:https://laravel.com/docs/5.4/container#container-events

関連する問題