Laravel 4一个接口,同时具有多个实现



问题是我不知道如何绑定一个接口的多个tple实现。

示例:

// One interface
interface SmsInterface {
...
}
// First implementation using SmsCoin
class SmscoinAPI implements SmsInterface {
...
}

// Second implementation using Fortumo
class FortumoAPI implements SmsInterface {
...
}

//两个控制器:

class SmsCoinController {
public function __construct(SmsInterface $sms) {
$this->sms = $sms
}
}
class FortumoController {
public function __construct(SmsInterface $sms) {
$this->sms = $sms
}
}
  1. 问题:如何将SmsInterface与FortumoController的实现FortumoApi绑定,以及如何将SmeInterface与SmsCoinController的实现SmsCoinApi绑定?

  2. 我使用ServiceProvider注册绑定,可以在那里注册吗?如果没有,绑定应该放在哪里?

编辑:

我在任何地方都找不到答案,读了很多laravel的书,到处都说要使用多个实现,但没有任何地方展示如何交换/切换这些实现。

如果我有一个接口和两个实现,如何在控制器中绑定和交换它们。我需要在控制器构造函数方法中这样做吗?或通过检查控制器的路线在路线中或在filters.php中?还是在服务提供商?以及如何在技术上正确地编写代码?

这个问题我花了很长时间才解决。在Laravel 5.0发布后,我发布了使用上下文绑定找到的解决方案

考虑这个例子,当一个控制器需要一个具有多个实现的接口时。

<?php
// We are creating one abstract controller with one logic
abstract class AbstractSearchController
{
protected $searchService;
public function __construct(SearchServiceInterface $searchService)
{
$this->searchService = $searchService;
}
public function getResult($keyword)
{
return $this->searchService->getItems($keyword);
}
}
// In routes.php file we can point url like: http://example.com/search/posts/?keyword=my-search-keyword to use 
// something like this: Route::resource('search/posts', 'PostSearchController', ['only' => ['index']]);
class PostSearchController extends AbstractSearchController
{
// No code here as this controller only is needed so that we can point Specific implementation to it
}
// In routes.php file we can point url like: http://example.com/search/members/?keyword=my-search-keyword to use 
// something like this: Route::resource('search/members', 'MemberSearchController', ['only' => ['index']]);
class MemberSearchController extends AbstractSearchController
{
//
}
// Our main interface that will have multiple implementations at same time
interface SearchServiceInterface
{
public function getItems($keyword);
}
// Our first implementation of interface
class MemberSearchRepo implements SearchServiceInterface
{
public function getItems($keyword)
{
// Get members by keyword
}
}
// Our second implementation of interface
class PostSearchRepo implements SearchServiceInterface
{
public function getItems($keyword)
{
// Get posts by keyword
}
}
// When PostsSearchController needs Search Logic point IoC to give our first implementation
$this->app->when('PostSearchController')->needs('SearchServiceInterface')->give('PostSearchRepo');
// When MemberSearchController needs Search Logic point IoC to give our seconds implementation
$this->app->when('MemberSearchController')->needs('SearchServiceInterface')->give('MemberSearchRepo');

我希望这个扩展的例子能帮助人们理解如何实现Laravel 4.x所需的功能,以及Laravel 5提供的功能

我一直在尝试做同样的事情,直到我在Laravel文档中找到它。它被称为上下文绑定,实现它的方式如下:

use IlluminateSupportFacadesStorage;
use AppHttpControllersPhotoController;
use AppHttpControllersVideoController;
use IlluminateContractsFilesystemFilesystem;
$this->app->when(PhotoController::class)
->needs(Filesystem::class)
->give(function () {
return Storage::disk('local');
});
$this->app->when(VideoController::class)
->needs(Filesystem::class)
->give(function () {
return Storage::disk('s3');
});

希望它能有所帮助!

虽然你的答案有效,但我在自己的项目中也遇到过同样的问题。我提出的解决方案是在执行到达控制器之前决定使用特定接口的哪个实现。

许多人使用global.php文件为具体类设置绑定。这很好,我试了很长时间,但你的应用程序越大,你开始进行的绑定就越多,当文件真的是包罗万象时,它就会有点长。我开始将所有绑定存储在start文件夹中的bindings.php文件中,并在global.php文件的末尾包含一个require_once

无论如何,在我的bindings.php文件中,我放置了所有的逻辑,以确定此服务器请求需要哪些具体实现。在我的例子中,我的具体类由用户请求的县决定,并通过POST或GET变量指定。

if(Input::has('state') && Input::has('county'))
{
$var_name = strtoupper(Input::get('state')).'.'.ucfirst(strtolower(Input::get('county')));
App::bind('SearchModelInterface', Config::get('counties.'.$var_name.'.searchClass'));
App::bind('InserterModelInterface', Config::get('counties.'.$var_name.'.inserterClass'));
Config::set('propertyClassName', Config::get('counties.'.$var_name.'.propertyClass'));
Config::set('chosenCounty', strtolower(Input::get('county')));
App::bind('Property', function($app)
{
$class = Config::get('propertyClassName');
return new $class();
});
}else{
App::bind('SearchModelInterface', 'Harris_TX_SearchModel');
App::bind('InserterModelInterface', 'Harris_TX_InserterModel');
App::bind('Property', function($app)
{
return new Harris_TX_Property();
});
Config::set('chosenCounty', 'harris');
}

正如您所看到的,有几个接口是根据配置文件设置的,具体取决于请求的县,如果没有,则提供默认值。同样有帮助的是,Laravel的所有facade在这里都是完全可用的,包括Config facade,它允许我设置将在整个请求执行过程中使用的值。

我从未见过Taylor、Jeffrey或社区中任何其他大牌推荐过这样的东西,但这对我来说真的很好。

通过将接口绑定到IOC中的类(从服务提供商内部),您正在"全局"执行此绑定,因此无法使用IOC自动注入不同的类。

您可以手动返回控制器的一个实例,其中包含从路由关闭中注入的正确类。

Route::get('sms', function()
{
return new SmsCoinController(new SmscoinAPI);
});
Route::get('fortumo', function()
{
return new FortumoController(new FortumoAPI);
});

要么这样,要么根本不在构造函数中使用接口提示。只要提示实际的类别,国际奥委会就会为您注入。

最新更新