laravel 消息通知实现

PS:本次主要记录一下laravel 自带的消息通知Notification的实现

1.生成数据库,可以使用迁移

  • 在项目目录下的cmd中运行 artisan命令
php artisan notifications:table
php artisan migrate
  • 在user表里增加一个notification_count 字段,记录未读通知数量

2.生成消息通知类

这里模拟点赞通知

php artisan make:notification UserSupport

如果implements ShouldQueue这个接口的话就会异步队列执行,如果去掉的话就是同步执行。

<?php

/**
 * 模拟用户点赞通知
 * laravel 通知表  notifications
 * 点赞表 user_support
 * 作者表 users
 * 用户表 user_info
 */

namespace App\Notifications;

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

use App\Models\UserSupport as UserSupportModel;

class UserSupport extends Notification implements ShouldQueue
{
    use Queueable;

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

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

    public function toMail($notifiable)
    {
        return (new MailMessage)
                    ->line('The introduction to the notification.')
                    ->action('Notification Action', 'www.baidu.com')
                    ->line('Thank you for using our application!');
    }

    public function toDatabase($notifiable)
    {
         $user = $this->support->user;
        
         $pic = rand(1,10);
        
        // 存入数据库里的数据
        return [
            'support_id' => $this->support->id,
            'doname' => $this->support->UserInfo->name,
            'toname' => $user->name,
            'pic'    => $pic.'.png',
            'cont'   => '内容内容'
        ];
    }

每个通知类都有个 via() 方法,它决定了通知在哪个频道上发送。我们加上 database 数据库来作为通知频道。

因为使用数据库通知频道,我们需要定义 toDatabase()。这个方法接收 $notifiable 实例参数并返回一个普通的 PHP 数组。这个返回的数组将被转成 JSON 格式并存储到通知数据表的 data 字段中。

3. 触发通知

  • 1.在模型监控器里 app/Observers/SupportObserver.php,观察者模式之前写过,这里就不做讲解了,想了解的点击此处
<?php

namespace App\Observers;

use App\Models\UserSupport;
use App\Notifications\UserSupport as UserSupportNotify;//引入通知类

class SupportObserver
{
    public function created(UserSupport $userSupport)
    {
        // 通知作者被点赞了
        //notify 方法稍后再user模型中定义
        $userSupport->user->notify(new UserSupportNotify($userSupport));
    }
    1. user模型 app/Models/User.php 中定义notify通知方法
namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Auth;

class User extends Authenticatable
{
    
    use Notifiable {
        notify as protected laravelNotify;
        // Notifiable 的trait里面有notify方法,此处我们给它个别名
    }
 	public function notify($instance)
    {	
    	
        // 如果要通知的人是当前用户,就不必通知了!
        if ($this->id == Auth::id()) {
            return;
        }

        // 只有数据库类型通知才需提醒,Email直接发送  或者其他的都 Pass
        if (method_exists($instance, 'toDatabase')) {
            $this->increment('notification_count');//字段加一
        }

        $this->laravelNotify($instance);//发送通知
    }
  • 请注意顶部 Auth 的引入。

  • 我们对 notify() 方法做了一个巧妙的重写,现在每当你调用 $user->notify() 时, users 表里的 notification_count 将自动 +1。

  • 在 User 模型类使用了 Notifiable trait, 而 Notifiable 中又引入了 HasDatabaseNotifications trait。
    HasDatabaseNotifications 中有 3 个函数,分别是 获取所有通知、获取未读通知 和 已读通知。

      trait HasDatabaseNotifications
      {
          public function notifications()
          {
              return $this->morphMany(DatabaseNotification::class, 'notifiable')
                                  ->orderBy('created_at', 'desc');
          }
      
      	  public function readNotifications()
          {
              return $this->notifications()
                                  ->whereNotNull('read_at');
          }
      
          public function unreadNotifications()
          {
              return $this->notifications()
                                  ->whereNull('read_at');
          }
      }
    
    • 接下来我们需要将通知展示出来

4.模板展示调用

控制器获取数据

  $uid = Auth::id();
  $user =  User::find($uid);

  // 已读未读是有一个 read_at 字段
  // dd($user->unreadNotifications); // 获取所有未读通知
  // dd($user->readNotifications); // 获取所有已读通知
  // dd($user->notifications); // 获取所有通知
  $unreadNotifications = $user->unreadNotifications;//用来消息通知      
  $userlist = User::select('id','name')->get();//用来点赞       
  return view('admin.index',compact('unreadNotifications','userlist'));

模板中判断是否有通知
{{ Auth::user()->notification_count > 0 ? ‘block’ : ‘none’ }}
{{ Auth::user()->notification_count }}

遍历展示通知数据

@foreach($unreadNotifications as $v)
     <a href="#" class="dropdown-item notify-item">
         <div class="notify-icon bg-faded">
             <img src="assets/images/avatars/avatar{{$v['data']['pic']}}" >
         </div>
         <p class="notify-details">
             <b>{{$v['data']['doname']}}</b>
             <span>{{$v['data']['cont']}}</span>
             <small class="text-muted">{{$v['created_at']}}</small>
         </p>
     </a>
 @endforeach

其中data数据就是通知类里toDatabase方法里存入数据量里的数据,如下图
laravel 消息通知实现_第1张图片

5.清空未读通知

再User模型里 app/Models/user.php 添加方法

public function markAsRead()
    {	
    	// 标记为已读,未读数量清零
        $this->notification_count = 0;
        $this->save();
        //更改notifications表read_at值
        $this->unreadNotifications->markAsRead();
    }

再控制器里调用这个方法就行
markAsRead其实就是在Illuminate\Notifications----》DatabaseNotification.php里将read_at修改了
laravel 消息通知实现_第2张图片

测试模拟点赞

:

public function support(Request $request){
            if($request->ajax()){
                
               $uid = $request->post('uid','1');
               $usersup = UserSupport::Create(['uid'=>$uid,'user_id'=>'33']);
               return true;

            }

            $IP = $request->getClientIp();
            return '非法请求,IP:'.$IP;
        }

点赞触发create时,观察者则监听到,下发通知

你可能感兴趣的:(laravel)