为你的论坛系统添加一个『提及』功能

背景

在论坛系统中,提及用户 是一个很常见的功能,也就是我们常说的@

例如:在learnku的回帖功能中我们可以看到,键入@会自动输出你已关注的用户列表,回帖成功后,被提及用户将受到一条通知

为你的论坛系统添加一个『提及』功能
回帖完成后,被@用户将会收到一条消息通知。今天,我们将为larabbs来添加这一功能

修改数据模型

我们可以使用正则表达式,来匹配用户回复内容中提及的一个或多个用户。我们需要修改下 Reply 模型。
修改文件为以下:

app/Models/Reply.php

<?php

namespace App\Models;

class Reply extends Model
{
    .
    .
    .
    public function mentionedUsers()
    {
        preg_match_all('/@([\w\-]+)/', $this->content, $matches);
        return $matches[1];
    }
}

生成通知类

$ php artisan make:notification UserMentioned

修改文件为以下:

app/Notifications/UserMentioned.php

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use App\Models\Reply;

class UserMentioned extends Notification
{
    use Queueable;

    public $reply;

    public function __construct(Reply $reply)
    {
        // 注入回复实体,方便 toDatabase 方法中的使用
        $this->reply = $reply;
    }

    public function via($notifiable)
    {
        // 开启通知的频道
        return ['database'];
    }

    public function toDatabase($notifiable)
    {
        $topic = $this->reply->topic;
        $link =  $topic->link(['#reply' . $this->reply->id]);

        // 存入数据库里的数据
        return [
            'reply_id' => $this->reply->id,
            'reply_content' => $this->reply->content,
            'user_id' => $this->reply->user->id,
            'user_name' => $this->reply->user->name,
            'user_avatar' => $this->reply->user->avatar,
            'topic_link' => $link,
            'topic_id' => $topic->id,
            'topic_title' => $topic->title,
        ];
    }
}

触发通知

我们希望当用户回复主题后,通知到被提及用户。故触发通知的时机是:『回复发布成功后』,在模型监控器里,我们可以在 created 方法里实现此部分代码,修改 created() 方法为以下:

app/Observers/ReplyObserver.php

<?php
.
.
.
use App\Models\User;
use App\Notifications\UserMentioned;

class ReplyObserver
{
    public function created(Reply $reply)
    {
        .
        .
        .
        // 通知被提及用户
        User::whereIn('name', $reply->mentionedUsers())
            ->get()
            ->each(function ($user) use ($reply) {
                $user->notify(new UserMentioned($reply));
            });
    }

    .
    .
    .
}

创建通知模板

创建此文件:

resources/views/notifications/types/_user_mentioned.blade.php

<li class="media @if ( ! $loop->last) border-bottom @endif">
  <div class="media-left">
    <a href="{{ route('users.show', $notification->data['user_id']) }}">
      <img class="media-object img-thumbnail mr-3" alt="{{ $notification->data['user_name'] }}" src="{{ $notification->data['user_avatar'] }}" style="width:48px;height:48px;" />
    </a>
  </div>

  <div class="media-body">
    <div class="media-heading mt-0 mb-1 text-secondary">
      <a href="{{ route('users.show', $notification->data['user_id']) }}">{{ $notification->data['user_name'] }}</a>
      在
      <a href="{{ $notification->data['topic_link'] }}">{{ $notification->data['topic_title'] }}</a>
      的评论中提及了你

      <span class="meta float-right" title="{{ $notification->created_at }}">
        <i class="far fa-clock"></i>
        {{ $notification->created_at->diffForHumans() }}
      </span>
    </div>
    <div class="reply-content">
      {!! $notification->data['reply_content'] !!}
    </div>
  </div>
</li>

至此,提及用户 功能开发完毕

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 2

当昵称不是唯一的时候该怎样解决呢

4年前 评论

@生活无限好 这个就要看name是表示的是昵称还是用户名了,larabbs没有允许name唯一,确实是会出现重复的情况。
而在learnku中,我们的name是唯一的。如果要解决那可能需要在注册的时候把name的验证条件加上unique:users

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!