Tạo thông báo Real-Time với laravel
Initialization project Đầu tiên chúng ta sẽ init một project laravel sau đó sẽ config Database Mysql và thiết lập các biến môi trường cho ứng dụng copy env.example thành .env . cp .env.example .env DB_HOST=localhost DB_DATABASE=homestead DB_USERNAME=homestead DB_PASSWORD=secret .env Bây ...
Initialization project
Đầu tiên chúng ta sẽ init một project laravel sau đó sẽ config Database Mysql và thiết lập các biến môi trường cho ứng dụng
copy env.example thành .env .
cp .env.example .env DB_HOST=localhost DB_DATABASE=homestead DB_USERNAME=homestead DB_PASSWORD=secret .env
Bây giờ sẽ dùng composer để cài đặt các gói của ứng dụng
composer install
Chạy migrate để tạo ra bảng và sinh ra dữ liệu
php artisan migrate --seed
Mối quan hệ Users
Chúng ta muốn user có khả năng theo dõi user khác, và theo dõi bởi user khác. do đo chúng ta sẽ tạo ra quan hệ Many To Many.
php artisan make:migration create_followers_table --create=followers
Chúng ta cần tạo thêm vài trường để sinh bảng. user_id đại diện cho user người đang theo dõi và follows_id đại diện cho user đang được theo dõi
Cập nhật các trường cho followers
public function up() { Schema::create('followers', function (Blueprint $table) { $table->increments('id'); $table->integer('user_id')->index(); $table->integer('follows_id')->index(); $table->timestamps(); }); }
Chạy migrate để tạo bảng
php artisan migrate
Gán mới quan hệ cho Model 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
Chúng ta cần một vài chức năng cho theo theo dõi người khác, và kiểm tra xem user nào đang được Following
// ... 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
Danh sách Users
Cài đặt route
//... 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
Tao controller mới cho users
php artisan make:controller UsersController
// ... use AppUser; 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
@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
Đường dẫn /users page hiển thị danh sách users.
Class UsersController thêm chức năng flow và 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
Notifications
Laravel cung cấp API cho việc gửi thông báo qua nhiều kênh khác nhau
Follow notification: Được gửi khi user được follow bởi một user khác.
Tạo post notification: Mỗi khi bài viết mới được tạo sẽ gửi đến người follow.
User Followed Notification
Sử dụng artisan commands để tạo ra bảng và dữ liệu mẫu
php artisan notifications:table
php artisan migrate
tiếp theo tạo thêm notifi. Chạy lệnh sau để tạo ra class UserFollowed
php artisan make:notification UserFollowed
Sau đó chúng ta sẽ cập nhật fle class notification mà chúng ta vừa tạo ra:
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
Bằng cách sử dụng ShouldQueue. Laravel tự đông đẩy Notifi vào trong queue và chạy ngầm, nó làm tăng tốc độ xử lý
// ... use AppNotificationsUserFollowed; 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
Đánh đấu Notification đã được đọc
Notifi chứa một vài thông tin liên quan đến resource. Ví dụ, khi người dùng nhận được thông báo có bài viết mới, Notifi hiên thị nội dung và khi người dùng click vào nội dung đó thì phải hướng đến bài post mới và cờ phải gán là đã đọc
Bây giờ tiếp theo chúng ta sẽ phải kiểm tra xem notifi đã được đọc hay chưa
Tạo middleware bằng câu lệnh sau
php artisan make:middleware MarkNotificationAsRead
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
//... class Kernel extends HttpKernel { //... protected $middlewareGroups = [ 'web' => [ //... AppHttpMiddlewareMarkNotificationAsRead::class, ], // ... ]; //... }
app/Http/Kernel.php
Hiển thị thông báo
// ... class UsersController extends Controller { // ... public function notifications() { return auth()->user()->unreadNotifications()->limit(5)->get()->toArray(); } }
app/Http/Controllers/UsersController.php
Notifi trả về ít nhất 5 thông báo chưa đọc.
//... Route::group([ 'middleware' => 'auth' ], function () { // ... Route::get('/notifications', 'UsersController@notifications'); });
routes/web.php
Bây giờ thêm dropdown cho notifications
<head> <script> window.Laravel = <?php echo json_encode([ 'csrfToken' => csrf_token(), ]); ?> </script> @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 <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
npm install
Thêm code sau vào app.js
window._ = require('lodash'); window.$ = window.jQuery