2014-09-02 53 views
4

命名空間略去了......Laravel IOC自動解析 - 從控制器工作而不是從自定義類

我寫了下面的服務提供商,註冊在配置/ app.php:

class OfferServiceProvider extends ServiceProvider 
{ 
    public function register() 
    { 
     $this->registerLossControlManager(); 
    } 

    protected function registerLossControlManager() 
    { 
     $this->app->bind('LossControlInterface', 'LossControl'); 
    } 
} 

這裏是我的LossControlInterface

interface LossControlInterface 
{ 
    /** 
    * @param int $demandId 
    * @param float $offerTotal 
    * @param float $productTotal 
    * @param null|int $partnerId 
    * @return mixed 
    */ 
    public function make($demandId, $offerTotal, $productTotal, $partnerId = null); 

    /** 
    * @return float 
    */ 
    public function getAcceptableLoss(); 

    /** 
    * @return bool 
    */ 
    public function isAcceptable(); 

    /** 
    * @return bool 
    */ 
    public function isUnacceptable(); 

    /** 
    * @return null 
    */ 
    public function reject(); 
} 

現在控制器內,我可以注入LossController如下:

use LossControlInterface as LossControl; 

class HomeController extends BaseController { 
    public function __construct(LossControl $lossControl) 
    { 
     $this->lossControl = $lossControl; 
    } 

    public function getLossThresholds() 
    { 
     $lossControl = $this->lossControl->make(985, 1000, null); 

     var_dump('Acceptable Loss: ' . $lossControl->getAcceptableLoss()); 
     var_dump('Actual Loss: ' . $lossControl->calculateLoss()); 
     var_dump('Acceptable? ' . $lossControl->isAcceptable()); 

    } 
} 

但是,如果我嘗試的依賴性和由命令調用自定義類中注入LossControlInterface:

[2014-09-02 13:09:52] development.ERROR: exception 'ErrorException' with message 'Argument 11 passed to Offer::__construct() must be an instance of LossControlInterface, none given, called in /home/vagrant/Code/.../ProcessOffer.php on line 44 and defined' in /home/vagrant/Code/.../Offer.php:79 

看來好像我不能依賴注入其接口爲自定義類,但我可以在依賴注入控制器時。

任何想什麼我做錯了或省略了自動解析工作?

+0

你可以發佈創建自定義類的代碼嗎?它是否也是從服務提供商內部或您的工匠命令中創建的? – 2014-09-02 13:06:38

+0

它是從工匠指令中創建的。命令/ ProcessOffer.php:'private function setOffer(Offer $ offer = null){$ this-> processOffer = $ offer?:new Offer();}' – Gravy 2014-09-02 13:09:22

回答

9

IoC在控制器中是自動的,並且您看不到注射,因爲Laravel爲您處理控制器的構造。當創建使用new關鍵字的任何其他自定義類,你仍然需要在所有需要它的構造函數的參數發送:

$myClass = new ClassWithDependency(app()->make('Dependency')); 

可以隱藏這一點,在一定程度上,通過漏斗您的自定義創建

// Your service provider 
public function register() 
{ 
    $this->app->bind('ClassWithDependency', function($app) { 
     return new ClassWithDependency($app->make('Dependency')); 
    }); 
} 

然後纔有的IoC使它只要你需要它:通過服務供應商類

$myClass = app()->make('ClassWithDepenency'); 

在你的情況,你可以改變你代碼如下所示:

private function setOffer(Offer $offer = null) { 
    $this->processOffer = $offer ?: 
     new Offer(app()->make('LossControlInterface')); 
} 

一個或許更簡潔的方法可能是創建一個服務提供者和OfferFactory其被注入到你的控制器。然後,控制器可以要求工廠創建要約時,它需要一個:

// Controller 
public function __construct(OfferFactory $offerFactory) 
{ 
    $this->offerFactory = $offerFactory; 
} 

public function setOffer(Offer $offer = null) 
{ 
    $this->processOffer = $offer ?: $this->offerFactory->createOffer(); 
} 

// OfferFactory 
class OfferFactory 
{ 
    public function createOffer() 
    { 
     return app()->make('Offer'); 
    } 
} 

這有從創建報價背後的邏輯完全解耦控制器,同時可以讓你有一個點的好處爲創建優惠的過程添加任何必要的複雜性。

1

在Laravel 5.2爲您的特定問題的最簡單的解決辦法是用

App::make('Offer'); 

,甚至更短的更換

new Offer(); 

app('Offer'); 

將使用Laravel集裝箱取關心依賴。

然而,如果你想傳遞額外的參數給Offer構造,有必要將其綁定在你的服務提供商

App::bind('Offer', function($app, $args) { 
    return new Offer($app->make('LossControl'), $args); 
}); 

瞧,現在你可以寫

app('Offer', [123, 456]);