2016-11-18 115 views
1

我使用存儲庫模式遇到了此問題。目前我使用一個接口和一個自定義類來實現它,然後鍵入提示到控制器的結構中,並且由於Laravel,它將自動並遞歸地解決存儲庫的依賴關係。在Laravel中通過依賴注入解決抽象類的依賴關係

我也爲此在服務提供商:

$this->app->bind(path/to/repoInterface,path/to/implementationClass) 

但是,由於我的方式編碼這些存儲庫,以避免重複代碼,我創建了一個有一個共同的方法把所有的抽象類這些知識庫。這個類如下:

abstract class CommonRepo{ 

    public function __construct(SomeModelClass model){} 

    public function commonMethod(){//Code here} 

我的資料庫具有以下結構:

public class ExampleRepository extends CommonRepo implements ExampleRepositoryI{ 

    public function __construct(){ 
    parent::__construct(); 
    } 
} 

Laravel不喜歡這一點,所以它給這個錯誤:

Argument 1 passed to path/to/repo/CommonRepo::__construct() must be an instance of path/to/model/SomeModelClass, none given, called in... 

所以,顯然不解決類CommonRepo的依賴性,但它確實解決了對正常存儲庫的依賴關係。

我想,如果有可能,而不必做相關操作

什麼我怎麼能,那麼,解決這一類的依賴使用類型提示(在Laravel方式)? PD:使用Laravel 5.2

+1

您可以從中得到啓發這個http://meanderingsoul.com/dev/2015/04/dependency-injection-with-inherited-controllers-in-laravel-5 –

+0

或者也許只是從ExampleRepository類中移除構造函數,除非調用父構造函數,否則沒有其他要做的事情。 –

+0

@MateuszDrost我沒有輸入,但還有更多的事情要做。每個存儲庫都有自己的依賴關係(通常只是雄辯模型,因爲我不喜歡濫用外觀)。 – user2430929

回答

2

父類的構造被稱爲像正常的功能,無需觸摸依賴解析器,所以你應該做的兩種可能性之一:

public class ExampleRepository extends CommonRepo implements ExampleRepositoryI 
{  
    public function __construct(SomeModelClass $model){ 
     parent::__construct($model); 
    } 
} 

public class ExampleRepository extends CommonRepo implements ExampleRepositoryI 
{  
    public function __construct(){ 
     parent::__construct(App::make(SomeModelClass::class)); 
    } 
} 
+0

感謝您的時間,但這正是我想避免的,因爲我必須編寫parent :: __構造(App :: make(SomeModelClass :: class));在每個存儲庫中(目前我有6個擴展該公共父級),所以如果我不得不在該ComonRepo中添加/刪除/修改依賴項,它會變得討厭。 – user2430929

2

有趣的問題。我做了一些修補,但我不知道這是你想要的。但是您可以動態創建存儲庫類所需的Eloquent模型實例。

比方說,你必須存儲在app\Models\User.phpUser模型類:

<?php 

namespace App\Models; 

use Illuminate\Database\Eloquent\Model; 

class User extends Model 
{ 
    // 
} 

然後,您創建一個抽象基類所有的倉庫類:app\Repositories\BaseRepository.php。這是您放置存儲庫類的所有常用功能的地方。但不是通過構造函數注入Eloquent實例,而是添加一個名爲getModel()的方法來動態創建存儲庫的Eloquent模型實例。

<?php 

namespace App\Repositories; 

use ReflectionClass; 
use RuntimeException; 
use Illuminate\Support\Str; 

abstract class BaseRepository 
{ 
    protected $modelNamespace = 'App\\Models\\'; 

    public function getById($id) 
    { 
     return $this->getModel()->find($id); 
    } 

    public function getModel() 
    { 
     $repositoryClassName = (new ReflectionClass($this))->getShortName(); 

     $modelRepositoryClassName = $this->modelNamespace . Str::replaceLast('Repository', '', $repositoryClassName); 

     if (! class_exists($modelRepositoryClassName)) { 
      throw new RuntimeException("Class {$modelRepositoryClassName} does not exists."); 
     } 

     return new $modelRepositoryClassName; 
    } 
} 

現在讓我們假設你想創建一個信息庫用於User模型,並且這個用戶的庫必須實現以下接口:app\Repositories\UserRepositoryInterface.php

<?php 

namespace App\Repositories; 

interface UserRepositoryInterface 
{ 
    public function getByEmail($email); 
} 

創建app\Repositories\UserRepository.php類,並簡單地從BaseRepository擴展它類。另外不要忘記實施在UserRepositoryInterface上定義的所有特定實現。

<?php 

namespace App\Repositories; 

use App\Repositories\BaseRepository; 
use App\Repositories\UserRepositoryInterface; 

class UserRepository extends BaseRepository implements UserRepositoryInterface 
{ 
    public function getByEmail($email) 
    { 
     return $this->getModel()->where('email', $email)->firstOrFail(); 
    } 
} 

這樣你就可以綁定UserRepositoryInterface它是像這樣實現:

$this->app->bind(\App\Repositories\UserRepositoryInterface::class, \App\Repositories\UserRepository::class); 

最後,你可以自由地注入UserRepositoryInterface到控制器的構造函數或方法。您還可以通過服務容器解決這樣的:

$userRepository = App::make(App\Repositories\UserRepositoryInterface::class); 

$userRepository->getByEmail('[email protected]'); 

當然,這裏有一個問題,以這種方式。存儲庫類應以相關模型啓動,因此InvoiceRepository.php專用於Invoice.php模型類。

希望得到這個幫助!

+0

嘿,謝謝你的迴應。儘管這不是我想要的,但我可以在將來明確地找到它的用處,因爲我經常發現自己注入了模型,有時它與回購的名稱相匹配,所以很好。 不應該緩存getModel()方法嗎?像在構造函數中調用它? – user2430929

0

這可能有幫助。您可以在對象解析和設置屬性時監聽。

$this->app->resolving(CommonRepo::class, function ($object, $app) { 
    // Called when container resolves object of any type... 
    $object->commonObject = app(CommonObject::class); 
}); 

文檔:https://laravel.com/docs/5.4/container#container-events