首页 > 解决方案 > 已解决:寻找一种更智能的方式来同步和排序 Laravel/Eloquent 数据透视表中的条目

问题描述

在我的 Laravel 5.1 应用程序中,我有 Page(为网页建模)和 Media(为图像建模)类。Page 包含媒体对象的集合,并且这种关系在“media_page”数据透视表中维护。数据透视表包含 page_id、media_id 和 sort_order 列。

网站上的实用程序表单允许管理员手动将一个或多个媒体项与页面相关联,并指定媒体项在视图中呈现的顺序。当表单提交时,控制器会收到一个排序的媒体 ID 列表。关联保存在 Controller 的 store() 和 update() 方法中,如下所示:

[店铺] $page->media()->attach($mediaIds);

[更新]$page->media()->sync($mediaIds);

这工作正常,但不允许我保存在 mediaIds 请求参数中指定的 sort_order。因此,媒体项目总是按照它们在数据库中出现的顺序返回到视图中,而不管管理员如何手动订购它们。我知道在保存单个记录时如何为数据透视表附加额外的数据,但在将数组传递给 attach() 或 sync() 时不知道如何执行此操作(或者是否可能),如上所示。

我能看到的唯一方法是:

我希望有一个更简单的解决方案,需要更少的数据库访问。还是我只是想多了,实际上,自己做循环与让 Laravel 在接收到数组时更进一步做循环没有什么不同?

[解决方案] 我通过如下重塑数组来使其工作。它分解以逗号分隔的 'mediaIds' 请求参数并遍历结果数组,将每个媒体 id 分配为 $mediaIds 数组中的键,将 sort_order 值设置为等于键在数组中的位置。

$rawMediaIds = explode(',', request('mediaIds'));
foreach($rawMediaIds as $mediaId) {
    $mediaIds[$mediaId] = ['sort_order' => array_search($mediaId, $rawMediaIds)];
}

然后在检索 Page 的关联媒体时按 sort_order 排序:

public function media() {
    return $this->belongsToMany(Media::class)->orderBy('sort_order', 'asc');
}

标签: laraveleloquent

解决方案


您可以在附加或同步时将数据添加到数据透视表,如下所示:


$mediaIds = [
    1 => ['sort_order' => 'order_for_1'],
    3 => ['sort_order' => 'order_for_3']
];

//[STORE]
$page->media()->attach($mediaIds;

//[UPDATE]
$page->media()->sync($mediaIds);

推荐阅读