如何使用Pusher向Laravel添加实时通知

现代的Web用户希望了解应用程序内发生的所有事情。 您不希望成为一个没有通知下拉列表的网站,不仅在所有社交媒体网站中找到,而且在如今的其他所有地方也都找不到。

幸运的是,使用Laravel和Pusher可以轻松实现此功能。

实时通知

为了向用户提供良好的体验,应实时显示通知。 一种方法是定期将AJAX请求发送到后端,并获取最新的通知(如果存在)。

更好的方法是利用WebSocket的功能,并在发送消息时立即接收通知。 这就是我们将在本文中使用的内容。

推杆

Pusher是一项Web服务,用于通过WebSocket将实时双向功能集成到Web和移动应用程序。

它有一个非常简单的API,但是我们将通过Laravel Broadcasting和Laravel Echo使它更加简单。

在本文中,我们将向现有博客添加实时通知。

该项目

初始化

首先,我们将克隆简单的Laravel博客:

git clone   https ://github.com/marslan-ali/laravel-blog

然后,我们将创建一个MySQL数据库并设置环境变量,以使应用程序可以访问数据库。

让我们将env.example复制到.env并更新与数据库相关的变量。

cp .env.example . envDB_HOST =localhost
DB_DATABASE =homestead
DB_USERNAME =homestead
DB_PASSWORD =secret

现在让我们使用以下命令安装项目的依赖项

composer install

并运行migration and seeding命令以使用一些数据填充数据库:

php artisan migrate --seed

如果您运行该应用程序并访问/posts则将看到生成的帖子列表。

检查应用程序,注册用户,并创建一些帖子。 这是一个非常基本的应用程序,但是可以完美地演示我们的演示。

关注用户关系

我们希望赋予用户跟随其他用户并被用户跟随的能力,因此我们必须在用户之间建立Many To Many关系才能实现。

让我们创建一个数据透视表,将用户与用户联系起来。 进行新的followers迁移:

php artisan make:migration create_followers_table --create=followers

我们需要为该迁移添加一些字段:一个user_id代表正在关注的用户,一个follows_id字段代表正在关注的用户。

更新迁移,如下所示:

public function up ()
 {
    Schema::create( 'followers' , function (Blueprint $table)  {
        $table->increments( 'id' );
        $table->integer( 'user_id' )->index();
        $table->integer( 'follows_id' )->index();
        $table->timestamps();
    });
}

现在,让我们迁移以创建表:

php artisan migrate

让我们向User模型添加关系方法。

// ...

class extends Authenticatable
 {
    // ...

    public function followers () 
     {
        return $this ->belongsToMany( self ::class, 'followers' , 'follows_id' , 'user_id' )
                    ->withTimestamps();
    }

    public function follows () 
     {
        return $this ->belongsToMany( self ::class, 'followers' , 'user_id' , 'follows_id' )
                    ->withTimestamps();
    }
}
app/User.php

现在用户模型具有必要的关系, followers返回用户的所有关注者,而follows返回用户所关注的每个人。

我们将需要一些帮助程序功能,以允许该用户follow另一个用户,并检查该用户是否在isFollowing特定用户。

// ...

class extends Authenticatable
 {
    // ...

    public function follow ($userId) 
     {
        $this ->follows()->attach($userId);
        return $this ;
    }

    public function unfollow ($userId)
     {
        $this ->follows()->detach($userId);
        return $this ;
    }

    public function isFollowing ($userId) 
     {
        return (boolean) $this ->follows()->where( 'follows_id' , $userId)->first([ 'id' ]);
    }

}
app/User.php

完善。 设置好模型后,就该列出用户了。

列出用户

让我们从设置必要的路线开始

/...
Route::group([ 'middleware' => 'auth' ], function ()  {
    Route::get( 'users' , 'UsersController@index' )->name( 'users' );
    Route::post( 'users/{user}/follow' , 'UsersController@follow' )->name( 'follow' );
    Route::delete( 'users/{user}/unfollow' , 'UsersController@unfollow' )->name( 'unfollow' );
});
routes/web.php

然后,该为用户创建一个新的控制器了:

php artisan make :controller UsersController

我们将为其添加index方法:

// ...
use App \ User ;
class UsersController extends Controller
 {
    //..
    public function index ()
     {
        $users = User::where( 'id' , '!=' , auth()->user()->id)->get();
        return view( 'users.index' , compact( 'users' ));
    }
}
app/Http/Controllers/UsersController.php

该方法需要一个视图。 让我们创建users.index视图并将此标记放入其中:

@extends( 'layouts.app' )

