*/ public const TYPES = ['like', 'dislike', 'favorite', 'watch', 'bookmark', 'download']; /** * `target_type` 列的合法取值:锚点是哪一类对象。 * * task 任务、collection 文集、progress_chapter 书·章节、article 文章、terms 术语。 * * @var list */ public const TARGET_TYPES = ['task', 'collection', 'progress_chapter', 'article', 'terms']; protected $table = 'likes'; protected $primaryKey = 'id'; public $incrementing = false; protected $keyType = 'string'; protected $casts = [ 'id' => 'string', ]; protected $fillable = ['type', 'target_id', 'target_type', 'user_id', 'context']; /** * 操作者是人类用户时的那一行。 * * `user_id` 存的是 uuid,对应 `user_infos.userid`(不是主键 `id`),所以要写 * 三参数形式。同款写法见 {@see Channel::owner()}。 * * 关系没有数据库外键约束——`likes` 建表时就没有,加不得(migration 只准加 * 不准改)。匹配列 `user_infos.userid` 上有唯一索引,whereIn 走得动。 */ public function user(): BelongsTo { return $this->belongsTo(UserInfo::class, 'user_id', 'userid'); } /** * 操作者是 AI 助手时的那一行。 * * 同一个 `user_id` 落在 `user_infos` 或 `ai_models` 两张表之一,没有类型判别列, * 所以不是 morphTo,只能两条关系并存、取到哪个算哪个。 * 见 {@see ReactionResource::toArray()}。 */ public function aiModel(): BelongsTo { return $this->belongsTo(AiModel::class, 'user_id', 'uid'); } }