首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何为休息关系组织控制器?[拉威尔航线]

如何为休息关系组织控制器?[拉威尔航线]
EN

Stack Overflow用户
提问于 2017-03-04 11:39:48
回答 3查看 1.4K关注 0票数 0

想象一下实体GenreBook

每个都有API资源端点/genre/book。在Laravel路线上,这可能是:

代码语言:javascript
复制
 $app->resource('/genre', GenreController::class);

我想要这段关系的终结点。GET /genre/1/book,把书放在Genre #1下面。

这里的最佳实践是什么?将处理程序放置在GenreControllerBookController或一个全新的控制器中?

在sidenote上,我使用的是dingo-api包,但我不认为这有什么不同。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-03-09 09:37:54

因此,克里斯建议为这种关系设立一个专用控制器,@RossWilson有一种天才的方法,可以重用关系控制器(至少用于加载Book的操作)。

不幸的是,Lumen的RouteProvider返回一个简单的数组,因此不具备$request->route($param)和更重要的是$request->route()->forgetParameter($param)的方便性。

===新解决方案===

最后,我做的基本上和RossWilson建议的完全一样,就像Lumen所支持的那样。我没有在Controller的__construct中获取路由参数,而是制作了一个中间件,将路由参数移动到请求的输入和查询数组中。

中间件看起来如下所示:

代码语言:javascript
复制
public function handle($request, $next)
{
    if ($genre_id = Arr::get($request->route()[2], 'genre')) {
        // Add 'genre_id' to the input array (not replacing it if it already exists).
        $request->merge(['genre_id' => $request->input('genre_id', $genre_id)]);
        // Add 'genre_id' to the query array.
        $request->query->add('genre_id', $genre_id);

        // Forget the route parameter
        // Has to be done manually, because Lumen...
        $route = $request->route();
        $request->setRouteProvider(function() use ($route) {
            Arr::forget($route[2], 'genre');
            return $route;
        });
    }

    // Pass the updated $request to $next.
    return $next($request);
}

在我的实现中,我只设置了GETDELETE请求的查询参数,以及POSTPUT的输入参数。

然后,您可以对BookController资源重用genre.book资源,从$request->query('genre_id')进行过滤,并将关系从$request->input('genre_id')关联起来。

===原始解===

相反,我最终得到了一个专用关系控制器GenreBookController,该控制器继承自非关系控制器BookController。由于需要匹配的方法声明(请参见下面的$book_id = null如何解决此问题),它并不像可能的那样优雅,但它非常苗条和枯燥。

GenreBookController extends BookController

代码语言:javascript
复制
protected function addGlobalScope($genre_id)
{
    // Thanks Ross Wilson for the global scope suggestion.
    Book::addGlobalScope('genreScope', function ($query) use ($genre_id) {
        $query->where('genre_id', $genre_id);
    });
}

public function show(Request $request, $genre_id, $book_id = null)
{
    $this->addGlobalScope($genre_id);
    return parent::show($request, $book_id);
}

对于BookController,show方法和往常一样(它不需要知道show上的额外参数)。

我还想出了一种简单的方法,让GenreBookController可以将类型参数传递给store方法:

代码语言:javascript
复制
public function store(Request $request, $genre_id)
{
    // This way lets an input genre_id override the Route parameter.
    $request->merge(['genre_id' => $request->input('genre_id', $genre_id)]);

    // This way forces the Route parameter to be used over input parameters.
    $request->merge(['genre_id' => $genre_id]);

    return parent::store($request);
}

同样,对于BookController来说,它是一切照旧的,当然,它可能会对通过$request->input('genre_id')传递的类型进行任何验证/授权。这样就没有重复的验证和授权逻辑。

--关于FormRequests的一点注记

如果使用FormRequests验证genre_id,则在GenreBookController可以从路由参数设置genre_id输入变量之前进行验证。

在我看来,你有两个选择:

  1. 使用中间件将路由参数移动到请求输入。
  2. 把它放在FormRequestFormRequest方法上(我还没有测试这个,因为我不喜欢把这样的逻辑放在这里)。

Laravel:,如果你不使用Lumen,我建议看一下@RossWilson的答案,在我看来,它有点干净。

票数 0
EN

Stack Overflow用户

发布于 2017-03-04 13:45:06

一种选择是只使用当前的BooksController。将下面的内容添加到BooksController

代码语言:javascript
复制
public function __construct(Request $request)
{
    if ($genreId = $request->route('genre')) {

        $request->route()->forgetParameter('genre');

        Book::addGlobalScope('genreScope', function ($query) use ($genreId) {
            $query->whereGenreId($genreId);
        });
    }
}

这将允许您的书籍成为Genre的作用域,并将其作为路由param删除。

那你的路线就是:

代码语言:javascript
复制
$api->resource('genre.book');

请注意,使用此方法,您仍将以相同的方式使用storeupdate方法,即在请求中传递genre_id

希望这能有所帮助!

票数 2
EN

Stack Overflow用户

发布于 2017-03-04 12:08:11

虽然这里没有100%的具体答案--每个资源都有一个控制器几乎总是比较容易,如果你想直接点击它,那么一个控制器就是你想要做的事情。

如果你可以(通常)坚持主要动作(索引,创建,存储,显示,编辑,更新,删除),这将使它更容易。它将保持有组织的事情,未来的开发人员在您的项目将能够很容易地遵循结构。

很好的阅读:基本放大器的DHH方法:http://jeromedalbert.com/how-dhh-organizes-his-rails-controllers/

白屋API指南:https://github.com/WhiteHouse/api-standards#white-house-web-api-standards

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42595561

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档