我有两个对象,User
和Item
(现在可能会更晚),我可以使用以下网址模式附加文件:
/users/:user_id/attachments/:id
/items/:item_id/attachments/:id
为了保持DRY,我想只使用一个独特的控制器(AttachmentsController
)来处理每一个案例。
使用唯一控制器,嵌套资源可以是User
或Item
(或我想要附加到其上的任何其他对象)。有没有办法,使用Route
或Request
从这个控制器动态检索这些资源(用户,项目......等......)?
理想环境
对我来说理想的用例是能够检索诸如/users/:user_id/attachments/:id
之类的url模式,这样我就可以动态查找要使用的对象(参见下面的Rails解决方案)。当然,如果存在更好的解决方法,我就在。
我还在考虑做一些像动态检索对象的mixin:
trait ResourceFinder
{
public function behaveableFrom(Request $request, $id)
{
$patternWords = explode('/', $request->path());
$classname = ucfirst(str_singular($words[0]));
return $classname::findOrFail($id);
}
}
等效Rails解决方案
有关信息,我使用以下代码段在Ruby on Rails上完全相同:
module Behaveable
module ResourceFinder
def behaveable
klass, param = behaveable_class
klass.find(params[param.to_sym]) if klass
end
end
def behaveable_class
params.each do |name, _value|
if name =~ /(.+)_id$/
model = name.match(%r{([^\/.]*)_id$})
return model[1].classify.constantize, name
end
end
nil
end
end
建议?
答案 0 :(得分:0)
您可以使用路线资源控制器。
Route::resource('user.attachments', 'AttachmentsController');
http://laravel.com/docs/5.1/controllers#restful-nested-resources
但是你想要使用一个控制器,所以你有这样的选择:
1)为restful controller中的每个方法创建一些检查器,以检查它是Item
还是User
2)使用所需方法创建一些AttachmentsBaseController,然后创建
另外2个控制器User \ ItemController将扩展基础控制器。通过这种方式,您可以定义基本工作流,如果某些内容发生变化取决于User \ Item,您可以在相关控制器中重新定义所需的方法。
答案 1 :(得分:0)
我终于使用mixin找到了一个非常干净的解决方案,正如我在原帖上所述。
<强> routes.php文件强>
foreach (['users', 'menus'] as $resource) {
Route::resource("$resource.attachments", 'AttachmentsController', ['except' => ['create', 'edit']]);
}
应用\ HTTP \控制器\性状\ BehaveableFinder.php 强>
<?php
namespace App\Http\Controllers\Traits;
use Illuminate\Http\Request;
trait BehaveableFinder
{
/**
* Get the behaveable object.
*
* @param Request $request
* @param int $id
* @return \Illuminate\Database\Eloquent\Model
*/
public function behaveableFrom(Request $request, $behaveableId)
{
$context = explode('/', $request->path())[0];
$class = 'App\\Models\\' . ucfirst(str_singular($context));
return $class::findOrFail($behaveableId);
}
}
应用\ HTTP \控制器\ AttachmentsController.php 强>
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Http\Controllers\Traits\BehaveableFinder;
class AttachmentsController extends Controller
{
use BehaveableFinder;
/**
* Get attachable's medias.
*
* GET http://domain.com/:attachable/:attachableId/attachments
*
* @param Request $request
* @param int $attachableId
* @return Response
*/
public function index(Request $request, $attachableId)
{
$attachable = $this->behaveableFrom($request, $attachableId);
return response()->json($attachable->medias, 200);
}
// ...rest of crud methods works the same way
}
这里的优点是,此mixin
可用于任何其他多态上下文,例如注释(可注释对象)。这种方法的局限性在于它只能在深度为2的嵌套级别上工作。但是,在REST设计中避免过多的嵌套级别通常是一种很好的做法。
我认为总有改进的余地,如果您有任何改进方案,我很乐意看到其他方法,欢迎提出建议。