简体   繁体   English

通过Laravel 5中的config进行接口的上下文绑定

[英]Contextual binding of interface via config in laravel 5

Lets assume I have an interface like so: 假设我有一个像这样的接口:

interface RepositoryInterface{
    public function getById($id);
}

This interface gets implemented by X amount of classes. 该接口由X个类实现。

As an example: 举个例子:

class SqliteRepository implements RepositoryInterface{
    public function getById($id)
    {
        return $id;
    }
}

I also have a config file in the config folder(do note, this is not the database.php file, it's whole different file): 我在config文件夹中也有一个配置文件(请注意,这不是database.php文件,它是完全不同的文件):

'default'  => 'sqlite',

'connections' => [
    'sqlite' => [
        'database' => env('DB_DATABASE', storage_path('database.sqlite')),
    ],

    'some_other_db' => [
        'database' => env('DB_DATABASE', storage_path('some_other_db')),
    ],
],

The connections itself can be anything. connections本身可以是任何东西。 A database, an API, heck even a csv file. 数据库,API甚至会破坏一个csv文件。

The main idea behind this is that I can switch in between storage mediums simply by changing the config. 其背后的主要思想是,我只需更改配置即可在存储介质之间切换。 Don't ask me why I'm not using the default laravel database file, it's a long story. 不要问我为什么我不使用默认的laravel database文件,这是一个很长的故事。


The problem: 问题:

I want to be able to inject different implementations of the RepositoryInterface into controllers based on that config file, something along the lines of this: 我希望能够基于该配置文件将RepositoryInterface不同实现注入到控制器中,类似以下内容:

if(Config::get('default') == 'sqlite')
{
    // return new SqliteRepository
}

Obviously the way to go here would be Service Providers. 显然,服务提供商将是您的理想之选。 However I'm not exactly sure how to approach this issue. 但是我不确定如何解决这个问题。 I mean I could do something along the lines of this: 我的意思是我可以按照以下方式做点事情:

class RepositoryServiceProvider extends ServiceProvider
{
    public function register()
    {
        if(Config::get('storage') == 'sqlite')
        {
            $this->app->singleton(SqliteRepository::class, function ($app) {
                return new SqliteRepository(config('SqliteRepository'));
            });
        }

    }
}

But it feels a little wrong, not to mention that it gives me zero error control. 但是感觉有点不对,更不用说它给了我零错误控制。 I don't want to be throwing errors in the ServiceProvider. 我不想在ServiceProvider中抛出错误。 I need some sort of contextual binding or something along those lines. 我需要某种上下文绑定或类似的方式。 I have read the the documentation regarding contextual binding but it's no exactly what I'm looking for, as it refers rather to concrete implementations of classes based on what controller uses them. 我已经阅读了有关上下文绑定的文档,但这并不是我想要的,因为它指的是基于控制器使用它们的类的具体实现。

I was thinking more of an abstract factory type of deal, but, again, I'm not sure how to fit into laravel's way of doing things. 我更多地考虑的是抽象的工厂交易类型,但是同样,我不确定如何适应laravel的做事方式。

Any pointing in the right direction is appreciated. 任何指向正确方向的指示都值得赞赏。

interface RepositoryInterface{
    public function getById();
}

...
...

class SqliteRepository implements RepositoryInterface{
    public function getById()
    {
        return 1;
    }
}

...
...

class CsvRepository implements RepositoryInterface{
    public function getById()
    {
        return 2;
    }
}

...
...

class MonkeyPooRepository implements RepositoryInterface{
    public function getById()
    {
        return 3;
    }
}

...
...

use RepositoryInterface;
class Controller {

    public function __construct( RepositoryInterface $repo ) {
        $this->repo = $repo;
    }

    public function index()
    {
        dd($this->repo->getById());
    }

}

on your app provider; 在您的应用程序提供商上;

public function register()
{
    $this->app->bind( RepositoryInterface::class, env('REPOSITORY', 'MonkeyPooRepository' ) );
}

index method would return (int)3 索引方法将返回(int)3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM