کم و بیش همه شما دوستان و طرفداران دنیای وب با چت روم ها و سیستم های چت آنلاین کار کرده اید. گاهی این سوال پیش می آید که آیا این سیستم خیلی پیشرفته و پیچیده است و من توانایی اجرای آن را دارم یا خیر؟ در پاسخ به این سوال باید بگویم که با مطالعه این آموزش قطعا به ساده ترین شکل ممکن برنامه چت با لاراول و Vuejs را پیاده سازی خواهید کرد.
در این آموزش یک برنامه چت با لاراول و Vue.Js ایجاد می کنیم. برای بهبود عملکرد سیستم از سرویس پیام رسانی فوری pusher و برای سمت کلاینت هم از Laravel Echo و کتابخانه pusher.js برای بروزرسانی بلادرنگ رابط کاربری مان استفاده خواهیم کرد.
در این مقاله یاد می گیریم که لاراول چطور یک رویداد را منتشر کرده و Vue.js این رویداد را گرفته و کامپوننت vue را بصورت بلادرنگ بروزرسانی می کند.
برای نصب آخرین نسخه لاراول لطفا ابتدا دستورات زیر را در ترمینال وارد کنید.
laravel new chat # or composer create-project laravel/laravel chat --prefer-dist
به داخل فولدر پروژه بروید:
cd chat
دستور زیر را برای نصب وابستگی های Frontend اجرا کنید. npm یک سیستم مدیریت پکیج بسیار قدرتمند است که در آن تمام وابستگی های کار با فریم ورک های سمت فرانتد مانند Vuejs وجود دارد.
npm install
پروژه را در ویرایشگر مورد علاقه خود باز کنید، من از Visual Studio Code استفاده می کنم.
npm install
یک پایگاه داده ایجاد و مشخصات آن را در فایل .env قرار دهید.
حال یک چهارچوب احراز هویت که توسط لاراول ارائه می شود را ایجاد کنید.
php artisan make:auth
حال به ترمینال رفته و دستور زیر را برای Migrate کردن جداول در پایگاه داده اجرا کنید.
php artisan migrate
سپس به آدرس http://localhost:8000/register رفته و یک کاربر را ثبت نام کنید.
در این مرحله باید یک مدل Message به همراه migration مربوط به آن بوجود بیاورید. از این مدل برای ذخیره پیام ها استفاده می کنیم.
بنابراین به ترمینال رفته و دستور زیر را برای ایجاد مدل و migration اجرا کنید.
php artisan make:model Message -m
حال به فایل migration رفته و کدهای زیر را به آن اضافه کنید.
// create_messages_table public function up() { Schema::create('messages', function (Blueprint $table) { $table->increments('id'); $table->integer('user_id')->unsigned(); $table->text('body'); $table->timestamps(); $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); }); }
با دستور زیر جدول را به پایگاه داده تان migrate کنید.
php artisan migrate
برای نوشتن برنامه چت با لاراول و Vuejs دو مدل داریم:
روابط این مدل به شرح زیر است:
مدل user رابطه hasMany با مدل Message دارد. بدین معنی است که هر کاربر می تواند تعداد بی شماری (رابطه یک به چند) پیام ارسال کند.
Message هم رابطه belongsTo با مدل user دارد. بدین معنی است که هر پیام قطعا مختص یک کاربر است.
// User.php public function messages() { return $this->hasMany(Message::class); }
سپس فایل Message را باز کرده و رابطه معکوس این مدل را با مدل user تعریف می کنیم.
// Message.php public function user() { return $this->belongsTo(User::class); }
همچنین برای جلوگیری از بروز خطای Mass Assignment فیلدهای fillable مان را در فایل Message تعریف می کنیم.
// Message.php protected $fillable = ['body'];
همچنین یک فیلد دیگر به نام selfMessage به آن اضافه می کنیم. این فیلد مشخص می کند یک پیام مربوط به ما و یا به کاربری که با آن چت می کنیم است.
// Message.php protected $appends = ['selfMessage'];
در زیر یک متد تعریف کردیم که به کاربر می گوید که پیامی که دریافت میکند مربوط به کاربری است که به سیستم وارد (login) شده است یا نه (یا مربوط به کاربر مهمان است).
ما باید این موارد را از هم متمایز کنیم چون می خواهیم کلاس های css مختلفی به پیام های هر گروه از کاربران بدهیم.
// Message.php public function getSelfMessageAttribute() { return $this->user_id === auth()->user()->id; }
در نهایت مدل Message.php باید شبیه زیر باشد.
// Message.php <?php namespace App; use Illuminate\Database\Eloquent\Model; class Message extends Model { protected $fillable = ['body']; protected $appends = ['selfMessage']; public function getSelfMessageAttribute() { return $this->user_id === auth()->user()->id; } public function user() { return $this->belongsTo(User::class); } }
یک کنترلر به نام chatController.php ایجاد کنید
php artisan make:controller ChatController
یک متد index() داخل آن تعریف نمایید.
// ChatController.php <?php namespace App\Http\Controllers; use Illuminate\Http\Request; class ChatController extends Controller { public function __construct() { return $this->middleware('auth'); } public function index() { return view('chat'); } }
سپس یک فایل ویو به نام chat.blade.php داخل فولدر views ایجاد کنید. کدهای زیر را در فایل chat.blade.php قرار دهید.
<!-- chat.blade.php --> @extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div class="card"> <div class="card-header">Chats</div> <div class="card-body"> Chats </div> </div> </div> <div class="col-md-4"> <div class="card"> <div class="card-header">Users</div> <div class="card-body"> Users </div> </div> </div> </div> </div> @endsection
فایل web.php را باز کرده و روت های زیر را در آن وارد کنید.
// web.php Route::get('/chat', 'ChatController@index')->name('chat');
به آدرس http://localhost:8000/chat بروید و ظاهر برنامه چت با لاراول و Vuejs ببینید.
ترمینال را باز کرده و کدهای زیر را در آن تایپ کنید.
npm run watch
حال اگر ما در فایل های vue کدی بنویسیم، بطور خودکار کامپایل شده و داخل فولدر public > js قرار میگیرد.
به مسیر assets > js > component رفته و فایل ExampleComponnent.vue را به chatComponent.vue تغییر نام دهید. همچنین در فولدر asset > js فایل app.js را مطابق زیر تغییر دهید.
// app.js require('./bootstrap'); window.Vue = require('vue'); Vue.component('chat-component', require('./components/ChatComponent.vue')); const app = new Vue({ el: '#app' });
فایل را ذخیره کنید. می بینید که یک پیام نوتیفیکیشن به عنوان Laravel Mix Compilation Successfully ظاهر می شود.
سپس کدهای زیر را در فایل chatComponent.vue بنویسید.
<template> <div class="col-md-8"> <div class="card"> <div class="card-header">Chats</div> <div class="card-body"> Chats </div> </div> </div> </template> <script> export default { mounted() { console.log('Component mounted.') } } </script>
همچنین یک فایل با نام UserComponent.vue داخل فولدر components ایجاد کنید.
<template> <div class="col-md-4"> <div class="card"> <div class="card-header">Users</div> <div class="card-body"> Users </div> </div> </div> </template> <script> export default { mounted() { console.log('Component mounted.') } } </script>
حال می خواهیم این کامپوننت ها را تفکیک کنیم.
کدهای داخل فایل chatComponent.vue را به دو کامپوننت تفکیک می کنیم:
سپس داخل فولدر components یک فایل کامپوننت vue به نام chatMessagesComponent.vue ایجاد می کنیم.
// ChatMessagesComponent.vue
<template>
<div class="chat__messages">
Messages
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>
همچنین به یک فرم نیاز داریم تا کاربران پیام های خود را در آن نوشته و آن را برای کاربران دیگر ارسال کنند.
سپس داخل فولدر componnets یک فایل کامپوننت vue به نام chatFormComponent.vue ایجاد می کنیم.
// ChatFormComponent.vue
<template>
<div>
Form
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>
سپس هر دو کامپوننت ها را داخل فایل assets > js > app.js ثبت می کنیم.
// app.js require('./bootstrap'); window.Vue = require('vue'); Vue.component('chat-component', require('./components/ChatComponent.vue')); Vue.component('user-component', require('./components/UserComponent.vue')); Vue.component('chat-messages-component', require('./components/ChatMessageComponent.vue')); Vue.component('chat-form-component', require('./components/ChatFormComponent.vue')); const app = new Vue({ el: '#app' });
همچنین کدهای chatMessageComponnent را به یک کامپوننت دیگر به نام MessageComponnent تفکیک می کنیم.
این کامپوننت فقط کار نمایش پیام ها را بر عهده دارد و هر پیام باید این کامپوننت را رندر کند.
سپس کامپوننت MessageComponent.vue را در داخل فولدر Componnents ایجاد می کنیم.
/ MessageComponent.vue
<template>
<div class="chat__message">
Message
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>
این کامپوننت را داخل فایل app.js ثبت می کنیم.
// app.js Vue.component('message-component', require('./components/MessageComponent.vue'));
حال فایل chatMessageComponnent.vue را با کدهای زیر بروزرسانی کنید.
// ChatMessagesComponent.vue <template> <div class="message-area"> <message-component></message-component> </div> </template> <script> export default { mounted() { console.log('Component mounted.') } } </script> <style> .message-area { height: 400px; max-height: 400px; overflow-y: scroll; padding: 15px; border-bottom: 1px solid #eee; } </style>
فایل را ذخیره کنید. خروجی باید مانند زیر باشد.
حال کدهای زیر را در فایل chatFormComponnent.vue اضافه کنید.
// ChatFormComponent.vue <template> <div> <form class="form"> <textarea cols="25" rows="5" class="form-input"> </textarea> <span class="notice"> Hit Return to send a message </span> </form> </div> </template> <script> export default { mounted() { console.log('Component mounted.') } } </script> <style> .form { padding: 8px; } .form-input { width: 100%; border: 1px solid #d3e0e9; padding: 5px 10px; outline: none; } .notice { color: #aaa } </style>
همان طور که می بینید ما به کامپوننت مان کمی استایل هم داده ایم. ظاهر برنامه چت با لاراول و Vuejs باید مطابق تصویر زیر باشد.
حال داخل فایل MessageComponnent استایل های زیر را اضافه کنید.
// MessageComponent.vue <template> <div class="message self"> <strong class="user">Krunal</strong> <p class="body">Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam cumque quaerat rem quia veniam exercitationem, commodi numquam omnis! Non placeat perspiciatis nulla illum cumque ad natus asperiores fuga. Facere, dignissimos.</p> </div> </template> <script> export default { mounted() { console.log('Component mounted.') } } </script> <style> .user { font-weight: 800; } .body { margin-bottom: 0; white-space: pre-wrap; } .message { border-bottom: 1px solid #000000 } .self { background-color: #f0f0f0; padding: 10px; } </style>
من یک پیام آزمایشی را در برنامه چت با لاراول و Vuejs نوشتم. ظاهر برنامه باید مطابق زیر باشد.
همان طور که می بینید یک کلاس به نام self که یک کلاس شرطی است، داریم. از این کلاس برای تمایز پیام های کاربرانی که به سیستم لاگین کرده اند با پیام های سایر کاربران استفاده میکنیم. این کار باید بصورت خودکار انجام بگیرد.
داخل فایل UserComponnent.vue کلاس ها و استایل های زیر را اضافه کنید تا برنامه چت با لاراول و Vuejs از نظر ظاهری حداقل استاندارد را داشته باشد.
من این کامپوننت را برای یک کاربر آزمایشی ایجاد میکنم.
// UserComponent.vue <template> <div class="col-md-4"> <div class="card"> <div class="card-header">Users</div> <div class="card-body"> <div class="users"> <a href="#">Krunal</a> </div> </div> </div> </div> </template> <script> export default { mounted() { console.log('Component mounted.') } } </script> <style> .users { background-color: #fff; border-radius: 3px; } </style>
یک کنترلر با نام MessageController با استفاده از دستور زیر ایجاد کنید.
php artisan make:controller MessageController
حال فایل web.php را باز کرده و روت های (Routes) زیر را در آن تعریف نمایید.
// web.php Route::get('/message', 'MessageController@index')->name('message');
داخل MessageController یک متد index تعریف میکنیم. این متد یک آبجکت json بر می گرداند. به عبارت دیگر خروجی این متد برای کار با api و در نهایت داده ی json است.
تمام پیام های ما داخل این آبجکت json ذخیره شده است.
// MessageController.php <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Message; class MessageController extends Controller { public function index() { $messages = Message::with(['user'])->get(); return response()->json($messages); } }
ما از روتی که در بالا تعریف کردیم برای ارسال یک درخواست شبکه از یک کامپوننت vue توسط Axios Api استفاده میکنیم.
در روت بالا ما توسط Api Axios یک درخواست شبکه را از یک کامپوننت vue ارسال کردیم و در پاسخ، تمام پیام ها را دریافت و آنها را نمایش می دهیم.
حال ما باید Axios را برای ارسال یک درخواست Ajax یا درخواست شبکه به سرور لاراول و بازیابی پیام ها و نمایش آنها به کاربران، پیکربندی کنیم.
ما درخواست get را داخل فایل chatMessageComponnent.vue می نویسیم.
// ChatMessageComponent.vue <template> <div class="message-area"> <message-component></message-component> </div> </template> <script> export default { data() { return { messages: [] } }, mounted() { axios.get('/message').then((response) => { this.messages = response.data; }); } } </script> <style> .message-area { height: 400px; max-height: 400px; overflow-y: scroll; padding: 15px; border-bottom: 1px solid #eee; } </style>
موقعی که کامپوننت آماده شد، یک درخواست از نوع Ajax به سرور ارسال می کنیم و یک پاسخ دریافت می کنیم. سپس این پاسخ را به پروپرتی message نسبت می دهیم.
حال باید پیام ها را به MessageComponent پاس بدهیم. این کامپوننت مسئول نمایش همه پیام ها است.
سپس کدهای زیر را داخل template در فایل chatMessageComponnent.vue می نویسیم.
// ChatMessageComponent.vue <template> <div class="message-area"> <message-component v-for="message in messages" :key="message.id" :message="message"> </message-component> </div> </template>
حال باید پروپرتی message را به فایل messageComponnent.vue پاس بدهیم.
// MessageComponent.vue <template> <div class="message self"> <strong class="user">{{ message.user.name }}</strong> <p class="body">{{ message.body }}</p> </div> </template> <script> export default { props: ['message'] } </script>
من در این فایل از هیچ استایلی استفاده نکردم. اما شما میتوانید در صورت تمایل به آن استایل هم اضافه کنید.
هم اکنون هیچ پیامی در دیتابیس نداریم، اگر پیامی در دیتابیس ذخیره شود میتوانیم همه پیام ها را در اینجا ببینیم.
ما در فرم هیچ دکمه ارسال یا submit قرار ندادیم و هر زمان که کاربر دکمه Enter را فشار داد، پیام به سرور ارسال می شود.
ابتدا، هنگام ارسال یک پیام باید رابط کاربری بصورت بلادرنگ خودش را بروزرسانی کند.
برای اینکار ما به تعدادی رویداد نیاز داریم که به برنامه Vue.js مان بگوید که پیام جدید دریافت شده است، لطفا رابط کاربری را بروزرسانی کن.
یک فایل به نام event.js را داخل فولدر js ایجاد کنید و کدهای زیر را در آن بنویسید.
// event.js import Vue from 'vue'; export default new Vue();
حال باید پیام ها را در برنامه چت با لاراول و Vuejs به آرایه message اضافه کنیم. برای اینکار به یک پیام موقت که شامل پروپرتی های زیر است، نیاز داریم:
هنگامی که کاربر روی دکمه Enter کلیک کرد، باید یک آبجکت موقت ایجاد و آن را به یک رویداد پاس بدهیم و سپس از طریق کامپوننت chatMessageComponnent آن رویداد را تعریف کنیم.
در قدم بعد آبجکتی که به یک رویداد پاس داده شده بود را گرفته و آن را به آرایه message اضافه می کنیم.
سپس vue.js به طور خودکار تغییرات کامپوننت messageComponnent را شناسایی کرده و سپس رابط کاربری را بروزرسانی می کند.
دلیل استفاده از یک رویداد به این خاطر است که ما یک داده در کامپوننت vue.js داریم و می خواهیم این داده را به یک کامپوننت vue.js دیگر پاس دهیم.
حالا من کدنویسی فایل chatFormComponnent را تکمیل می کنم. این فایل یک رویداد که شامل یک آبجکت موقت است را بر می گرداند.
// ChatFormComponent.vue <template> <form class="form"> <textarea id="body" cols="28" rows="5" class="form-input" @keydown="typing" v-model="body"> </textarea> <span class="notice"> Hit Return to send a message </span> </form> </template> <script> import Event from '../event.js'; export default { data() { return { body: null } }, methods: { typing(e) { if(e.keyCode === 13 && !e.shiftKey) { e.preventDefault(); this.sendMessage(); } }, sendMessage() { if(!this.body || this.body.trim() === '') { return } let messageObj = this.buildMessage(); Event.$emit('added_message', messageObj); this.body = null; }, buildMessage() { return { id: Date.now(), body: this.body, selfMessage: true, user: { name: 'Krunal' } } } } } </script> <style> .form { padding: 8px; } .form-input { width: 100%; border: 1px solid #d3e0e9; padding: 5px 10px; outline: none; } .notice { color: #aaa } </style>
در آبجکت موقت من نام کاربری را بصورت دستی نوشتم، اما در برنامه های واقعی باید نام کاربری که به سیستم لاگین کرده است را بنویسیم.
حال باید این رویداد را داخل کامپوننت chatMessage.vue بگیریم.
// ChatMessageComponent.vue <template> <div class="message-area"> <message-component v-for="message in messages" :key="message.id" :message="message"> </message-component> </div> </template> <script> import Event from '../event.js'; export default { data() { return { messages: [] } }, mounted() { axios.get('/message').then((response) => { console.log(response.data); this.messages = response.data; }); Event.$on('added_message', (message) => { this.messages.unshift(message); }); } } </script> <style> .message-area { height: 400px; max-height: 400px; overflow-y: scroll; padding: 15px; border-bottom: 1px solid #eee; } </style>
داخل فایل view > layout > app.blade.php کدهای زیر را در بین تگ <head> بنویسید.
<script> window.Laravel = {!! json_encode([ 'csrfToken'=> csrf_token(), 'user'=> [ 'authenticated' => auth()->check(), 'id' => auth()->check() ? auth()->user()->id : null, 'name' => auth()->check() ? auth()->user()->name : null, ] ]) !!}; </script>
در کد بالا در صورتی که کاربر به سیستم لاگین کرده باشد، نام کاربری آن را گرفته و به متغیر سراسری Laravel نسبت می دهیم. به این وسیله می توانیم در داخل کامپوننت vue.js به نام کاربری دسترسی داشته باشیم. هنگامی که یک آبجکت پیام موقت ایجاد کنیم، می توانیم نام پروپرتی را به پروپرتی نام کاربری Laravel نسبت بدهیم و در انتها نام کاربری که لاگین کرده است را خواهیم دید.
حال کدهای زیر را داخل فایل chatMessageComponnent می نویسیم.
// ChatMessageComponent.vue <template> <form class="form"> <textarea id="body" cols="28" rows="5" class="form-input" @keydown="typing" v-model="body"> </textarea> <span class="notice"> Hit Return to send a message </span> </form> </template> <script> import Event from '../event.js'; export default { data() { return { body: null } }, methods: { typing(e) { if(e.keyCode === 13 && !e.shiftKey) { e.preventDefault(); this.sendMessage(); } }, sendMessage() { if(!this.body || this.body.trim() === '') { return } let messageObj = this.buildMessage(); Event.$emit('added_message', messageObj); this.body = null; }, buildMessage() { return { id: Date.now(), body: this.body, selfMessage: true, user: { name: Laravel.user.name } } } } } </script> <style> .form { padding: 8px; } .form-input { width: 100%; border: 1px solid #d3e0e9; padding: 5px 10px; outline: none; } .notice { color: #aaa } </style>
در نهایت کدهای ChatMessageComponent.vue باید مانند زیر باشد
// ChatMessageComponent.vue <template> <div class="message-area" ref="message"> <message-component v-for="message in messages" :key="message.id" :message="message"> </message-component> </div> </template> <script> import Event from '../event.js'; export default { data() { return { messages: [] } }, mounted() { axios.get('/message').then((response) => { console.log(response.data); this.messages = response.data; }); Event.$on('added_message', (message) => { this.messages.unshift(message); if(message.selfMessage) { this.$refs.message.scrollTop = 0; } }); } } </script> <style> .message-area { height: 400px; max-height: 400px; overflow-y: scroll; padding: 15px; border-bottom: 1px solid #eee; } </style>
حال اگر کاربری که لاگین کرده، یک پیامی را ارسال کند، اسکرولر به سمت بالا می رود.
مسیر زیر را برای ذخیره پیام ها تعریف کنید.
// web.php Route::post('/message', 'MessageController@store')->name('message.store');
حال متد store() را برای ذخیره داده ها در پایگاه داده MySQL، تعریف می کنیم.
// MessageController.php public function store(Request $request) { $message = $request->user()->messages()->create([ 'body' => $request->body ]); return response()->json($message); }
سپس داخل فایل chatFormComponnent کد زیر را برای ارسال یک درخواست Axios به روتی که تعریف کردیم، می نویسم و بدنه پیام ها را به عنوان یک پارامتر به آن پاس می دهیم.
// ChatFormComponent.vue sendMessage() { if(!this.body || this.body.trim() === '') { return } let messageObj = this.buildMessage(); Event.$emit('added_message', messageObj); axios.post('/message', { body: this.body.trim() }).catch(() => { console.log('failed'); }); this.body = null; },
فایل را ذخیره و به آدرس http://localhost:8000/chat بروید.
یک متن را در textbox وارد کرده و دکمه Enter را بزنید. می بینید که یک پیام بصورت بلادرنگ ظاهر می شود، که این همان پیام موقت است.
حال صفحه را رفرش کنید. و ببینید که آیا این پیام هنوز هم وجود دارد یا نه؟ اگر وجود داشته باشد یعنی با موفقیت پیام را ذخیره کردیم.
ما از یک سرویس Pusher برای پیام های بلادرنگ در برنامه چت با لاراول و Vuejs استفاده می کنیم. ابتدا باید Broadcast_driver که داخل فایل .env وجود دارد را تغییر دهیم.
// .env BROADCAST_DRIVER=pusher
سپس در فایل config > app.js خط زیر را از حالت کامنت خارج کنید.
App\Providers\BroadcastServiceProvider::class,
در قدم بعد باید یک برنامه pusher ایجاد کنیم. برای اینکار به آدرس http://pusher.com رفته و یک اکانت ایجاد کنید. بعد از اینکه به اکانت تان لاگین کردید به آدرس http://dashboard.pusher.com هدایت می شوید.
در این صفحه یک برنامه ایجاد کنید و سپس به بخش App Keys بروید. در این بخش تمام اطلاعات را گرفته و داخل فایل .env در برنامه لاراول تان قرار دهید.
// .env PUSHER_APP_ID=your app id PUSHER_APP_KEY=your app key PUSHER_APP_SECRET=your app secret PUSHER_APP_CLUSTER=your cluster
حال باید پکیج pusher php server را توسط کامپوزر نصب کنیم.
composer require pusher/pusher-php-server
همچنین به وابستگی های زیر هم برای بخش front-end سایت نیاز داریم:
هر دو اینها را با دستور زیر نصب کنید
npm install pusher-js laravel-echo --save
حال فایل assets > js > bootstrap.js را باز کرده و خط زیر را از حالت کامنت خارج کنید. بصورت پیش فرض این خطوط کامنت شده اند.
// bootstrap.js 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 });
حال داخل فایل .env متغیرهایی شبیه زیر داریم.
// .env MIX_PUSHER_APP_KEY=your pusher key MIX_PUSHER_APP_CLUSTER=your cluster
در کد بالا، در قسمت MIX_PUSHER_KEY، public Key ایی که از سایت pusher گرفتید را وارد کنید، همانند قسمت PUSHER_APP_KEY.
همچنین در قسمت MIX_PUSHER_APP_CLUSTER نام clusterتان را که از سایت pusher گرفتید را وارد نمایید. در نهایت فایل را ذخیره کرده و ترمینال را ببینید اگر پیام خطایی نداشتید یعنی کار را به درستی انجام داده اید.
ابتدا داخل فایل routes > channel.php کدهای زیر را قرار دهید.
// channels.php <?php Broadcast::channel('chat', function ($user) { return [ 'id' => $user->id, 'name' => $user->name ]; });
در کد بالا ما یک کانال (channel) سراسری ایجاد کردیم که یک آبجکت user را بر میگرداند. حال اگر یک کاربر به برنامه چت با لاراول و Vuejs ملحق شود، ما باید رابط کاربری vue.js مان را بروزرسانی کنیم. بهتر است که با استفاده از یک رویداد اینکار را انجام دهیم. سپس هنگامی که یک کاربر جدید به چت ملحق شد، ما یک رویداد را ارسال می کنیم و بخش front-end سایت این رویداد را گرفته و رابط کاربری را بروزرسانی می کند.
داخل فولدر resource > assets > js یک فایل به نام echo.js را ایجاد می کنیم.
این فایل تمام رویدادها را گرفته و به vue.js اطلاع می دهد که رابط کاربری را بروزرسانی کند.
// echo.js Echo.join('chat') .here(users => { console.log(users); }) .joining(user => { console.log(user); }) .leaving(user => { console.log(user); })
سپس این فایل را داخل فایل resource > assets > js > bootstrap.js، با استفاده از دستور require مورد استفاده قرار دهید. من در انتهای فایل اینکار را انجام دادم.
// bootstrap.js window._ = require('lodash'); window.Popper = require('popper.js').default; try { window.$ = window.jQuery = require('jquery'); require('bootstrap'); } catch (e) {} window.axios = require('axios'); window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; let token = document.head.querySelector('meta[name="csrf-token"]'); if (token) { window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content; } else { console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token'); } 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 }); require('./echo');
حال، هنگامی که کاربری به چت ملحق شود یا چت را ترک کند ما باید یک رویداد را منتشر کنیم.
داخل فایل echo.js کدهای زیر را بنویسید.
// echo.js import Event from './event'; Echo.join('chat') .here(users => { Event.$emit('users.here', users); }) .joining(user => { Event.$emit('users.joined', user); }) .leaving(user => { Event.$emit('users.left', user); })
داخل فایل UserComponent.vue کدهای زیر را بنویسید. کدهای زیر را برای دریافت رویدادهای منتشر شده و تغییر دادن رابط کاربری می نویسیم.
// UserComponent.vue <template> <div class="col-md-4"> <div class="card"> <div class="card-header">Users</div> <div class="card-body"> <div class="users" v-for="user in users" :key="user.id"> <a href="#">{{ user.name }}</a> </div> </div> </div> </div> </template> <script> import Event from '../event.js'; export default { data() { return { users: [] } }, mounted() { Event.$on('users.here', (users) => { this.users = users; }) .$on('users.joined', (user) => { this.users.unshift(user); }) .$on('users.left', (user) => { this.users = this.users.filter(u => { return u.id != user.id }); }); } } </script> <style> .users { background-color: #fff; border-radius: 3px; } </style>
حال اگر یک کاربر جدید به برنامه لاراول مان وارد شود و به آدرس http://localhost:8000/chat برود، می توانیم نام آن را در قسمت کاربران ببینیم.
هنگامی که کاربری چت را ترک کند، آرایه users دوباره بروزرسانی می شود و ما می توانیم کاربران باقی مانده را ببینیم.
حال تنها نکته ای که باقی مانده، ارسال و دریافت پیام های بلادرنگ توسط pusher در برنامه چت با لاراول و Vuejs است.
در قسمت back-end، باید یک کلاس event ایجاد کنیم.
هنگامی که یک پیام جدیدی ایجاد شود، این کلاس یک رویداد را ارسال و دریافت می کند.
به ترمینال رفته و کدهای زیر را برای ایجاد یک رویداد وارد کنید.
php artisan make:event MessageCreated
حال هنگامی که یک پیامی را ذخیره کردیم، باید این پیام را به channel ارسال کنیم.
برای اینکار کدهای زیر را در متد store() کنترلر MessageController.php بنویسید.
// MessageController.php <?php namespace App\Http\Controllers; use App\Message; use Illuminate\Http\Request; use App\Events\MessageCreated; class MessageController extends Controller { public function index() { $messages = Message::with(['user'])->get(); return response()->json($messages); } public function store(Request $request) { $message = $request->user()->messages()->create([ 'body' => $request->body ]); broadcast(new MessageCreated($message)) ->toOthers(); return response()->json($message); } }
داخل فایل MessageController.php باید آرگومان ها را گرفته و به channel پاس دهیم.
// MessageCreated.php <?php namespace App\Events; use App\Message; 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 MessageCreated implements ShouldBroadcast { use Dispatchable, InteractsWithSockets, SerializesModels; public $message; /** * Create a new event instance. * * @return void */ public function __construct(Message $message) { $this->message = $message; } public function broadcastWith() { $this->message->load(['user']); return [ 'message' => array_merge($this->message->toArray(), [ 'selfMessage' => false ]) ]; } /** * Get the channels the event should broadcast on. * * @return \Illuminate\Broadcasting\Channel|array */ public function broadcastOn() { return new PresenceChannel('chat'); } }
برای اینکار، ابتدا یک اینترفیس برای برنامه چت با لاراول و Vuejs به نام shouldBroadCast را پیاده سازی می کنیم. سپس، نام آن را از privateChannel به presenceMessage تغییر داده و نام “chat” را به کانال مان ارسال می کنیم.
در قدم بعد، پیام ها را از یک کنترلر گرفته و به متد broadcastWith() می فرستیم.
حال داخل فایل echo.js ما یک کد برای دریافت رویدادها می نویسیم.
// echo.js import Event from './event'; Echo.join('chat') .here(users => { Event.$emit('users.here', users); }) .joining(user => { Event.$emit('users.joined', user); }) .leaving(user => { Event.$emit('users.left', user); }) .listen('MessageCreated', (data) => { Event.$emit('added_message', data.message); });
بعد از دریافت رویداد، یک رویداد دیگر منتشر و این رویداد توسط کامپوننت chatMessageComponent.vue دریافت می شود.
// ChatMessageComponent.vue <template> <div class="message-area" ref="message"> <message-component v-for="message in messages" :key="message.id" :message="message"> </message-component> </div> </template> <script> import Event from '../event.js'; export default { data() { return { messages: [] } }, mounted() { axios.get('/message').then((response) => { this.messages = response.data; }); Event.$on('added_message', (message) => { this.messages.unshift(message); if(message.selfMessage) { this.$refs.message.scrollTop = 0; } }); } } </script> <style> .message-area { height: 400px; max-height: 400px; overflow-y: scroll; padding: 15px; border-bottom: 1px solid #eee; } </style>
در انتها برای تست برنامه چت با لاراول و Vuejs مراحل زیر را اجرا کنید:
سورس این برنامه را می توانید از سایت گیت هاب دریافت کنید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.