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
相关产品推荐
相关产品推荐