@section( 'content' )
    <div class =" container ">
        < div class =" col - sm - offset -2 col - sm -8">

            <!-- Following -->
            < div class =" panel panel - default ">
                < div class =" panel - heading ">
                    All Users
                </ div >

                < div class =" panel - body ">
                    < table class =" table table - striped task - table ">
                        < thead >
                        < th > User </ th >
                        < th > </ th >
                        </ thead >
                        < tbody >
                        @ foreach ($ users as $ user )
                            < tr >
                                < td clphpass =" table - text ">< div > {{ $user->name }}</div></td>
                                @ if (auth()->user()->isFollowing($user->id))
                                    <td>
                                        <form action= "{{route('unfollow', ['id' => $user->id])}}" method= "POST" >
                                            {{ csrf_field() }}
                                            {{ method_field( 'DELETE' ) }}

                                            <button type= "submit" id= "delete-follow-{{ $user->id }}" class =" btn btn - danger ">
                                                < i class =" fa fa - btn fa - trash "></ i > Unfollow
                                            </ button >
                                        </ form >
                                    </ td >
                                @ else
                                    < td >
                                        < form action =" {{route( 'follow' , [ 'id' => $user->id])}} " method=" POST ">
                                            {{ csrf_field() }}

                                            <button type=" submit " id=" follow-user-{{ $user->id }} " class=" btn btn-success ">
                                                <i class=" fa fa-btn fa-user "></i>Follow
                                            </button>
                                        </form>
                                    </td>
                                @endif
                            </tr>
                        @endforeach
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
@endsection
resources/views/users/index.blade.php

现在,您可以访问/users页面以查看用户列表。

跟随或取消关注

UsersController缺少followunfollow方法。 让我们完成它们,完成这部分。

//...
class UsersController extends Controller
 {
    //...
    public function follow (User $user)
     {
        $follower = auth()->user();
        if ($follower->id == $user->id) {
            return back()->withError( "You can't follow yourself" );
        }
        if (!$follower->isFollowing($user->id)) {
            $follower->follow($user->id);

            // sending a notification
            $user->notify( new UserFollowed($follower));

            return back()->withSuccess( "You are now friends with {$user->name}" );
        }
        return back()->withError( "You are already following {$user->name}" );
    }

    public function unfollow (User $user)
     {
        $follower = auth()->user();
        if ($follower->isFollowing($user->id)) {
            $follower->unfollow($user->id);
            return back()->withSuccess( "You are no longer friends with {$user->name}" );
        }
        return back()->withError( "You are not following {$user->name}" );
    }
}
app/Http/Controllers/UsersController.php

完成以下功能。 现在,我们可以从/users页面关注和取消关注用户。

通知事项

Laravel提供了一个用于通过多个渠道发送通知的API。 电子邮件,SMS,Web通知和任何其他类型的通知都可以使用Notification类发送。

我们将有两种类型的通知:

  • 跟踪通知:在其他用户关注时发送给用户
  • 帖子创建通知:在创建新帖子时发送给给定用户的关注者

用户关注的通知

使用工匠命令,我们可以为通知生成迁移:

php artisan notifications: table

让我们迁移并创建此新表。

php artisan migrate

我们从关注通知开始。 让我们执行以下命令来生成通知类:

php artisan make :notification UserFollowed

然后,我们将更新刚刚创建的通知类文件:

class UserFollowed extends Notification implements ShouldQueue
 {
    use Queueable ;

    protected $follower;

    public function __construct (User $follower)
     {
        $this ->follower = $follower;
    }

    public function via ($notifiable)
     {
        return [ 'database' ];
    }

    public function toDatabase ($notifiable)
     {
        return [
            'follower_id' => $this ->follower->id,
            'follower_name' => $this ->follower->name,
        ];
    }
}
app/Notifications/UserFollowed.php

使用这几行代码,我们可以实现很多目标。 首先,我们需要在创建此通知时注入$follower的实例。

使用via方法,我们告诉Laravel通过database通道发送此通知。 当Laravel遇到此问题时,它将在通知表中创建一个新记录。

user_id和通知type是自动设置的,另外我们可以用更多数据扩展通知。 那就是toDatabase目的。 返回的数组将添加到通知的data字段中。

最后,通过实现ShouldQueue ,Laravel将自动将此通知放入要在后台执行的队列中,这将加快响应速度。 这是有道理的,因为稍后将在使用Pusher时添加HTTP调用。

让我们在用户受到关注时启动通知。

