laravel广播 - laravel-echo-server服务端 - laravel-echo客户端的交互过程及原理
交互图
!!! 事先说明 :
①本文章是以redis作为驱动来解读的。
② 文章中的代码注释一定看,介绍都在注释中!!!
此图如有侵权,通知我删除 ;
通过上图可以看得出来,laravel广播事件与前端是没有直接交互的。
大概流程就是 :laravel广播事件通过redis的发布订阅功能发布频道,laravel-echo-server链接redis订阅频道获取发布的数据,通过socket主动推送给laravel-echo,前端渲染。
现在我们就跟着这个流程读一下源码吧!
第一步:laravel广播发布数据到redis中。
(1)进入广播服务提供者类所在文件夹中 :\vendor\laravel\framework\src\Illuminate\Broadcasting
(2) 写一个发送广播事件的demo
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 PrivateMessageEvent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(){
}
/**
* 获取广播事件对应的频道。
*/
public function broadcastOn()
{
return new PrivateChannel('PrivateMessage.' . $this->admin_id );
}
/**
* 自定义广播数据
* @return mixed
*/
public function broadcastWith()
{
return $this->data;
}
}
// 发布广播事件
broadcast(new PrivateMessageEvent();
(3) 进入 BroadcastEvent.php 广播事件类找 handle 方法
/**
* 创建一个新的作业处理程序实例。
* @param mixed $event 广播事件类实例
*/
public function __construct($event)
{
$this->event = $event;
}
/**
* 处理排队的作业。
* @param \Illuminate\Contracts\Broadcasting\Broadcaster $broadcaster
*/
public function handle(Broadcaster $broadcaster)
{
// 主要看是否自定义广播事件名称,没有则使用类名
$name = method_exists($this->event, 'broadcastAs')
? $this->event->broadcastAs() : get_class($this->event);
// 发布广播数据到redis中
$broadcaster->broadcast(
// 参1: 获取广播的频道名
Arr::wrap($this->event->broadcastOn()),
// 参2:事件名
$name,
// 参3:获取自定义广播数据 / 广播类的公共属性 / socket
$this->getPayloadFromEvent($this->event)
);
}
(4)追一下这个方法:getPayloadFromEvent($this->event) 发现它会返回 (自定义广播数据 / 广播类的公共属性 / socket)
/**
* 获取给定事件的有效负载。
*
* @param mixed $event 广播事件类对象
* @return array
*/
protected function getPayloadFromEvent($event)
{
// 判断事件类中是否有broadcastWith方法
if (method_exists($event, 'broadcastWith')) {
// 返回自定义载核 以及 对象中叫socket的属性值
return array_merge(
$event->broadcastWith(), ['socket' => data_get($event, 'socket')]
);
}
$payload = [];
foreach ((new ReflectionClass($event))->getProperties(ReflectionProperty::IS_PUBLIC) as $property) {
$payload[$property->getName()] = $this->formatProperty($property->getValue($event));
}
unset($payload['broadcastQueue']);
// 返回所有公共属性
return $payload;
}
(5)返回刚才的地方再追一下 $broadcaster->broadcast() 方法,然后向下找到我们要使用的redis驱动类。进入!
/**
* 广播给定事件。
*
* @param array $channels 广播对应频道名称
* @param string $event 广播事件名称
* @param array $payload 广播数据
* @return void
*/
public function broadcast(array $channels, $event, array $payload = [])
{
// 建立redis链接
$connection = $this->redis->connection($this->connection);
// 写入redis的数据 : 事件名 、 载核 、 socket
$payload = json_encode([
'event' => $event,
'data' => $payload,
'socket' => Arr::pull($payload, 'socket'),
]);
foreach ($this->formatChannels($channels)