总结:消息通知
总结
-
视图上引用其他组件视图的同时加判断的方法
@includeWhen($boolean, '视图地址', [参数1=>'值1'])
-
如何发送消息通知
有几种发送消息的频道,这里学习使用数据库
-
首先需要建数据库,同时更新 users 表的结构(增加一个 notification_count 字段)
php artisan notifications:table
=> 生成notifications 表php artisan make:migration add_notification_count_to_users_table --table=users
=> 生成迁移文件,自行编辑:up 方法里面增加字段,down 写逆向操作。- 执行迁移
php artisan migrate
-
然后需要生成通知类
php artisan make:notification TopicReplied
=> 生成 app/Notifications/TopicReplied.php ,需要编辑这个文件有3个方法
- 构造函数
__construct()
=> 主要功能是先在外面配置成员变量用于存储等下需要用到的数据,在构造函数中,直接赋值use App\Models\Reply;
...
public $reply; public function __construct(Reply $reply) { $this->reply = $reply; }
* 频道配置 `via()`
public function via($notifiable)
{
// 这里使用数据库频道
return ['database'];
}* 入库函数 `toDatabase()` => 如果选择数据库作为通知频道,那么就需要编辑 toDatabase() 函数,在有新消息通知的时候,会先将消息详情存入数据库
public function toDatabase($notifiable)
{
// 先获取实例
$topic = $this->reply->topic;
// 这里获取链接地址,最后生成的地址为 "项目地址/topics/{topic}/{slug?}#reply{reply的主键id}"
$link = $topic->link(['#reply' . $this->reply->id]);// 存入数据库里的数据:这里直接 return 会自动转 json 然后存 notifications 表的 data 字段里面 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, ];
}
> 这里的 `link()` 就是我们生成带 slug 地址的那个写在 User 模型中的函数,那个函数之前写了个参数默认为空数组的参数,这里就是拼它的第三参数,将最终的地址变成 `http://larabbs.test/topics/{topic}?{slug}{#reply回复id}` => 这其实是个锚点,因为视图上装每条回复的div都给了个id: `id="reply{{ $reply->id }}"` 所以这样点击通知的链接的时候,会直接跳转到帖子的回复部分中的通知针对的那条回复。
- 构造函数
-
上面只是写好了通知类,发送通知需要在 ReplayObserver 这个模型观察器中进行:当回复成功后,发送通知
public function created(Reply $reply) { $topic = $reply->topic; // 获取回复的帖子的实例 $topic->increment('reply_count', 1); //增加帖子的回复数量 $topic->user->notify(new TopicReplied($reply)); //发送通知(实例化 TopicReplied 通知类) }
上面是通过
$reply->topic
获取回复所属的帖子,然后通过$topic->user
获取帖子所属用户,最后用模型中定义的notify(参数列表中实例化一个通知类)
发送通知。 -
User 模型中的 notify 方法
use Notifiable { notify as protected laravelNotify; }
/**
-
通知
*/
public function notify($instance)
{
// 如果要通知的人是当前用户,就不必通知了!
if ($this->id == Auth::id()) {
return;
}$this->increment('notification_count');
$this->laravelNotify($instance);
}> 其实 Notifiable 这个 trait 自带 notify 方法发送消息通知,但是我们这里需要改写它,但同时又需要使用自带的这个 notify 方法,为了避免歧义,我们引用时用 `notify as protected laravelNotify` => 相当于把 Notifiable 这个 trait 中的 notify 方法改名为 laravelNotify 。
然后 User 模型中的 notify 方法增加了两个逻辑:一是判断是不是发帖的人回复了自己,如果回复自己则不用通知,二是在 users 表中,给需要通知的用户的 notification_count 字段自增1,然后再用
laravelNotify(通知实例)
进行通知的推送。 -
-
如何显示通知
上面的逻辑是:用户回帖完成后(ReplyObserver@created),发送通知(User@notify(通知类实例)),最后入库:users 表的notification_count 字段 +1,notifications 表记录通知详情。现在需要显示
-
../layouts/_header.blade.php 中,用判断当前用户的 notification_count 字段的方法,来判断是否有通知,且这个通知的 “badge” 有一个超链接,指向 “项目网址/NotificationsController/index”。
-
显示通知则是:
- 配置路由 routes/web.php 中
Route::resource('notifications', 'NotificationsController', ['only' => ['index']]);
- 新建控制器 NotificationsController
php artisan make:controller NotificationsController
然后新建方法 index:use Auth;
...
public function index() { // 获取登录用户的所有通知 $notifications = Auth::user()->notifications()->paginate(20); // 跳转到视图 ../notifications/index.blade.php return view('notifications.index', compact('notifications')); }
> 这里需要引用 Auth 类,然后通过 `Auth::user()` 获取当前用户实例,调用 Notifiable 这个 trait 提供的 `notifications()` 方法读取属于该用户的消息通知
- 配置路由 routes/web.php 中
-
../notifications/index.blade.php,这里面有一段代码需要注意
@if ($notifications->count()) <div class="notification-list"> @foreach ($notifications as $notification) @include('notifications.types._' . snake_case(class_basename($notification->type))) @endforeach {!! $notifications->render() !!} </div>
@else
没有消息通知!@endif
> 首先用 `@if($notifications->count)` 判断有没有通知 * 有通知的话,这句代码需要注意 `@include('notifications.types._' . snake_case(class_basename($notification->type)))` 这是引用子视图,但是子视图的这个名字是这样得来的: * `'notifications.types._'` 这是说视图的两层文件夹 ../notifications/types/后面的_就是说视图以_开头 * 后面的 `class_basename($notification->type)` 是在读取 $notification 的 type 属性,即 notifications 表中的 type 字段 => 这个字段存的就是通知类的命名空间(发送通知时自动读通知类的内容,写进数据库的)。如果用 `class_basename()` 去读命名空间,得到的只是那个类名。`class_basename('App\Notifications\TopicReplied') = TopicReplied` * `snake_case()` 函数就是把字符串全转小写加下划线的形式 `snake_case('TopicReplied') => topic_replied` * 最后生成的视图其实是 ../notifications/types/_topic_replied.blade.php > 这里我其实没搞懂为什么要写这么复杂,直接写准确的地址感觉就行了,甚至不需要放 types/ 文件夹下? * 最后在 _topic_replied.blade.php 这个子视图中显示通知详情需要这样 `$notifications->data['字段']` => 因为其实 data 存的是 json,取出来不用管,直接用 `..->data['json属性即我们在 TopicReplied@toDatabase 方法中return 写进数据库的那些键名']` 即可读取具体数据。
-
你这样式需要调整调整, 太乱了 :cry:看不懂啊
public $reply; 是什么意思
第一次看觉得写的太乱不爱看!当遇到问题后,翻看了所有问题。你的这个写的不错!
看文档观察者事件需要注册,这里为什么没有