// ...
use App \ Notifications \ UserFollowed ;
class UsersController extends Controller
 {
    // ...
    public function follow (User $user)
     {
        $follower = auth()->user();
        if ( ! $follower->isFollowing($user->id)) {
            $follower->follow($user->id);

            // add this to send a notification
            $user->notify( new UserFollowed($follower));

            return back()->withSuccess( "You are now friends with {$user->name}" );
        }

        return back()->withSuccess( "You are already following {$user->name}" );
    }

    //...
}
app/Http/Controllers/UsersController.php

报表广告

我们可以在User模型上调用notify方法,因为它已经在使用Notifiable特征。

您要通知的任何模型都应使用它来访问notify方法。

将通知标记为已读

通知将包含一些信息和资源链接。 例如:当用户收到有关新帖子的通知时,该通知应显示信息性文本,单击后将用户重定向到该帖子,并标记为已读。

我们将制作一个中间件来检查请求是否具有?read=notification_id输入并将其标记为已读。

让我们使用以下命令制作中间件:

php artisan make:middleware MarkNotificationAsRead

然后,将这段代码放入中间件的handle方法中:

class MarkNotificationAsRead
 {
    public function handle ($request, Closure $next)
     {
        if ($request->has( 'read' )) {
            $notification = $request->user()->notifications()->where( 'id' , $request->read)->first();
            if ($notification) {
                $notification->markAsRead();
            }
        }
        return $next($request);
    }
}
app/Http/Middleware/MarkNotificationAsRead.php

为了使我们的中间件能够针对每个请求执行,我们将其添加到$middlewareGroups

//...
class Kernel extends HttpKernel
 {
    //...
    protected $middlewareGroups = [
        'web' => [
            //...
            \App\Http\Middleware\MarkNotificationAsRead::class,
        ],
        // ...
    ];
    //...
}
app/Http/Kernel.php

完成后,让我们显示一些通知。

显示通知

我们必须使用AJAX显示通知列表,然后使用Pusher实时更新。 首先,让我们向控制器添加一个notifications方法:

// ...
class UsersController extends Controller
 {
    // ...
    public function notifications ()
     {
        return auth()->user()->unreadNotifications()->limit( 5 )->get()->toArray();
    }
}
app/Http/Controllers/UsersController.php

这将返回最后5条未读的通知。 我们只需要添加一条路由即可访问它。

//...
Route::group([ 'middleware' => 'auth' ], function ()  {
    // ...
    Route::get( '/notifications' , 'UsersController@notifications' );
});
routes/web.php

报表广告

现在,在标题中添加通知下拉列表。

<head>
    <!-- // ... // -->
    <!-- Scripts -->
    <script>
        window.Laravel = <?php echo json_encode([
            'csrfToken' => csrf_token(),
        ]); ?>
    </script>
    <!-- This makes the current user 's id available in javascript -->
    @if(!auth()->guest())
        <script>
            window.Laravel.userId = <?php echo auth()->user()->id; ?>
        </script>
    @endif
</head>
<body>
    <!-- // ... // -->
    @if (Auth::guest())
        <li><a href="{{ url(' /login ') }}">Login</a></li>
        <li><a href="{{ url(' /register ') }}">Register</a></li>
    @else
        <!-- // add this dropdown // -->
        <li class="dropdown">
            <a class="dropdown-toggle" id="notifications" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
                <span class="glyphicon glyphicon-user"></span>
            </a>
            <ul class="dropdown-menu" aria-labelledby="notificationsMenu" id="notificationsMenu">
                <li class="dropdown-header">No notifications</li>
            </ul>
        </li>
<!-- // ... // -->
resources/views/layouts/app.blade.php

我们还在脚本内添加了一个全局window.Laravel.userId变量,以获取当前用户的ID。

JavaScript和SASS

我们将使用Laravel Mix来编译JavaScript和SASS。 首先,我们需要安装npm软件包。

npm install

现在,将以下代码添加到app.js:

window ._ = require ( 'lodash' );
window .$ = window .jQuery = require ( 'jquery' );
require ( 'bootstrap-sass' );
var notifications = [];
const NOTIFICATION_TYPES = {
    follow : 'App\\Notifications\\UserFollowed'
};
app/resources/assets/js/app.js

这只是一个初始化。 我们将使用通知来存储所有通知对象,无论它们是通过AJAX还是Pusher检索的。

您可能会猜到, NOTIFICATION_TYPES包含通知的类型。

接下来,让我们通过AJAX进行“获取”通知。

