我建立使用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控制台) –