- Published on
Real-Time Application with Laravel
Laravel နဲ့ Real-Time application တစ်ခု ဖန်တီးပါမယ်။
Project Overview
အစိမ်းကောင်ကို နှိပ်ရင် အစိမ်းရောင် background ပြောင်းပြီး အနီကောင်ကို နှိပ်ရင် အနီရောင် background ပြောင်းမှာပါ။ တစ်ယောက်ယောက်က တစ်ခုခုနှိပ်တာနဲ့ အဲ့ page ကို ဖွင့်ထားတဲ့ device တိုင်းမှာ real time update ဖြစ်သွားမှာပါ။
ဒါက ကျတော်စက်မှာ browser ၂ခု နဲ့ စမ်းပြထားတာပါ။
Frontend
အရင်ဆုံး Laravel project တစ်ခု create လုပ်ပါမယ်။
composer create-project laravel/laravel real-time-app-with-laravel
ပြီးရင်တော့ Laravel Folio ကို install လုပ်ပါမယ်။
composer require laravel/folio
php artisan folio:install
Laravel Folio ဆိုတာကတော့ Laravel မှာ frontend ရေးရင် သုံးတဲ့ package တစ်ခုပါ။ resources/views/pages
folder မှာ hello.blade.php
ဆိုပြီး create လုပ်ရင် http://localhost:8000/hello
ဆိုပြီးခေါ်လို့ရမှာပါ။ hi.blade.php
ဆိုပြီး create လုပ်ရင် /hi
ဆိုပြီးခေါ်လို့ရမှာပါ။ အလွယ်ပြောရရင် Next.js လိုပါပဲ။
php artisan folio:page play
ဆိုပြီး page တစ်ခု create လုပ်ပါမယ်။ ဒါဆိုရင် resources/views/pages/play.blade.php
ဆိုပြီး file တစ်ခု create လုပ်သွားမှာပါ။
ပြီးရင်တော့ Laravel Volt ကို install လုပ်ပါမယ်။
composer require livewire/volt
php artisan volt:install
Laravel Volt က blade file တစ် file ထဲမှာပဲ PHP logic တွေ ရေးဖို့ အတွက်ပါ။
<?php
use function Livewire\Volt\{state};
state(['count' => 0]);
$increment = fn () => $this->count++;
?>
<div>
<h1>{{ $count }}</h1>
<button wire:click="increment">+</button>
</div>
ဉပမာ Volt နဲ့ ဒါမျိုးရေးလို့ရပါတယ်။ +
button ကိုနှိပ်ရင် count မှာ ၁ တိုးသွားပါမယ်။
ပြီးရင်တော့ layout
တစ်ခု create လုပ်ပါမယ်။
php artisan livewire:layout
ဒါဆိုရင် resources/views/components/layouts/app.blade.php
ဆိုပြီး file တစ်ခု create လုပ်သွားပါမယ်။ အဲ့ file မှာ အခုလိုရေးပါမယ်။
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title ?? 'Page Title' }}</title>
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
{{ $slot }}
</body>
</html>
ပြီးရင်တော့ TailwindCSS ကို install လုပ်ပါမယ်။
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
ပြီးရင် tailwind.config.js
မှာ အခုလိုပြင်ပါမယ်။
/** @type {import('tailwindcss').Config} */
export default {
content: [
"./resources/**/*.blade.php",
],
theme: {
extend: {},
},
plugins: [],
}
ဒါဆိုရင် စောနက create လုပ်ထားတဲ့ play.blade.php
မှာ ui စရေးလို့ရပါပြီ။
<x-layouts.app title="Play">
<div id="playground" class="w-full h-screen flex items-center" style="background: rgb(74 222 128)">
<div class="w-1/2">
<img class="cursor-pointer w-64 mx-auto" src="/earth_spirit.png"
alt="radiant">
</div>
<div class="w-1/2">
<img class="cursor-pointer w-64 mx-auto" src="/mars.png" alt="dire">
</div>
</div>
</x-layouts.app>
<x-layouts.app title="Play">
x-layouts.app က စောနက create လုပ်ထားတဲ့ app.blade.php
ကို extend လုပ်ထားတာပါ။
ဒါဆိုရင် /play
လို့ browser မှာခေါ်လိုက်ရင် ui ကို မြင်ရပါပြီ။
Backend
Laravel မှာ real-time event တွေကို Broadcasting ကနေ ရေးရပါတယ်။
php artisan install:broadcasting
ဆိုပြီး broadcasting ကို install လုပ်ပါမယ်။ Laravel Reverb ကို သွင်းမလားမေးရင် yes
လုပ်ပေးလိုက်ပါ။
Laravel Reverb ဆိုတာကတော့ websocket server တစ်ခုဖြစ်ပါတယ်။ ပြီးတော့ သူ့ကို pusher client တွေနဲ့ ချိတ်သုံးလို့ရပါတယ်။ ဒီနေရာမှာ တစ်ခုသေချာရှင်းလင်းချင်တာက pusher client သုံးတယ်ဆိုတာ pusher ကို ဝယ်သုံးတာမဟုတ်ပါဘူး pusher sdk ကိုပဲသုံးတာတာ host က laravel reverb host ကို သုံးရမှာပါ။ Laravel Reverb ကိုယ်တိုင်က pusher server သဘောပါ။
REVERB_APP_ID=286585
REVERB_APP_KEY=ns5vuegxbudmxyrdyfnb
REVERB_APP_SECRET=zdveddmzanu54wsqw7ad
REVERB_HOST="localhost"
REVERB_PORT=8080
REVERB_SCHEME=http
ဒီ key တွေကို pusher client မှာထည့်ပြီး Laravel Reverb နဲ့ ချိတ်လို့ရပါတယ်။ ကိုယ်ကြိုက်သလိုလည်း .env
မှာပြင်လို့ရပါတယ်။ ဒီဟာကို နောက်ဆုံးမှာ pusher js သုံးပြီး pure html နဲ့ ရေးပြပါမယ်။
ပြီးရင်တော့ event တစ်ခု create လုပ်ပါမယ်။
php artisan make:event CharacterUpdated
ဒါဆိုရင် app/Events/CharacterUpdated.php
ဆိုပြီး file တစ်ခု create လုပ်သွားပါတယ်။
<?php
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class CharacterUpdated implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(
public readonly string $character
) {
}
public function broadcastOn(): array
{
return [
new Channel('character'),
];
}
}
ဒီနေရာမှာ အရေးကြီးတာ ၂ခု ရှိပါတယ်။ ShouldBroadcast
ကို impletement လုပ်ထားရပါမယ်။ broadcastOn မှာ သုံးထားတဲ့ channel က Illuminate\Broadcasting\Channel
ဖြစ်ရပါမယ်။ ကျတော်တို့က auth မပါတဲ့ public channel တစ်ခုလုပ်မှာမို့ပါ။ character
ဆိုတာကတော့ ကျတော်တို့ရဲ့ channel name ပါ။
Integrate Websocket
php artisan reverb:start
ဆိုပြီး socket server ကို start လုပ်ပါမယ်။
ပြီးရင်
php artisan queue:listen
ဆိုပြီး Queue Worker ကို start လုပ်ပါမယ်။
ပြီးရင်တော့ စောနက play.blade.php
မှာ အခုလိုရေးပါမယ်။
<?php
use App\Events\CharacterUpdated;
$updateCharacter = function(string $character) {
CharacterUpdated::dispatch($character);
};
?>
<x-layouts.app title="Play">
@volt
<div id="playground" class="w-full h-screen flex items-center" style="background: rgb(74 222 128)">
<div class="w-1/2">
<img wire:click="updateCharacter('green')" class="cursor-pointer w-64 mx-auto" src="/earth_spirit.png"
alt="radiant">
</div>
<div class="w-1/2">
<img wire:click="updateCharacter('red')" class="cursor-pointer w-64 mx-auto" src="/mars.png" alt="dire">
</div>
</div>
@endvolt
<script type="module">
Echo.channel('character')
.listen('CharacterUpdated', (e) => {
if(e.character == 'green') {
document.getElementById('playground').style.background = 'rgb(74 222 128)';
} else if (e.character == 'red') {
document.getElementById('playground').style.background = 'rgb(248, 113, 113)';
}
});
</script>
</x-layouts.app>
php tag ထဲက code တွေက volt ကြောင့် အဲ့လိုလိုရေးလို့ရတာပါ။ updateCharacter
ဆိုတဲ့ function တစ်ခုရှိပါတယ်။ အဲ့ function ကိုခေါ်ရင် CharacterUpdated
event ကို dispatch လုပ်သွားမှာပါ။
@volt @endvolt
ထဲက code တွေက livewire anonymous component လို့ယူဆသွားမှာပါ။ wire:click="updateCharacter('green')"
က ပုံကို နှိပ်လိုက်ရင် updateCharacter function ကို green ဆိုတဲ့ value pass ပြီး ခေါ်သွားမှာပါ။
Echo.channel('character')
.listen('CharacterUpdated', (e) => {
if(e.character == 'green') {
document.getElementById('playground').style.background = 'rgb(74 222 128)';
} else if (e.character == 'red') {
document.getElementById('playground').style.background = 'rgb(248, 113, 113)';
}
});
ဒါကတော့ Laravel Echo နဲ့ရေးထားတာပါ။ သူက character channel ကို join ပြီး CharacterUpdated event ကို listen လုပ်ပါတယ်။ event ထဲက character က green
ဆိုရင် background ကို အစိမ်းပြောင်းပြီး red
ဆိုရင် အနီပြောင်းပါတယ်။ ဒါဆိုရင် CharacterUpdated ကို dispatch လုပ်တိုင်း /play
ကိုဖွင့်ထားတဲ့ device တိုင်းမှာ real-time background ပြောင်းနေမှာပါ။
Frontend ကို javascript framework ဒါမှမဟုတ် android app ကနေသုံးမယ်ဆိုရင် pusher ကို အခုလိုမျိုး ချိတ်လို့ရပါတယ်။
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div id="playground" class="w-full h-screen flex items-center" style="background: rgb(74 222 128)">
<div class="w-1/2">
<img class="cursor-pointer w-64 mx-auto" src="/earth_spirit.png" alt="radiant">
</div>
<div class="w-1/2">
<img class="cursor-pointer w-64 mx-auto" src="/mars.png" alt="dire">
</div>
</div>
<script src="https://js.pusher.com/8.0.1/pusher.min.js"></script>
<script>
var pusher = new Pusher('ns5vuegxbudmxyrdyfnb', {
appId: '286585',
secret: 'zdveddmzanu54wsqw7ad',
wsHost: '127.0.0.1',
wsPort: 8080,
forceTLS: false,
enabledTransports: ['ws'],
cluster: ''
});
var channel = pusher.subscribe('character');
channel.bind('App\\Events\\CharacterUpdated', (data) => {
if (data.character == 'green') {
document.getElementById('playground').style.background = 'rgb(74 222 128)';
} else if (data.character == 'red') {
document.getElementById('playground').style.background = 'rgb(248, 113, 113)';
}
});
</script>
</body>
</html>
ဒီဟာဆိုရင် pure html မှာ official pusher js နဲ့ ချိတ်ပြီး ရေးပြထားတာပါ။
Source code ကို ဒီမှာ ကြည့်လို့ရပါတယ်။ တခြား real-time POC ရေးထားတဲ့ project တစ်ခုကိုလည်း PyaeSoneAungRgn/realtime-reaction မှာ ကြည့်လို့ရပါတယ်။ သိချင်တာရှိရင်လည်း မေးလို့ရပါတယ် ခဗျာ။