user777 user777 - 5 months ago 23
PHP Question

Laravel 4 One interface with multiple implementations at same time

Problem is that i don't know how to bind multitple implementations of one interface.

Example:

// One interface
interface SmsInterface {
...
}

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


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


// Two controllers:

class SmsCoinController {
public function __construct(SmsInterface $sms) {
$this->sms = $sms
}
}

class FortumoController {
public function __construct(SmsInterface $sms) {
$this->sms = $sms
}
}



  1. Question: How I can bind SmsInterface with implementation FortumoApi for FortumoController, and bind SmsInterface with implementation SmsCoinApi for SmsCoinController ?

  2. I was using ServiceProvider for registering bindings, can I do it there ? If not where should bindings put?



EDIT:

I can't get answer anywhere, read many laravel books, everywhere is said to use multiple implementations, but nowhere is shown how to swap/switch those implementations.

If i have one interface and two implementations, how to bind and swap them in controller. Do i need to do that in that controller constructor method ? or in routes by checking controller's route or in filters.php ? or in Service provider ? and how to technically correclty write that code ?

Answer

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

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

Comments