让我们假设我有一个这样的界面:
interface RepositoryInterface{
public function getById($id);
}
此接口由X个类实现。
举个例子:
class SqliteRepository implements RepositoryInterface{
public function getById($id)
{
return $id;
}
}
我在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')),
],
],
connections
本身可以是任何东西。数据库,API,甚至是csv文件。
这背后的主要思想是我可以通过更改配置来切换存储介质。不要问我为什么我没有使用默认的laravel database
文件,这是一个很长的故事。
问题:
我希望能够基于该配置文件将RepositoryInterface
的不同实现注入到控制器中,类似于以下内容:
if(Config::get('default') == 'sqlite')
{
// return new SqliteRepository
}
显然,这里的方式是服务提供商。但是,我不确定如何处理这个问题。 我的意思是我可以按照以下方式做点什么:
class RepositoryServiceProvider extends ServiceProvider
{
public function register()
{
if(Config::get('storage') == 'sqlite')
{
$this->app->singleton(SqliteRepository::class, function ($app) {
return new SqliteRepository(config('SqliteRepository'));
});
}
}
}
但感觉有点不对,更何况它给了我零错误控制。我不想在ServiceProvider中抛出错误。我需要某种上下文绑定或类似的东西。我已经阅读了the documentation regarding contextual binding但它并不是我正在寻找的内容,因为它指的是基于控制器使用它们的类的具体实现。
我更多地考虑了一种抽象的工厂类型的交易,但是,我再也不确定如何适应laravel的做事方式。
任何指向正确方向的人都会受到赞赏。
答案 0 :(得分:1)
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());
}
}
在您的应用提供商处;
public function register()
{
$this->app->bind( RepositoryInterface::class, env('REPOSITORY', 'MonkeyPooRepository' ) );
}
索引方法将返回(int)3