API RESTful Laravel 6.x的最佳实践:多对多关系

3

我正在使用Laravel 6开发API。

我有两个模型:

card -> 具有card_id等的卡表

user -> 具有user_id等的用户表

我已经在模型中定义了多对多的关系。

User.php

public function cards()
{
    return $this->belongsToMany('App\Models\v1\Card');
}

Card.php

public function users() {
    return $this->belongsToMany('App\Models\v1\User');
}

透视表被称为card_user。

现在我已经创建了单个实体的路由:

Route::resource('v1/users', 'v1\UsersController');
Route::resource('v1/cards', 'v1\CardsController');

我需要开发路由和控制器来插入和删除数据透视表中的行。

对于这个问题,最佳实践是什么?

我尝试使用一个特殊的控制器来响应特定的端点来解决这个问题:

Route::resource('v1/cards/{id}/users', 'v1\CardsUsersController')->only([
    'index', 'store', 'destroy'
]);

但当我需要存储信息时,我需要将卡片和用户的ID传递到URL中,并作为post请求正文中的对象,如下所示:

[
    'user_id' => $userId,
    'card_id' => $cardId
]

有更好的方法吗?

非常感谢!


你需要分享 UsersUsersControllerCardsUsersController - Wahyu Kristianto
3个回答

4
你可以使用嵌套资源,如下所述: https://laravel.com/docs/6.x/controllers#restful-nested-resources 有时您可能需要为“嵌套”资源定义路由。例如,照片资源可能有多个“评论”,这些评论可能附加在照片上。要嵌套资源控制器,请在路由声明中使用“点”符号。
Route::resource('photos.comments', 'PhotoCommentController');

此路由将注册一个“嵌套”的资源,可通过以下URL访问:photos/{photos}/comments/{comments}。

2
如果您必须为它们拥有单独的路由和控制器,那么最好的做法是:
Route::resource('v1/card_user', 'v1\CardsUsersController')->only(['index', 'store','destroy']);

保持代码简洁,不要过于复杂化。无论是你还是未来的其他人查看代码时都应该能够理解其用途。

2
标准的方法是使用资源/ID/子资源/子资源ID。 - Devon
谢谢!那么在路由中我可以返回什么样的资源呢?我已经创建了一个CardUser资源并返回类似以下内容的东西:{#1279 +"card_user": {#1216 +"card_id": 1 +"card_code": "95196" +"enabled": 1 +"users": array:1 [ 0 => {#1272 +"id": 1 +"last_name": "Lubowitz" +"first_name": "Beau" +"username": "beau.lubowitz" } ] } +"status": "success" +"code": 201 } - BobbyLinux
@RobertoBani 如果你跟随我的例子,那么你的CardUser资源应该将卡和用户作为单独的实体。顺便说一句,这似乎不是标准方法,所以我认为你应该使用Devons的答案来遵循最佳实践。我建议使用这种方法,因为我个人更喜欢保持URL简短。这个问题会帮助你更好地理解。 - Arun A S

1
我会将两个答案结合起来。作为一种关系,它在技术上是一个嵌套资源。此外,您真正拥有2个RESTful操作:存储和销毁(在Laravel中对应于附加和分离)。您可能还需要一个索引来查看所有关系。我认为“创建”操作是可选的,这取决于您的用户界面。
// Ability_Role pivot routes
Route::resource('v1/user.cards', 'UserCardController')
  ->only(['index', 'create', 'store','destroy']);

这将给出以下路由:
+--------+----------+------------------------------+--------------------+-------------------------------------------------+------------+
| Domain | Method   | URI                          | Name               | Action                                          | Middleware |
+--------+----------+------------------------------+--------------------+-------------------------------------------------+------------+
|        | GET|HEAD | v1/user/{user}/cards         | user.cards.index   | App\Http\Controllers\UserCardController@index   | web        |
|        | POST     | v1/user/{user}/cards         | user.cards.store   | App\Http\Controllers\UserCardController@store   | web        |
|        | GET|HEAD | v1/user/{user}/cards/create  | user.cards.create  | App\Http\Controllers\UserCardController@create  | web        |
|        | DELETE   | v1/user/{user}/cards/{card}  | user.cards.destroy | App\Http\Controllers\UserCardController@destroy | web        |
+--------+----------+------------------------------+--------------------+-------------------------------------------------+------------+

我选择将路由标记为user.cards,因为我认为您更希望从用户模型开始并附加卡片。
对于store方法,您可以发布一个卡片数组以附加到用户。
如果您还想从卡片开始,并存储一组用户,您也可以定义反向关系(尽管这需要第二个控制器,只有create和store路线)。
// Inverse create and store routes
Route::get('v1/cards/{card}/users/create', 'CardUserController@create')
  ->name('cards.users.create');
Route::post('v1/cards/{card}/users', 'CardUserController@store')
  ->name('cards.users.store');

现在你将会添加2条路由:

+--------+----------+------------------------------+--------------------+-------------------------------------------------+------------+
| Domain | Method   | URI                          | Name               | Action                                          | Middleware |
+--------+----------+------------------------------+--------------------+-------------------------------------------------+------------+
|        | GET|HEAD | api/user                     | api.               | Closure                                         | api        |
|        |          |                              |                    |                                                 | auth:api   |
|        | POST     | v1/cards/{card}/users        | cards.users.store  | App\Http\Controllers\CardUserController@store   | web        |
|        | GET|HEAD | v1/cards/{card}/users/create | cards.users.create | App\Http\Controllers\CardUserController@create  | web        |
|        | GET|HEAD | v1/user/{user}/cards         | user.cards.index   | App\Http\Controllers\UserCardController@index   | web        |
|        | POST     | v1/user/{user}/cards         | user.cards.store   | App\Http\Controllers\UserCardController@store   | web        |
|        | GET|HEAD | v1/user/{user}/cards/create  | user.cards.create  | App\Http\Controllers\UserCardController@create  | web        |
|        | DELETE   | v1/user/{user}/cards/{card}  | user.cards.destroy | App\Http\Controllers\UserCardController@destroy | web        |
+--------+----------+------------------------------+--------------------+-------------------------------------------------+------------+

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接