现代的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
缺少follow
和unfollow
方法。 让我们完成它们,完成这部分。
//...
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