//...
$( document ).ready( function ( )  {
    // check if there's a logged in user
    if (Laravel.userId) {
        $.get( '/notifications' , function ( data )  {
            addNotifications(data, "#notifications" );
        });
    }
});
function addNotifications ( newNotifications, target )  {
    notifications = _.concat(notifications, newNotifications);
    // show only last 5 notifications
    notifications.slice( 0 , 5 );
    showNotifications(notifications, target);
}

app/resources/assets/js/app.js

这样,我们就可以从API中获取最新的通知,并将其放入下拉列表中。

addNotifications内部,我们使用Lodash将当前通知与新通知连接起来 ,仅显示最新的5条。

我们还需要一些其他功能来完成这项工作。

报表广告

//...
function showNotifications ( notifications, target )  {
    if (notifications.length) {
        var htmlElements = notifications.map( function ( notification )  {
            return makeNotification(notification);
        });
        $(target + 'Menu' ).html(htmlElements.join( '' ));
        $(target).addClass( 'has-notifications' )
    } else {
        $(target + 'Menu' ).html( '<li class="dropdown-header">No notifications</li>' );
        $(target).removeClass( 'has-notifications' );
    }
}
app/resources/assets/js/app.js

此函数生成所有通知的字符串,并将其放入下拉列表中。

如果没有收到通知,则仅显示“没有通知”。

它还向下拉按钮添加了一个类,当存在通知时,它将仅更改其颜色。 有点像Github的通知。

最后,一些辅助函数可以生成通知字符串。

//...
// Make a single notification string
function makeNotification ( notification )  {
    var to = routeNotification(notification);
    var notificationText = makeNotificationText(notification);
    return '<li><a href="' + to + '">' + notificationText + '</a></li>' ;
}
// get the notification route based on it's type
function routeNotification ( notification )  {
    var to = '?read=' + notification.id;
    if (notification.type === NOTIFICATION_TYPES.follow) {
        to = 'users' + to;
    }
    return '/' + to;
}
// get the notification text based on it's type
function makeNotificationText ( notification )  {
    var text = '' ;
    if (notification.type === NOTIFICATION_TYPES.follow) {
        const name = notification.data.follower_name;
        text += '<strong>' + name + '</strong> followed you' ;
    }
    return text;
}
app/resources/assets/js/app.js

现在,我们将其添加到我们的app.scss文件中:

//... 
#notifications .has-notifications {
  color : #bf5329
}
app/resources/assets/sass/app.scss

让我们编译资产:

npm run  dev

如果您现在尝试追随用户,他们会收到通知。 当他们单击它时,他们将被重定向到/users ,并且通知将消失。

新帖通知

当用户创建新帖子时,我们将通知关注者。

让我们从生成通知类开始。

php artisan make :notification NewPost

让我们更新生成的类,如下所示:

// ..
use App \ Post ;
use App \ User ;
class NewArticle extends Notification implements ShouldQueue
 {
    // ..
    protected $following;
    protected $post;
    public function __construct (User $following, Post $post)
     {
        $this ->following = $following;
        $this ->post = $post;
    }
    public function via ($notifiable)
     {
        return [ 'database' ];
    }
    public function toDatabase ($notifiable)
     {
        return [
            'following_id' => $this ->following->id,
            'following_name' => $this ->following->name,
            'post_id' => $this ->post->id,
        ];
    }
}
app/Notifications/NewArticle.php

报表广告

接下来,我们需要发送通知。 我们有几种方法可以做到这一点。

我喜欢使用雄辩的旁观者。

让我们成为Post的观察者,并听听其事件。 我们将创建一个新类: app/Observers/PostObserver.php

namespace App\Observers;
use App\Notifications\NewPost;
use App\Post;
class PostObserver
 {
    public function created (Post $post)
     {
        $user = $post->user;
        foreach ($user->followers as $follower) {
            $follower->notify( new NewPost($user, $post));
        }
    }
}

然后,在AppServiceProvider注册观察者:

//...
use App \ Observers \ PostObserver ;
use App \ Post ;
class AppServiceProvider extends ServiceProvider
 {
    //...
    public function boot ()
     {
        Post::observe(PostObserver::class);
    }
    //...
}
app/Providers/AppServiceProvider.php

现在我们只需要格式化要在JS中显示的消息即可:

