总结:消息通知

总结

  1. 视图上引用其他组件视图的同时加判断的方法 @includeWhen($boolean, '视图地址', [参数1=>'值1'])

  2. 如何发送消息通知

    有几种发送消息的频道,这里学习使用数据库

    • 首先需要建数据库,同时更新 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(通知实例) 进行通知的推送。

  3. 如何显示通知

    上面的逻辑是:用户回帖完成后(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()` 方法读取属于该用户的消息通知
    • ../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 写进数据库的那些键名']` 即可读取具体数据。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 4

你这样式需要调整调整, 太乱了 :cry:看不懂啊

4年前 评论

public $reply; 是什么意思

4年前 评论

第一次看觉得写的太乱不爱看!当遇到问题后,翻看了所有问题。你的这个写的不错!

4年前 评论

看文档观察者事件需要注册,这里为什么没有

10个月前 评论

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