2017-10-29 320 views
2

Laravel鼓勵依賴注入。由於我在我的項目中使用laravel,我想我會嘗試使用這種方法。構造函數注入vs方法注入

我正在利用Laravel的服務容器type hinting my dependencies and letting it resolve them。我有四個控制器。所有這些擴展名爲GlobalController的基類。我也有兩個模型。所有這些擴展名爲GlobalModel的基類。

我的第一次嘗試是(有點)使用方法注入。 GlobalController如下所示:

namespace App\Http\Controllers; 

use Illuminate\Http\Request;; 
use App\Models\GlobalModel; 

class GlobalController extends Controller 
{ 

    public function __construct() 
    { 
     $this->middleware(['authenticate', 'token']); 
    } 

    // functions that handle normal http requests and ajax requests 

    } 

從GlobalController擴展的控制器之一稱爲UserController。它的一些功能是:

  • 指標 - 顯示所有數據
  • 編輯 - 顯示編輯表單
  • 更新 - 更新數據庫

編輯和更新使用route-model-binding

namespace App\Http\Controllers; 

use Illuminate\Http\Request;; 
use App\Models\User; 

class UserController extends GlobalController 
{ 

    public function index(User $user) 
    { 
     $users = $user->all(); 
     return view('pages/view_users')->with('users', $users); 
    } 

    public function edit(User $user) 
    { 
     return view('pages/edit_user')->with('user', $user); 
    } 

    public function update(Request $request, User $user) 
    { 
     $data = $request->all(); 
     if ($user->validate($data)) 
     { 
      $user->update($data); 
      return $this->successResponse($request, 'users', 'Successfully edited user'); 
     } 
     return $this->failedResponse($request, $user); 
    } 

    // other functions 

    } 

雖然這工作正常,請求和用戶注入很多次。如果必須更改Request實現(例如),我將不得不手動更改許多函數來鍵入提示該特定的Request對象。一點都不好。由於它們通常在大多數函數中調用,所以我嘗試了構造函數注入。

下面是GlobalController使用構造器注入:

namespace App\Http\Controllers; 

use Illuminate\Http\Request;;; 
use App\Models\GlobalModel; 

class GlobalController extends Controller 
{ 
    protected $request; 
    protected $model; // use polymorphism 

    public function __construct(Request $request, GlobalModel $model) 
    { 
     $this->request = $request; 
     $this->model = $model; 
     $this->middleware(['authenticate', 'token']); 
    } 

    // functions that handle normal http requests and ajax requests 

} 

,這裏是UserController中使用含有相同功能的構造器注入:

namespace App\Http\Controllers; 

use Illuminate\Http\Request;; 
use App\Models\User; 

class UserController extends GlobalController 
{ 

    public function __construct(Request $request, User $user) // use polymorphism 
    { 
     parent::__construct($request, $user); 
    } 

    public function index() 
    { 
     $users = $this->model->all(); 
     return view('pages/view_users')->with('users', $users); 
    } 

    public function edit(int $id) 
    { 
     $this->model = $this->model->find($id); 
     return view('pages/edit_user')->with('user', $this->model); 
    } 

    public function update(int $id) 
    { 
     $this->model = $this->model->find($id); 
     $data = $this->request->all(); 
     if ($this->model->validate($data)) 
     { 
      $this->model->update($data); 
      return $this->successResponse('users', 'Successfully edited user'); 
     } 
     return $this->failedResponse(); 
    } 

    // other functions 

} 

現在,我不能把我的手指上,但我認爲這個實現看起來不正確。它變得不太可讀。 $ model和$ this的使用使代碼更加噁心。

我很困惑。我明白我可以從依賴注入中獲得好處,但我確定我的方法注入和構造函數注入的實現是非常錯誤的。我應該選擇什麼樣的實施?或者我應該從這兩個中選擇一個呢?

回答

1

我絕對更喜歡Laravel控制器的第一種方法。起初,你不需要在每種方法中注入模型。 (爲什麼要在索引函數中注入一個用戶模型?)。

其次,您不能再使用RouteModelBinding的好處,而必須手動檢查具有給定$ id的模型是否真的存在並採取相應措施。你也不能使用像CreateUserRequest這樣可以處理驗證和授權的特定FormRequests。(雖然這是一個可選功能)

另請注意,在構造函數中注入的模型從不是包含用戶數據的「真實」模型。因此,這隻會讓您訪問eleoquent功能。所以你可以在你的代碼中使用User :: find($ id)。這總會讓你失望。

public function __construct(User $user) 
{ 
    dd($user->exists); 
} 

如果你想抽象的東西,你可以在你的構造函數注入庫。

public function __construct(UserRepository $userRepository) 
{ 
    $this->userRepository = $userRepository; 
    // then the Repository is responsible for retrieving users 
    // and you are not coupled to Eloquent. If you later want, you can Read 
    // users from an XML File if you need 
} 

附加信息(有點offtopic):雖然這是非常罕見的,我從來沒有需要通過創建一個自定義的請求類這樣的改變要求類,你可以這樣做:

namespace App; 


use Illuminate\Http\Request; 

class MyRequest extends Request 
{ 
    // override request methods or add your new own methods 
} 

然後在全局index.php中:

$response = $kernel->handle(
    // instead of Illuminate\Http\Request::capture() 
    $request = \App\MyRequest::capture() 
); 
+0

「爲什麼要在索引函數中注入用戶模型?」)。「 - 索引函數獲取所有數據到視圖。我需要$ user來做$ user-> all()。這不好嗎? – morbidCode

+0

或只需調用User :: all()。如果您想要獲取所有用戶,則不需要特定的用戶實例。或者如果您覺得這對您更好,請使用UserRepository。 –

+0

啊,你是對的。我可以使用外牆!但是,門面不做同樣的事情?你的意思是說,在全部調用時,Facade不會創建新的User實例嗎?我想我只是想盡量避免立面。 – morbidCode

1

如果在大多數方法中使用模型,請使用構造函數注入。 而且$ model和$ this的用法沒有任何問題。但是,如果您仍想清除代碼,請考慮存儲庫模式(SRP)。您可以管理那裏的長長的代碼。 看到這個stackoverflow answer - How can I organise classes in a Laravel 5 Project?。我希望這會幫助你的困惑。