Laravel 4 One interface with multiple implementations at same time Laravel 4 One interface with multiple implementations at same time laravel laravel

Laravel 4 One interface with multiple implementations at same time


This question took for me long time to solve it. After Laravel 5.0 is out i'm posting solution that i have found using Contextual binding

Consider this example, when one controller needs one interface with multiple implementations.

<?php// We are creating one abstract controller with one logicabstract 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 timeinterface SearchServiceInterface{    public function getItems($keyword);}// Our first implementation of interfaceclass MemberSearchRepo implements SearchServiceInterface{    public function getItems($keyword)    {        // Get members by keyword    }}// Our second implementation of interfaceclass 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');

I hope this extended example will help people to understand how to implement feature that I needed for Laravel 4.x with abillities that Laravel 5 provides


I've been trying to do the same, until I found it in the Laravel docs. It's called Contextual Binding, and the way in which you have to implement it is like this:

use Illuminate\Support\Facades\Storage;use App\Http\Controllers\PhotoController;use App\Http\Controllers\VideoController;use Illuminate\Contracts\Filesystem\Filesystem;$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');          });

Hope it helps!


Though your answer works, I've run into the same issue in my own projects. The solution I came up with was to decide which implementation of a specific interface to use before execution even reaches the controller.

Many people use the global.php file to set up their bindings for concrete classes. That's fine, and I tried that for a long time, but the larger your app gets, the more bindings you'll start making, and it gets to be a little long for the file when it's really meant to be a catch all. I started storing all my bindings in a bindings.php file, in the start folder and included a require_once at the end of the global.php file.

Anyway, in my bindings.php file I place all my logic to determine which concrete implementations are required for this server request. In my case, my concrete classes are determined by the county the user requests and are specified via either POST or GET variables.

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');}

As you can see, there's several interfaces that are set according to config files depending on which county is requested, and defaults provided if none are. It's also helpful to see that all of Laravel's facades are fully available here including the Config facade, which allows me to set values that will be used throughout the request execution.

I've never seen anything like this recommended by Taylor, Jeffrey, or any of the other big names in the community, but this works really well for me.