我建立使用Laravel 5.Laravel 5.0應用程序結構
試圖到HTTP控制器保持到被儘可能最小的一個RESTful API,所以我使用一個服務層(和存儲庫)來處理最的邏輯。由於大多數控制器都有類似的方法(例如show
,index
,update
)我寫了一些處理每一個的特徵。由於這些直接與服務對話,我可以爲每個控制器重複使用這些服務。
例如:
<?php namespace API\Http\Controllers\Restful;
trait UpdateTrait
{
protected $updater;
public function update($itemID)
{
if (!$this->updater->authorize($itemID)) {
return response(null, 401);
}
if (!$this->updater->exists($itemID)) {
return response(null, 404);
}
$data = $this->request->all();
$validator = $this->updater->validator($data);
if ($validator->fails()) {
return response($validator->messages(), 422);
}
$this->updater->update($itemID, $data);
return response(null, 204);
}
}
因爲所有的控制器共享它們都可以依賴單一接口上相同的特徵。
例如:
<?php namespace API\Services\Interfaces;
interface UpdaterServiceInterface
{
public function validator(array $data);
public function exists($itemID);
public function update($itemID, array $data);
public function authorize($itemID);
}
然而,這會導致自動依賴注入的幾個問題。
1)我必須使用情境感知結合:
$this->app->when("API\Http\Controllers\ThingController")
->needs("API\Services\Interfaces\UpdateServiceInterface")
->give("API\Services\Things\ThingUpdateServiceInterface")
這不是本身有問題 - 雖然它確實會導致一些相當大的服務提供商的代碼,這是不理想的。但是,這意味着我似乎無法使用方法注入,因爲在使用上下文感知綁定時,自動依賴關係解析似乎不適用於控制器方法。:我剛收到could not instantiate API\Services\Interfaces\UpdateServiceInterface
消息。
這意味着控制器構造函數來處理所有的依賴注入,它得到相當混亂的:
class ThingsController extends Controller
{
use Restful\IndexTrait,
Restful\ShowTrait,
Restful\UpdateTrait,
Restful\PatchTrait,
Restful\StoreTrait,
Restful\DestroyTrait;
public function __construct(
Interfaces\CollectionServiceInterface $collection,
Interfaces\ItemServiceInterface $item,
Interfaces\CreatorServiceInterface $creator,
Interfaces\UpdaterServiceInterface $updater,
Interfaces\PatcherServiceInterface $patcher,
Interfaces\DestroyerServiceInterface $destroyer
) {
$this->collection = $collection;
$this->item = $item;
$this->creator = $creator;
$this->updater = $updater;
$this->patcher = $patcher;
$this->destroyer = $destroyer;
}
}
這是不好的 - 這是很難測試,所有這些依賴必須實例化,即使只有其中一個正在使用。
但我想不出一個更好的方法。
我可以使用更具體的接口,例如ThingUpdateServiceInterface
(然後我不需要上下文綁定,並可以直接注入特徵),但是後來我有很多接口只是名稱不同。這似乎很愚蠢。
我想到的另一種選擇是使用很多較小的控制器,所以Things\UpdateController
和Things\ShowController
- 至少這種方式不必要的依賴不會每次都被實例化。
或者試圖抽象出使用特質是做錯事情的錯誤方法。性狀有時看起來像是可能是反模式。
任何意見,將不勝感激。
感謝您的詳細問題。如何使用UpdateTrait中的代碼創建'UpdateService'並在你的RESTful更新方法中提示它,比如'public function update($ itemID,UpdateService)'我沒有測試過這個麪糰,但我認爲它可能不會。您可能在測試中遇到問題,如果您繼續使用目前的功能 – Digitlimit
在L5中,您可以執行稱爲方法注入的操作,請參閱[此處](https://mattstauffer.co/blog/laravel-5.0-method-injection)更重要的是,我會創建授權中間件+「存在」中間件,並儘可能使用請求類。特徵是很好的抽象代碼,但後來你會遇到問題,我認爲只是因爲到目前爲止,應用程序「不復雜」,時間流逝,應用程序變得越來越複雜,所以你將需要「獨特」更新,修補程序也許驅逐艦(可以說你做了一些M:N的關係)。怎麼樣創建RestfullController?並做一些延伸? – Kyslik
- 當您使用上下文綁定時,方法注入不起作用,或者至少我無法獲得它。 - 我不想創建一個單獨的RestfulController並進行擴展,因爲其中很多不會使用大多數方法(例如,某些只有'index'和'show')。 - 我已經在使用auth中間件,但仍然有意義在服務中使用它,我認爲(例如,如果使用服務而不是HTTP控制檯) –