You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何借助模型关联通过多态表计算社交网络中的karma值?

问题描述

我正在开发类Reddit的社交应用,用户发布的Message和Comment会收到点赞(vote值为1)和点踩(vote值为-1),以此计算用户的karma值。已建立User、Message、Comment、Vote模型,所有关联关系配置正常(如User HasMany Message、Comment BelongsTo Message等)。其中Vote为多态表,包含vote、user_id等字段,关联关系已正确设置。

最初尝试用以下代码计算用户karma值,但无法正常运行:

$user = User::find(...);
$karma = $user->messages()->votes()->sum('vote');

目前通过以下方式实现了功能,但觉得不够简洁,想请教是否有仅通过模型关联实现的更优写法(后续还要对Comment做同样处理):

$user = User::find(...);
$ids = $user->messages->pluck('id')->toArray();
$karma = Vote::where('voteable_type', 'App\Models\Message')
    ->whereIn('voteable_id', $ids)
    ->sum('vote');

优化方案

可以通过Eloquent的关联特性实现更简洁的写法,以下是几种基于模型关联的解决方案:

1. 单独计算Message的Karma值

在User模型中定义hasManyThrough关联,直接关联到用户所有Message的投票记录:

// app/Models/User.php
public function messageVotes()
{
    return $this->hasManyThrough(
        Vote::class,
        Message::class,
        'user_id',       // Message表关联User的外键
        'voteable_id',   // Vote表关联Message的外键
        'id',            // User表主键
        'id'             // Message表主键
    )->where('voteable_type', Message::class);
}

之后计算Message的karma值只需一行代码:

$user = User::find(...);
$messageKarma = $user->messageVotes()->sum('vote');

2. 同时计算Message和Comment的总Karma值

先在User模型中添加Comment Votes的关联,再新增一个计算总Karma的访问器:

// app/Models/User.php
public function commentVotes()
{
    return $this->hasManyThrough(
        Vote::class,
        Comment::class,
        'user_id',
        'voteable_id',
        'id',
        'id'
    )->where('voteable_type', Comment::class);
}

// 定义总Karma访问器
public function getTotalKarmaAttribute()
{
    return $this->messageVotes()->sum('vote') + $this->commentVotes()->sum('vote');
}

使用时直接访问属性即可:

$user = User::find(...);
$totalKarma = $user->total_karma; // 支持蛇形命名访问

3. 统一关联所有内容的投票(更灵活)

如果需要一次性关联用户发布的Message和Comment的所有投票,可以用闭包筛选多态类型:

// app/Models/User.php
public function contentVotes()
{
    return $this->hasManyThrough(
        Vote::class,
        \Illuminate\Database\Eloquent\Model::class,
        'user_id',
        'voteable_id',
        'id',
        'id'
    )->where(function ($query) {
        $query->where('voteable_type', Message::class)
              ->orWhere('voteable_type', Comment::class);
    });
}

计算总Karma时直接调用:

$totalKarma = $user->contentVotes()->sum('vote');

这些写法完全依赖模型关联,避免了手动处理ID数组,代码更简洁且符合Eloquent的设计规范。

内容的提问来源于stack exchange,提问作者luisfer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 04:45:24