Maison  >  Article  >  cadre php  >  Salle de discussion en temps réel : mise en œuvre via la diffusion d'événements basée sur Laravel+Pusher+Vue

Salle de discussion en temps réel : mise en œuvre via la diffusion d'événements basée sur Laravel+Pusher+Vue

不言
不言original
2018-07-31 15:48:545355parcourir

J'ai déjà dit que je compilerais un tutoriel sur la diffusion d'événements. Aujourd'hui, j'ai enfin le temps d'écrire cet article. Ce tutoriel est basé sur Laravel+Pusher+Vue, avec la diffusion d'événements comme technologie de base, vous permettant de créer rapidement. une application de salle de discussion en temps réel. Sans plus tarder, jetons un coup d'œil au contenu spécifique.

Initialisation de l'application

Configuration de l'installation

Tout d'abord, installez une nouvelle application de salle de discussion via Composer :

composer create-project laravel/laravel chatroom --prefer-dist

Parce que utilisez la diffusion d'événements, vous devez décommenter le fournisseur de services de diffusion dans config/app.php :

Salle de discussion en temps réel : mise en œuvre via la diffusion dévénements basée sur Laravel+Pusher+Vue

Modifiez l'élément de configuration BROADCAST_DRIVER dans .env en pusher :

BROADCAST_DRIVER=pusher

Bien que Laravel prenne en charge Pusher dès le départ, nous devons toujours installer le SDK PHP correspondant :

composer require pusher/pusher-php-server

Définir les informations d'identification de Pusher

Visitez le site officiel de Pusher, inscrivez-vous et connectez-vous au backend utilisateur, et créez une nouvelle application Channels :

Salle de discussion en temps réel : mise en œuvre via la diffusion dévénements basée sur Laravel+Pusher+Vue

Une fois la création terminée, vous pouvez obtenir les clés d'application sur la page de saut. Informations :

Salle de discussion en temps réel : mise en œuvre via la diffusion dévénements basée sur Laravel+Pusher+Vue

Remplissez simplement les champs correspondants dans les éléments de configuration correspondants dans .env dans le répertoire racine de l'application de salle de discussion.

Initialisation des ressources front-end

Nous utilisons Laravel Mix pour compiler du CSS et du JavaScript front-end :

npm install

De plus, Laravel fournit également la bibliothèque JavaScript Laravel Echo pour vous abonner et écouter les événements :

npm install --save laravel-echo pusher-js

Une fois l'installation terminée, vous devez également dire à Laravel Echo d'utiliser Pusher. Laravel nous a fourni cette implémentation dans resources/assets/js/bootstrap. js, mais il est commenté par défaut. Il suffit d'annuler ce commentaire :

import Echo from 'laravel-echo'
window.Pusher = require('pusher-js');
window.Echo = new Echo({
    broadcaster: 'pusher',
    key: process.env.MIX_PUSHER_APP_KEY,
    cluster: process.env.MIX_PUSHER_APP_CLUSTER,
    encrypted: true
});

Code d'échafaudage d'authentification de l'utilisateur

Nous avons défini que seuls les utilisateurs connectés peuvent accéder à la salle de discussion pour chat. Afin de simplifier le processus, nous utilisons la fonction d'authentification utilisateur par défaut de Laravel :

php artisan make:auth

La commande ci-dessus générera le routage, la vue, le contrôleur et d'autres codes nécessaires au système d'authentification utilisateur. Avant que la fonction ne prenne effet, vous devez exécuter la commande de migration de base de données pour générer la table de données correspondante, modifier les éléments de configuration liés à la base de données dans .env pour vous assurer que la base de données peut être connectée correctement, puis exécuter la commande suivante :

php artisan migrate

À ce stade, l'application est initialisée. Le travail de préparation est terminé, commençons à écrire le code métier.

Implémentation du code métier

Modèle de message

Créez d'abord une classe de modèle et son fichier de migration de base de données correspondant pour le message envoyé :

php artisan make:model Message -m

Ajoutez la ligne de code suivante à la classe de modèle d'application/message nouvellement générée pour faciliter l'affectation par lots :

/**
 * Fields that are mass assignable
 *
 * @var array
 */
protected $fillable = ['message'];

Écrivez ensuite le fichier de migration correspondant aux messages nouvellement générés dans le répertoire bases de données/migrations La méthode up :

Schema::create('messages', function (Blueprint $table) {
    $table->increments('id');
    $table->integer('user_id')->unsigned();
    $table->text('message');
    $table->timestamps();
});

Exécutez enfin la commande de migration pour générer les messages de la table de données :

php artisan migrate

Association entre utilisateurs et messages

Évidemment, la relation entre utilisateurs et messages Il existe une relation un-à-plusieurs. Ajoutez une nouvelle méthode d'association dans la classe de modèle Utilisateur :

/**
 * A user can have many messages
 *
 * @return \Illuminate\Database\Eloquent\Relations\HasMany
 */
public function messages()
{
    return $this->hasMany(Message::class);
}

