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

Laravel帖子@用户提及与#话题标签正则实现及报错处理

问题修复与实现方案

1. 报错解决

你遇到的BadMethodCallException报错根源是三个问题:

  • 调用$this->tags()->attach()时,$this指向的是当前Livewire组件createPost,而非你刚创建的帖子实例,应该用刚存好的$posts变量调用关联方法
  • 你的Post模型大概率还没定义和Tag模型的多对多关联
  • 额外错误:Post::create参数数组里混入了多余的$url变量定义,属于语法冗余需要删除

修正模型关联

先在app/Models/Post.php中添加和标签的多对多关联:

// 别忘了顶部引入Tag模型
use App\Models\Tag;

public function tags()
{
    return $this->belongsToMany(Tag::class);
}

同时要确保你已经创建了tags表、post_tag中间表,Tag模型类名首字母大写(你代码里写的tag::where是错误写法,必须是Tag::where)


2. 正则与业务逻辑实现

正则规则

  • 匹配#话题:你当前的/(?<=#)(\w+)/mi仅支持英文/数字/下划线的话题,如果要支持中文话题可以换成/(?<=#)([^\s#]+)/mi
  • 匹配@用户:可以用/(?<=@)(\w+)/mi,同理支持中文用户名换成/(?<=@)([^\s@]+)/mi

修正后的完整业务代码

public function createPost()
{
    if (auth()->check()) {
        $this->validate();

        $post = Post::create([
            'user_id' => auth()->user()->id,
            'school_id' => $this->school,
            'body' => $this->body,
            'is_anon' => $this->is_anon,
        ]);

        // 处理#话题
        preg_match_all('/(?<=#)([^\s#]+)/mi', $this->body, $matchedTags, PREG_SET_ORDER, 0);
        foreach($matchedTags as $matchedTag) {
            $tag = Tag::firstOrCreate(['name' => $matchedTag[0]]);
            $post->tags()->syncWithoutDetaching([$tag->id]);
        }

        // 处理@提及 发通知
        preg_match_all('/(?<=@)([^\s@]+)/mi', $this->body, $matchedUsers, PREG_SET_ORDER, 0);
        foreach($matchedUsers as $matchedUser) {
            $user = User::where('username', $matchedUser[0])->first();
            if ($user) {
                // 直接调用Laravel通知系统发通知,提前创建好MentionNotification即可
                $user->notify(new \App\Notifications\MentionNotification($post));
            }
        }
    }
}

这里用firstOrCreate替代你原来的if判断写法更简洁,syncWithoutDetaching可以避免重复关联同一个标签到帖子,比attach更安全。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 12:48:02