Laravel 5.3 New features Laravel Echo use: Live chat room

Source: Internet
Author: User
Tags auth closure join joins json php and what echo live chat

1, what is Laravel Echo
Echo is a tool that allows us to easily implement WebSockets in Laravel applications (about websockets working principles and mechanisms to refer to this article: WebSocket combat) while simplifying building complex websockets interactions for more general, Complex part.

Note: Echo is still in the development phase, the tutorial code and the final release version may be in discrepancy, I hope.
Echo is made up of two parts: a series of optimizations for the Laravel event broadcast system, and a new JavaScript package.

In Laravel 5.3, the Echo backend component has been integrated into the Laravel core library without additional introduction (unlike the Cashier expansion pack), and you need to work with the front-end JavaScript to use these components, not just the Echo JavaScript library, You'll also see the laravel optimization of ease of use when dealing with websockets.

The Echo JavaScript Library can be introduced via NPM, which is based on the pusher JS (JavaScript pusher SDK) or Socket.io (JavaScript redis websockets SDK).

2. When to use Echo
WebSockets is useful when you need to send an asynchronous live message to a user-whether the message is a notification or a page update data, while keeping the user on the same page without refreshing. Of course, you can use long polling, or some regular JavaScript ping, to do this, but it wastes bandwidth and makes unnecessary requests without updating the server. By contrast, WebSockets is powerful and does not cause additional load to the server, scalable, and extremely fast.

If you want to use Websockets,echo in a laravel application, it provides a clean, concise syntax for a variety of functions, simple as a public channel, complex such as authentication, authorization, private, and presence channels.

Note: The WebSockets implementation provides three channels: public, which means that everyone can subscribe, private, authenticated and authorized users can subscribe to, presense, not allowed to send messages, only to inform the user whether the channel already exists.
3, to achieve a simple broadcast events
Let's say we want to implement a chat room system with multiple rooms, so we need to trigger an event each time a new chat room message is received.

Note: You need to familiarize yourself with the Laravel event broadcast mechanism to better understand this tutorial.
So, first we create this event:

PHP Artisan make:event chatmessagewasreceived
Open this newly generated class (app/events/chatmessagewasreceived.php) and make sure it's implemented Shouldbroadcast, and then we'll broadcast it to a "chat-room.1" Public channel.

Then we create a model and a corresponding migration for the chat room message, which contains the USER_ID and messages fields:

PHP Artisan Make:model chatmessage--migration
Finally, the code for the event class chatmessagewasreceived is as follows:

...
Class Chatmessagewasreceived extends Event implements Shouldbroadcast
{
Use Interactswithsockets, serializesmodels;

Public $chatMessage;
Public $user;

Public function __construct ($chatMessage, $user)
{
$this->chatmessage = $chatMessage;
$this->user = $user;
}

Public Function Broadcaston ()
{
return [
"Chat-room.1"
];
}

}
Edit the generated migration class code as follows:

...
Class Createchatmessagestable extends migration
{
Public function up ()
{
Schema::create (' Chat_messages ', function (Blueprint $table) {
$table->increments (' id ');
$table->string (' message ');
$table->integer (' user_id ')->unsigned ();
$table->timestamps ();
});
}

Public function Down ()
{
Schema::d rop (' chat_messages ');
}
}
Also make sure that the new fields in the model are in the whitelist:

...
Class Chatmessage extends Model
{
Public $fillable = [' user_id ', ' message '];
}
Then, the event is triggered in a specific scenario. For testing purposes, I usually create an artisan command to create an event, so let's try it.

PHP Artisan Make:command Sendchatmessage
Open the newly created command class app/console/commands/sendchatmessage.php and edit the file as follows:

...
Class Sendchatmessage extends Command
{
protected $signature = ' chat:message {message} ';

protected $description = ' Send chat message. '

Public function handle ()
{
Fire off of an event, just randomly grabbing the "the"
$user = \app\user::first ();
$message = \app\chatmessage::create ([
' user_id ' => $user->id,
' Message ' => $this->argument (' message ')
]);

Event (New \app\events\chatmessagewasreceived ($message, $user));
}
}
Open app/console/kernel.php, add the command you just created to the $commands property to register it as a valid artisan command:

...
Class Kernel extends Consolekernel
{
protected $commands = [
Commands\sendchatmessage::class,
];
...
At this point, the event code is basically complete, you need to register a pusher account (Echo can also handle Redis and Socket.io, but in this case we use pusher), create a new application in the pusher account and get key, secret, and app IDs, and then set these values to the Pusher_key, Pusher_secret, and pusher_app_id corresponding to the. env file.

Finally, the pusher library is introduced:

Composer require pusher/pusher-php-server:~2.0
Now you can send the event to the pusher account by running the following command:

PHP artisan chat:message "Howdy Everyone"
If all goes well, you should be able to go to the Pusher debug console, trigger this event, and see the following effects:

4. Implement broadcast events through ECHO
We've just implemented a simple push event to the pusher system, so let's look at what Echo has to offer us.

Install the Echo JS Library

The easiest way to introduce the Echo JavaScript library into a project is through NPM and elixir. First, we introduce pusher JS:

# Install the basic elixir requirements
NPM Install
# Install Pusher JS and Echo, and add to Package.json
NPM Install Pusher-js--save
NPM Install Laravel-echo--save
Next, modify the Resouces/assets/js/app.js to import the appropriate file:

Window. Pusher = require (' Pusher-js ');

Import Echo from "Laravel-echo"

Window.echo = new Echo (' Your pusher key here ');
@todo: Set up Echo bindings
Then, set the Elixir Gulpfile.js file to take effect:

var elixir = require (' Laravel-elixir ');

Elixir (function (Mix) {
Mix.browserify (' app.js ');
});
Finally, run the Gulp or Gulp Watch command to import the resulting file into the HTML template, in addition to adding the CSRF token input:

...
<meta name= "Csrf-token" content= "{{Csrf_token ()}}" >
...
<body>
...

<script src= "Js/app.js" ></script>
</body>
Note: If it is a newly installed Laravel application, you need to run PHP artisan Make:auth before writing all of the HTML, because subsequent functionality requires Laravel authentication.
Subscribe to public channels via Echo

Back to Resources/assets/js/app.js, let's listen to the chat-room.1 of the public channel that ECHO broadcasts to, and record all incoming information to the user console:

Window. Pusher = require (' Pusher-js ');

Import Echo from "Laravel-echo"

Window.echo = new Echo (' Your pusher key here ');

Echo.channel (' chat-room.1 ')
. Listen (' chatmessagewasreceived ', function (data) {
Console.log (Data.user, data.chatmessage);
});
We told Echo: the subscribed public channel name is chat-room.1, and the listener event is chatmessagewasreceived, and when the event occurs, it is passed to the anonymous function and executes the code. The specific display is as follows:

With just a few lines of code, we can access the JSON-formatted chat information and the corresponding user, not only to inform the user, but also to update the memory data, so that each websockets message implements the current page data update.

5. Subscribe to private channel via Echo

And then we let chat-room.1 become private. To do this, first we need to prefix the channel name with the private-, and then edit the Broadcastson () method on the event class chatmessagewasreceived to set the channel name to Private-chat-room.1.

Next, replace the previous echo.channel () with the Echo.private () in App.js.

Others remain the same, but the script now runs an error:

This is another powerful feature that ECHO offers us: Authentication and authorization.

Echo Basic Authentication and authorization

The authentication system consists of two parts, first of all, when you first open the application, Echo sends the POST request to the/broadcasting/socket route, and when we set the Echo tool on the Laravel side, this route passes through your laravel session The ID is associated to the pusher socket ID so that both laravel and pusher know how to identify whether a given pusher socket connection is connected to a specific laravel session.

Note: Each JavaScript-initiated request, whether Vue or jquery, contains a X-socket-id header corresponding to the socket ID, but it works without it--it can be obtained by the Socket ID associated with the session earlier.
Second, the ECHO Authentication and authorization feature means that when you want to access a protected resource, echo Ping/broadcasting/auth to check if you can access the channel, because your socket ID is associated with the corresponding Laravel Session, we can write a simple and clear ACL rule for this route.

First, open config/app.php to cancel this line of comments:

App\providers\broadcastserviceprovider::class,
Open the service provider file (app/providers/broadcastserviceprovider.php), which reads as follows:

...
Class Broadcastserviceprovider extends ServiceProvider
{
Public Function boot ()
{
Broadcast::route ([' Middleware ' => [' web ']]);

Broadcast::auth (' channel-name.* ', function ($user, $id) {
return true;
});
}
There are two places to note, first of all, Broadcast::route () allows you to define the middleware to be applied to/broadcasting/socket and/broadcasting/auth, and you can keep it as web-invariant. Second, Broadcast::auth () allows us to define the permissions for the specified channel or channel group.

Write private channel authentication permissions

Now we have a channel called private-chat-room.1, and there may be multiple channels in the future, such as private-chat-room.2, so we define permissions for all channels here:

Broadcast::auth (' chat-room.* ', function ($user, $chatroomId) {
Return whether or isn't this current user are authorized to visit this chat room
});
As you can see, the first value passed to the closure is the current user, and if any of the * is matched to, it is passed in as the second argument.

Note: Although we renamed Private-chat-room.1, you can see that there is no need to add private-prefixes when defining access rights.
In this blog tutorial, we simply demonstrate the authorization code, you also need to create a model and migration for the chat room, and a many-to-many association with the user, and then in the closure to check whether the current user is connected to this chat room, now we simply return true:

Broadcast::auth (' chat-room.* ', function ($user, $chatroomId) {
if (true) {//Replace with real ACL
return true;
}
});
Test to see what you will see.

You should be able to see an empty console log, and then you can trigger the artisan command, which will see the user and chat room messages, just as before, but now requires authorized authenticated users.

If you see the following message, there is no problem, meaning that everything works fine, but your system determines that you do not have access to the chat room:

6. Subscribe to Presence Channel via Echo

Now we can determine in the background which users can access the chat room, when the user sends the message to the chat room (similar to sending the request via AJAX to the server, but instead of the user request through the Artisan command in our case), Triggers the chatmessagewasreceived event and broadcasts it, sending the message through WebSockets to all authenticated and authorized users, what are we going to do next?

Suppose we want to show which users are online in the chat room, or make a prompt when the user enters or leave, which can be done through the presence channel.

We need to do two things: a new Broadcast::auth () permission definition and a new channel with the presence-prefix. Interestingly, since authentication definitions do not require private-and presence-prefixes, private-chat-room.1 and presence-chat-room.1 are in Broadcast::auth () Can share the same code: chat-room.*, there is no problem, as long as the two certification rules consistent. But it's confusing to everyone, so I'm going to add a new name, using PRESENCE-CHAT-ROOM-PRESENCE.1.

Since we're just talking about whether it exists, there's no need to bind this channel to events, instead, just add us directly to the channel in App.js:

Echo.join (' chat-room-presence.1 ')
. Here (function (members) {
Runs when you join, and when anyone else leaves or joins
Console.table (members);
});
We join a presence channel and then provide a callback that triggers when the user loads the page or when another user joins or leaves. This will be triggered in these three events, and more granular control can be used to monitor then (current user joins), joining (other users join), and leaving (other users to leave):

Echo.join (' chat-room-presence.1 ')
   . Then (function (members) {
        //runs when to join
        console.table (members);
& nbsp;  })
    joining (function (Joiningmember, members) {
        //runs when another member joins
        console.table ( Joiningmember);
   })
    Leaving (function (Leavingmember, members) {
       / /runs when another member leaves
        console.table (leavingmember);
   }); The
reminds you again that you can not prefix the channel name with the presence-, as far as I know, the only scene in the echo that must be prefixed by presence-is the event class's Broadcaston () method that defines the event on a private channel broadcast. All other places can remove these prefixes, Echo will automatically process (such as the authentication definition in Broadcastserviceprovider), or through the method name (Echo.channel () and Echo.private () in the JavaScript package) method).

Next, set permissions for this channel in Broadcastserviceprovider:

Broadcast::auth (' chat-room-presence.* ', function ($user, $roomId) {
if (true) {//Replace with real authorization
return [
' id ' => $user->id,
' Name ' => $user->name
];
}
});
As you can see, when the user authenticates and the channel does not return true, it returns an array of user information that can be used for sidebar such as online users.

If everything works, now you can open the application in different browsers and view the updated membership list in the console:

7, excluding the current user

Echo also provides a feature: What if you don't want the current user to get a notification?

Maybe your chat room will pop up all sorts of new messages every time, and you just want to have a little bit of information on top of the screen, and you don't want the person who sent the message to get the message, right?

To exclude the current user from the list of received messages, you need to call the $this->dontbroadcasttocurrentuser () method in the constructor of the event class:

...
Class Chatmessagewasreceived extends Event implements Shouldbroadcast
{
...
Public function __construct ($chatMessage, $user)
{
$this->chatmessage = $chatMessage;
$this->user = $user;

$this->dontbroadcasttocurrentuser ();
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.