harryg
harryg

Reputation: 24077

Laravel interface injection of decorated repositories

I've been following the really helpful Laracast on decorating repositories in order to provide different layers getting data from models.

In implementing it I made 2 repositories for my Client model that both implement the ClientRepository interface (a caching repo and a db repo).

I then made a service provider and registered them accordingly.

In the same manner I did the same for an FxRateRepository. Here is the service provider that does the registration:

// Providers/DatabaseServiceProvider

public function register()
{
    // Register the fx repositories
    $this->app->singleton('\repositories\FxRateRepository', function()
    {
        return new CacheFxRateRepository(new DbFxRateRepository);
    });

    // Register the client repositories
    $this->app->singleton('\repositories\ClientRepository', function()
    {
        return new CacheClientRepository(new DbClientRepository);
    });
}

Now this is all well and good and works well... until I realised that my DbClientRepository needs an instance of FxRateRepository. In my service provider I "new up" an instance of each repo and pass them into the parent repos as dependencies.

Obviously I can't pass an interface into DbClientRepository so how do I tell Laravel to inject an implementation of FxRateRepository into my DbClientRepository?

I tried just type-hinting in the constructor of the DbClientRepository but I get an Exception:

class DbClientRepository implements ClientRepository {
  private $fxRepo;
  public function __construct(FxRateRepository $fxRepo)
  {
      $this->fxRepo = $fxRepo;
  }
}

Argument 1 passed to repositories\DbClientRepository::__construct() must be an instance of repositories\FxRateRepository, none given

I am probably missing out some handy feature of the IoC container but would appreciate any advice on how achieve this?

Upvotes: 2

Views: 1004

Answers (1)

lukasgeiter
lukasgeiter

Reputation: 152950

Type-hinting the dependency in the constructor of DbClientRepository is correct, however you then can't just instantiate it by new DbClientRepository but have to resolve it from the IoC container with App::make() so Laravel can take care of DI:

$this->app->singleton('\repositories\ClientRepository', function()
{
    return new CacheClientRepository(App::make('repositories\DbClientRepository');
});

Instead of the Facade you can also just use the $app object:

$this->app->singleton('\repositories\ClientRepository', function($app)
{
    return new CacheClientRepository($app->make('repositories\DbClientRepository');
});

Upvotes: 2

Related Questions