Reaction.php 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. <?php
  2. namespace App\Models;
  3. use App\Http\Resources\V3\ReactionResource;
  4. use Illuminate\Database\Eloquent\Factories\HasFactory;
  5. use Illuminate\Database\Eloquent\Model;
  6. use Illuminate\Database\Eloquent\Relations\BelongsTo;
  7. /**
  8. * 用户对某个锚点(target)的单向操作记录。
  9. *
  10. * 点赞、收藏、书签、关注、下载记录共用这张表:type 区分操作种类,
  11. * 唯一键 (type, target_id, user_id) 保证「一个用户对一个锚点的同种操作只有一条」。
  12. *
  13. * 底层仍是历史表 `likes`(表名不迁移,v2 的 Like 模型继续指向同一张表)。
  14. */
  15. class Reaction extends Model
  16. {
  17. use HasFactory;
  18. /**
  19. * `type` 列的合法取值。
  20. *
  21. * 列本身是 varchar(32) 没有约束,这里是 v3 入口处收紧的白名单——
  22. * v2 的 `LikeController` 不做校验,历史数据里出现过的只有这几种。
  23. *
  24. * @var list<string>
  25. */
  26. public const TYPES = ['like', 'dislike', 'favorite', 'watch', 'bookmark', 'download'];
  27. /**
  28. * `target_type` 列的合法取值:锚点是哪一类对象。
  29. *
  30. * task 任务、collection 文集、progress_chapter 书·章节、article 文章、terms 术语。
  31. *
  32. * @var list<string>
  33. */
  34. public const TARGET_TYPES = ['task', 'collection', 'progress_chapter', 'article', 'terms'];
  35. protected $table = 'likes';
  36. protected $primaryKey = 'id';
  37. public $incrementing = false;
  38. protected $keyType = 'string';
  39. protected $casts = [
  40. 'id' => 'string',
  41. ];
  42. protected $fillable = ['type', 'target_id', 'target_type', 'user_id', 'context'];
  43. /**
  44. * 操作者是人类用户时的那一行。
  45. *
  46. * `user_id` 存的是 uuid,对应 `user_infos.userid`(不是主键 `id`),所以要写
  47. * 三参数形式。同款写法见 {@see Channel::owner()}。
  48. *
  49. * 关系没有数据库外键约束——`likes` 建表时就没有,加不得(migration 只准加
  50. * 不准改)。匹配列 `user_infos.userid` 上有唯一索引,whereIn 走得动。
  51. */
  52. public function user(): BelongsTo
  53. {
  54. return $this->belongsTo(UserInfo::class, 'user_id', 'userid');
  55. }
  56. /**
  57. * 操作者是 AI 助手时的那一行。
  58. *
  59. * 同一个 `user_id` 落在 `user_infos` 或 `ai_models` 两张表之一,没有类型判别列,
  60. * 所以不是 morphTo,只能两条关系并存、取到哪个算哪个。
  61. * 见 {@see ReactionResource::toArray()}。
  62. */
  63. public function aiModel(): BelongsTo
  64. {
  65. return $this->belongsTo(AiModel::class, 'user_id', 'uid');
  66. }
  67. }