Programming Real-Time Web Applications With TALL Stack
Yoram Kornatzky
Posted on August 17, 2022
Real-Time Web Applications
Real-time web applications reflect immediately to each user the concurrent actions of other users.
Widely used real-time applications include:
- Auctions
- Chat systems
- Shared whiteboards
- Collaborative document editors
- Online education
The TALL Stack
The TALL stack is a prominent combined front-end and backend framework in the PHP world.
The stack:
The Triggering Action
Action in the Blade template of a Livewire component is triggered on a button click,
<input name="bid_price" wire:model="bid_price"/>
<button wire:click="bid()/>
Which invokes a function in the component,
namespace App\Http\Livewire;
use Livewire\Component;
class Bidder extends Component
{
public float $bid_price;
public float $price;
public function bid()
{
}
}
The Connecting Pipes
By broadcasting events in Laravel, the actions of users are propagated to other users.
So say we have an event that is broadcast when a user sends a bid,
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use App\Models\Auction;
use App\Models\User;
class LiveBid implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(
private Auction $auction,
private $item,
private $user,
private float $bid_price,
)
{
//
}
/**
* Get the data to broadcast.
*
* @return array
*/
public function broadcastWith()
{
return [
'item' => $this->item,
'type' => $this->type,
'bid' => $this->bid_price,
'user' => $this->user,
];
}
}
Using:
use App\Events\LiveBid;
broadcast(new LiveBid(
$this->auction,
$this->item,
$this->user,
$bid_price
))->toOthers();
How the Events Flow
Using Laravel Websockets, broadcast events are sent to Livewire components.
Components list the events they listen to,
namespace App\Http\Livewire;
use Livewire\Component;
class Bidder extends Component
{
public float $price;
protected function getListeners()
{
return [
"echo:auction.{$this->auction->id},LiveBid"
=> 'live_price_notification',
];
}
}
Where we have a channel per auction,
"echo:auction.{$this->auction->id},LiveBid"
with many auctions running in parallel.
On receiving the event, the listener calls the assigned function with the data that was broadcast as an array,
public function live_price_notification($data)
{
// update price
$this->price = $data['price'];
}
Dynamic Update to the Front-End
So for the Bidder component, its Blade template, bidder.blade.php is automatically dynamically updated by Livewire once the price property is updated,
Price: {{ $price }} EUR
Summing up, the flow is,
Livewire -> Livewire
Where no JavaScript was needed.
This is the more straightforward case.
When We Need JavaScript
In a whiteboard application, we must use JavaScript to listen to user actions, such as moving the mouse, as they are purely browser events. Consequently, to reflect the actions of other users, we must render things at the browser level, such as pointer positions on the screen, for which we must use JavaScript.
The TALL stack uses the lightweight Alpine.js framework to do the browser lifting.
To integrate the actions from the browser into the Livewire component, we use Alpine.js Livewire.emit,
Livewire.emit('MouseMoved', x, y)
To dynamically update the front-end, say the position on the canvas, we use in the Livewire component,
$this->dispatchBrowserEvent('SetPointerPosition', [
'x' => $x, 'y' => $y
]);
Summing up, the flow is,
Alpine.js -> Livewire -> Livewire -> Alpine.js
A Recap
For PHP lovers, the TALL stack supplies a superb way to program real-time web applications with a pure PHP playbook.
Posted on August 17, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.