Ensuite, définissez l'association correspondante dans la classe de modèle Message :

/**
 * A message belong to a user
 *
 * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
 */
public function user()
{
    return $this->belongsTo(User::class);
}
Code du contrôleur

Créez le contrôleur ChatsController pour implémenter une logique métier spécifique :

php artisan make:controller ChatsController
Écrivez la classe de contrôleur nouvellement générée app/Http/Controllers/ChatsController avec le code suivant :

<?php
namespace App\Http\Controllers;
use Auth;
use App\Message;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
class ChatsController extends Controller
{
    public function __construct()
    {
        $this->middleware(&#39;auth&#39;);  // 登录用户才能访问
    }
    /**
     * Show chats
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return view(&#39;chat&#39;);
    }
    /**
     * Fetch all messages
     *
     * @return Message
     */
    public function fetchMessages()
    {
        return Message::with(&#39;user&#39;)->get();
    }
    /**
     * Persist message to database
     *
     * @param  Request $request
     * @return Response
     */
    public function sendMessage(Request $request)
    {
        $user = Auth::user();
        $message = $user->messages()->create([
            &#39;message&#39; => $request->input(&#39;message&#39;)
        ]);
        return [&#39;status&#39; => &#39;Message Sent!&#39;];
    }
}
Ce contrôleur fournit trois méthodes commerciales, index est utilisé pour afficher la vue de la salle de discussion, l'utilisateur fetchMessages reçoit tous les messages et sendMessage est utilisé pour envoyer des messages.

Enregistrer les routes d'application

En conséquence, nous enregistrons trois routes dans routes/web.php :

Route::get(&#39;/&#39;, &#39;ChatsController@index&#39;);
Route::get(&#39;messages&#39;, &#39;ChatsController@fetchMessages&#39;);
Route::post(&#39;messages&#39;, &#39;ChatsController@sendMessage&#39;);
Supprimez la route /home des routes enregistrées. En conséquence, le L'attribut $redirectTo dans app/Http/Controllers/Auth/LoginController.php et app/Http/Controllers/Auth/RegisterController.php doit être ajusté :

protected $redirectTo = &#39;/&#39;;
Vue de la salle de discussion

Pour le code d'affichage de la salle de discussion, nous avons effectué de légers ajustements en fonction de l'extrait de code de la salle de discussion Bootsnipp. Créez d'abord resources/views/chat.blade.php :

@extends(&#39;layouts.app&#39;)
@section(&#39;content&#39;)
    <div class="container">
        <div class="row">
            <div class="col-md-8 col-md-offset-2">
                <div class="panel panel-default">
                    <div class="panel-heading">聊天室</div>
                    <div class="panel-body">
                        <chat-messages :messages="messages"></chat-messages>
                    </div>
                    <div class="panel-footer">
                        <chat-form
                                v-on:messagesent="addMessage"
                                :user="{{ Auth::user() }}"
                        ></chat-form>
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection
Cette vue permet d'afficher la page principale du salon de discussion. Notez que nous utilisons certains composants Vue dans la vue, le composant chat-messages est utilisé pour afficher tous les messages de discussion et le composant chat-form est utilisé pour envoyer des messages. Le code de ces composants sera donné plus tard.

Avant d'écrire le composant Vue, nous ajoutons du code de style pour la vue de discussion dans le modèle resources/views/layouts/app.blade.php (avant de l'ajouter à la balise ) :

<style>
  .chat {
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .chat li {
    margin-bottom: 10px;
    padding-bottom: 5px;
    border-bottom: 1px dotted #B3A9A9;
  }
  .chat li .chat-body p {
    margin: 0;
    color: #777777;
  }
  .panel-body {
    overflow-y: scroll;
    height: 350px;
  }
  ::-webkit-scrollbar-track {
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
    background-color: #F5F5F5;
  }
  ::-webkit-scrollbar {
    width: 12px;
    background-color: #F5F5F5;
  }
  ::-webkit-scrollbar-thumb {
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
    background-color: #555;
  }
</style>
Créez ensuite le composant ChatMessages.vue dans resources/assets/js/components :

<template>
    <ul class="chat">
        <li class="left clearfix" v-for="message in messages">
            <div class="chat-body clearfix">
                <div class="header">
                    <strong class="primary-font">
                        {{ message.user.name }}
                    </strong>
                </div>
                <p>
                    {{ message.message }}
                </p>
            </div>
        </li>
    </ul>
</template>
<script>
    export default {
        props: [&#39;messages&#39;]
    };
</script>
Créez ensuite le composant ChatForm.vue dans le même répertoire :

<template>
    <div class="input-group">
        <input id="btn-input" type="text" name="message" class="form-control input-sm" placeholder="在这里输入要发送的消息..." v-model="newMessage" @keyup.enter="sendMessage">
        <span class="input-group-btn">
            <button class="btn btn-primary btn-sm" id="btn-chat" @click="sendMessage">
                发送
            </button>
        </span>
    </div>
</template>
<script>
    export default {
        props: [&#39;user&#39;],
        data() {
            return {
                newMessage: &#39;&#39;
            }
        },
        methods: {
            sendMessage() {
                this.$emit(&#39;messagesent&#39;, {
                    user: this.user,
                    message: this.newMessage
                });
                this.newMessage = &#39;&#39;
            }
        }    
    }
</script>
Enfin, nous devons enregistrer ces deux composants dans l'instance racine de Vue située dans resources/assets/js/app.js :

require(&#39;./bootstrap&#39;);
window.Vue = require(&#39;vue&#39;);
Vue.component(&#39;chat-messages&#39;, require(&#39;./components/ChatMessages.vue&#39;));
Vue.component(&#39;chat-form&#39;, require(&#39;./components/ChatForm.vue&#39;));
const app = new Vue({
    el: &#39;#app&#39;,
    data: {
        messages: []
    },
    created() {
        this.fetchMessages();
    },
    methods: {
        fetchMessages() {
            axios.get(&#39;/messages&#39;).then(response => {
                this.messages = response.data;
            });
        },
        addMessage(message) {
            this.messages.push(message);
            axios.post(&#39;/messages&#39;, message).then(response => {
                console.log(response.data);
            });
        }
    }
});
Diffuser l'événement d'envoi de message

Pour pour discuter Pour une interaction en temps réel dans la salle, certains événements doivent être diffusés. Dans cet exemple, nous déclencherons l'événement MessageSent lorsque l'utilisateur enverra un message :

php artisan make:event MessageSent
Écrire l'application/Événements/. Code de classe d'événement MessageSent comme suit :
<?php
namespace App\Events;
use App\Message;
use App\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class MessageSent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;
    /**
     * User that sent the message
     *
     * @var User
     */
    public $user;
    /**
     * Message details
     *
     * @var Message
     */
    public $message;
    /**
     * Create a new event instance.
     * @param User $user
     * @param Message $message
     * @return void
     */
    public function __construct(User $user, Message $message)
    {
        $this->user = $user;
        $this->message = $message;
    }
    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel(&#39;chat&#39;);
    }
}

由于只有登录用户才能访问我们的应用,所以我们定义了一个私有的频道 chat,只有登录用户才能连接上它。

接下来,我们需要修改 ChatsController 的 sendMessage() 来广播 MessageSent 事件:

public function sendMessage(Request $request)
{
    $user = Auth::user();
    $message = $user->messages()->create([
        &#39;message&#39; => $request->input(&#39;message&#39;)
    ]);
    broadcast(new MessageSent($user, $message))->toOthers();
    return [&#39;status&#39; => &#39;Message Sent!&#39;];
}

然后在 routes/channels.php 中授权当前登录用户可以监听该私有频道:

Broadcast::channel(&#39;chat&#39;, function ($user) {
    return Auth::check();
});

现在,当一条消息发送后,MessageSent 事件就会被广播到 Pusher,使用 toOthers() 是为了将消息发送者从广播接收者中排除。

监听消息发送事件

MessageSent 事件在服务端被广播后,需要在客户端监听这个事件以便将最新发送消息更新到聊天室消息流中,我们可以通过在 resources/assets/js/app.js 中定义的 created() 方法中添加如下代码片段来实现这一功能:

created() {
    this.fetchMessages();
    Echo.private(&#39;chat&#39;)
        .listen(&#39;MessageSent&#39;, (e) => {
            this.messages.push({
                message: e.message.message,
                user: e.user
            });
        });
},

我们通过 Laravel Echo 连接到 chat 频道监听 MessageSent 广播事件,如果有新消息则将其推送到当前聊天室消息流中显示。

在正式测试聊天室应用之前,还需要运行以下命令通过 Laravel Mix 来编译前面编写的 JavaScript 代码:

npm run dev

使用示例

完成上述所有业务代码编写工作后,接下来就是见证工作成果的时候了,在项目根目录下运行如下命令启动应用:

php artisan serve

然后在浏览器通过 http://127.0.0.1:8000/ 访问应用,由于系统需要登录后才能访问,所以首先会跳转到登录页面,我们需要先注册一个新用户,注册成功后页面即跳转到聊天室页面,我们发送一条测试消息。

为了测试多个用户聊天的效果,打开另一个浏览器或者在当前浏览器新开一个隐身窗口,还是重复上面的访问注册步骤(注册名不同),注册成功后跳转到聊天室页面,看到的效果和上面一样,我们再发条消息试试。

可以看到两个窗口消息是同步的,所以已经达到我们预期的实时聊天效果,实现了通过事件广播构建实时聊天室的功能。

以上就是本篇文章的全部内容了,更多laravel内容请关注laravel框架入门教程。

相关文章推荐:

laravel框架中TokenMismatchException的异常处理内容

Laravel 5.1框架中的ACL用户授权和权限检查功能的实现

相关课程推荐:

2017年最新的五个Laravel视频教程推荐

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn