Sma*_*der 10 architecture interface laravel laravel-5
我正在使用Laravel 5构建RESTful API.
试图让Http控制器保持尽可能小,所以我使用服务层(和存储库)来处理大部分逻辑.
由于大部分的控制器也有类似的方法(例如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);
}
}
Run Code Online (Sandbox Code Playgroud)
因为所有控制器共享相同的特征,所以它们都可以依赖于单个接口.
例如:
<?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);
}
Run Code Online (Sandbox Code Playgroud)
但是,这会导致自动依赖注入的一些问题.
1)我必须使用上下文感知绑定:
$this->app->when("API\Http\Controllers\ThingController")
->needs("API\Services\Interfaces\UpdateServiceInterface")
->give("API\Services\Things\ThingUpdateServiceInterface")
Run Code Online (Sandbox Code Playgroud)
这本身并不成问题 - 虽然它确实会导致一些相当大的服务提供商代码,但这并不理想.但是,这意味着我似乎无法使用方法注入,因为在使用上下文感知绑定时,自动依赖项解析似乎不适用于控制器方法:我只是回复一条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;
}
}
Run Code Online (Sandbox Code Playgroud)
这不好 - 很难测试,所有这些依赖项必须实例化,即使只使用其中一个.
但我想不出一个更好的方法.
我可以使用更具体的接口,例如ThingUpdateServiceInterface,(然后我不需要上下文绑定并且可以直接注入到特征中),但是我会有很多只在名称上不同的接口.这看起来很愚蠢.
我想到的另一个选择是使用大量较小的控制器,所以a Things\UpdateController和a Things\ShowController- 至少这种方式不必要的依赖关系不会每次都被实例化.
或者也许试图抽象使用特征是错误的做事方式.特征有时看起来像是一种反模式.
任何意见,将不胜感激.
您的代码看起来很棒并且经过深思熟虑的概括。
我想建议使用此选项来使用工厂来创建服务,而不是预定义所有依赖项注入。
interface UpdateServiceInterface {
public function action($itemID);
//....
}
class ThingUpdateServiceInterface implements UpdateServiceInterface {
public function action($itemID)
{
// TODO: Implement exists() method.
}
}
class ApiServiceFactory {
protected $app;
public function __construct(Application $app) {
$this->app = $app;
}
public function getUpdateService($type) {
if ($type == 'things')
return $this->app->make('ThingUpdateServiceInterface');
}
public function getCreateService($type) {
if ($type == 'things') {
//same idea here and for the rest
}
}
}
class ApiController {
protected $factory;
protected $model;
public function __construct(ApiServiceFactory $factory) {
$this->factory = $factory;
}
public function update($data) {
$updater = $this->factory->getUpdateService($this->model);
$updater->action($data);
}
}
class ThingsController extends ApiController {
protected $model = 'App\Thing';
}
Run Code Online (Sandbox Code Playgroud)
这一切的想法是什么:
您可以为该操作创建一般操作,例如
DeleteServiceInterface
Run Code Online (Sandbox Code Playgroud)将由
class GeneralDeleteService implements DeleteServiceInterface {
public function delete($id){......}
}
Run Code Online (Sandbox Code Playgroud)
在工厂中,当您请求该删除服务时,如果没有传递名称,那么您将返回默认服务
希望这篇文章不会是“TLDR”
| 归档时间: |
|
| 查看次数: |
442 次 |
| 最近记录: |