// ...
const NOTIFICATION_TYPES = {
    follow : 'App\\Notifications\\UserFollowed' ,
    newPost : 'App\\Notifications\\NewPost'
};
//...
function routeNotification ( notification )  {
    var to = `?read= ${notification.id} ` ;
    if (notification.type === NOTIFICATION_TYPES.follow) {
        to = 'users' + to;
    } else if (notification.type === NOTIFICATION_TYPES.newPost) {
        const postId = notification.data.post_id;
        to = `posts/ ${postId} ` + to;
    }
    return '/' + to;
}
function makeNotificationText ( notification )  {
    var text = '' ;
    if (notification.type === NOTIFICATION_TYPES.follow) {
        const name = notification.data.follower_name;
        text += `<strong> ${name} </strong> followed you` ;
    } else if (notification.type === NOTIFICATION_TYPES.newPost) {
        const name = notification.data.following_name;
        text += `<strong> ${name} </strong> published a post` ;
    }
    return text;
}
app/resources/assets/js/app.js

和瞧! 用户正在收到有关关注和新帖子的通知! 继续尝试!

使用Pusher进行实时

是时候使用Pusher通过websocket实时获取通知了。

pusher.com上注册一个免费的Pusher帐户,然后创建一个新应用。

...
BROADCAST_DRIVER=pusher
PUSHER_KEY=
PUSHER_SECRET=
PUSHER_APP_ID=

broadcasting配置文件中设置您帐户的选项:

//...
    'connections' => [
            'pusher' => [
                //...
                'options' => [
                    'cluster' => 'eu' ,
                    'encrypted' => true
                ],
            ],
    //...
config/broadcasting.php

然后,我们将在providers数组中注册App \ Providers \ BroadcastServiceProvider。

// ...
'providers' => [
    // ...
    App\Providers\BroadcastServiceProvider
    //...
],
//...


我们现在应该安装Pusher的PHP SDK和Laravel Echo:

config/app.php

报表广告

composer require pusher/pusher-php-server
 npm install --save laravel-echo pusher-js

我们必须设置要广播的通知数据。 让我们更新UserFollowed通知:

//...
class UserFollowed extends Notification implements ShouldQueue
 {
    // ..
    public function via ($notifiable)
     {
        return [ 'database' , 'broadcast' ];
    }
    //...
    public function toArray ($notifiable)
     {
        return [
            'id' => $this ->id,
            'read_at' => null ,
            'data' => [
                'follower_id' => $this ->follower->id,
                'follower_name' => $this ->follower->name,
            ],
        ];
    }
}
app/Notifications/UserFollowed.php

NewPost

//...
class NewPost extends Notification implements ShouldQueue
 {
    //...
    public function via ($notifiable)
     {
        return [ 'database' , 'broadcast' ];
    }
    //...
    public function toArray ($notifiable)
     {
        return [
            'id' => $this ->id,
            'read_at' => null ,
            'data' => [
                'following_id' => $this ->following->id,
                'following_name' => $this ->following->name,
                'post_id' => $this ->post->id,
            ],
        ];
    }
}
app/Notifications/NewPost.php

我们需要做的最后一件事是更新我们的JS。 打开app.js并添加以下代码

// ...
window .Pusher = require ( 'pusher-js' );
import Echo from "laravel-echo" ;
window .Echo = new Echo({
    broadcaster : 'pusher' ,
    key : 'your-pusher-key' ,
    cluster : 'eu' ,
    encrypted : true
});
var notifications = [];
//...
$( document ).ready( function ( )  {
    if (Laravel.userId) {
        //...
        window .Echo.private( `App.User. ${Laravel.userId} ` )
            .notification( ( notification ) => {
                addNotifications([notification], '#notifications' );
            });
    }
});
app/resources/assets/js/app.js

我们在这里完成了。 通知是实时添加的。 您现在可以使用该应用程序,并查看通知的更新方式。

结论

Pusher有一个非常简单的API,它使接收实时事件变得异常容易。 结合Laravel通知,我们可以从一个地方通过多个渠道(电子邮件,SMS,Slack等)发送通知。 在本教程中,我们将用户跟踪功能添加到了一个简单的博客中,并使用上述工具对其进行了增强,以获得一些流畅的实时功能。

Pusher和Laravel通知还有很多:串联的服务允许您将发布/订阅消息实时发送到浏览器,移动设备和IOT设备。 还有一个在线状态API,可获取用户的在线/离线状态。

请检查它们各自的文档( Pusher文档Pusher教程Laravel文档 )以更深入地探索它们并充分利用它们的真正潜力。

如果您在任何类型的开发项目中需要帮助,我也可以为您提供有关项目的咨询。 我是最受好评的自由职业者。 您可以直接在 Upwork 上雇用我   你也可以雇用我   自由职业者

如果您有任何评论,问题或建议,请随时在下面的评论部分中发布它们!

From: https://hackernoon.com/how-to-add-real-time-notifications-to-laravel-with-pusher-6l12h3yqz

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值