neoan.io / broadcast
该软件包最新版本(v0.1.0)没有可用的许可证信息。
使用简化版的socket.io广播
v0.1.0
2023-01-20 23:12 UTC
Requires
- neoan3-apps/stateless: ^2.0
- php-curl-class/php-curl-class: ^9.13
This package is auto-updated.
Last update: 2024-09-21 02:59:30 UTC
README
保持多个客户端与数据库同步!
专为 LENKRAD 设计,但足够通用,可在任何框架中使用。
使任何数据库都成为实时数据库
安装
1. 安装软件包
composer require neoan.io/broadcast
2. 将所需的ENV变量添加到您的.env文件中
- JWT_SECRET(您的加密密钥)
- SOCKET_SERVER_PORT(例如,3000)
- SOCKET_SERVER_URL(例如,"localhost")
3. 将以下脚本添加到您的composer.json中
... "scripts": { "install-socket": "NeoanIo\\MarketPlace\\Broadcast\\NpmHandler::package" } ...
4. 运行脚本
composer run install-socket
5. 安装所需的node软件包
yarn install
或 npm install
6. 测试socket服务器
yarn sockert-server
或 npm run socket-server
设置
客户端功能
此软件包包含一个客户端库,用于自动与数据库同步。在 LENKRAD 中,您通常会通过路由公开此库
<?php namespace App\Socket; use Neoan\Routing\Attributes\Get; use Neoan\Routing\Interfaces\Routable; use NeoanIo\MarketPlace\Broadcast\ForClient; // exposes the client-library to the path /client.js #[Get('/client.js')] class Client implements Routable { public function __invoke(): void { // This will deliver a generated JS-file ForClient::exposeClient(); } }
然后在前端使用所需的任何功能
<script type="module" async> import {SyncEntity, HTMLBinder} from "/client.js"; </script>
后端
为了让同步工作,需要发生两件事。首先,返回的实体必须公开socket信息(包括身份验证)。我们可以使用 ForClient::wrapEntity
来实现这一点。典型的API路由可能如下所示
<?php namespace App\Note; use Neoan\Request\Request; use Neoan\Routing\Attributes\Get; use Neoan\Routing\Interfaces\Routable; use NeoanIo\MarketPlace\Broadcast\ForClient; #[Get('/api/note/:id')] class GetNote implements Routable { public function __invoke(): array { // retrieving a single record $model = NoteModel::get(Request::getParameter('id')); // wrapping the record return ForClient::wrapEntity($model->toArray()) ->toRoom('notes') ->withId($model->id) ->broadcast(); } }
接下来,我们希望在模型被写入时设置一个钩子。在 LENKRAD 中,我们可以使用 Model::afterStore
方法来实现。我们的Note模型可能如下所示
<?php namespace App\Note; use NeoanIo\MarketPlace\Broadcast\Broadcast; use Neoan\Model\Attributes\IsPrimaryKey; use Neoan\Model\Attributes\Type; use Neoan\Model\Model; class NoteModel extends Model { #[IsPrimaryKey] public int $id; #[Type('MEDIUMTEXT')] public string $content; // will fire whenever the model is saved to the database protected function afterStore(): void { // this broadcasts updates to the socket server Broadcast::toChannel('notes') ->withId($this->id) ->withBody($this->toArray()) ->emit(); } }
我们不必在更新路由中担心任何特定的代码。根据示例,它可能如下所示
<?php namespace App\Note; use Neoan\Request\Request; use Neoan\Routing\Attributes\Put; use Neoan\Routing\Interfaces\Routable; #[Put('/api/note/:id')] class PutNote implements Routable { public function __invoke(): NoteModel { $find = NoteModel::get(Request::getParameter('id')); $find->content = Request::getInput('content'); return $find->store(); } }
前端使用
// taken from earlier example import {SyncEntity, HTMLBinder} from "/client.js"; // allow for programmatic updates on any change (without event) // careful: this produces a lot of traffic and is usually not necessary) let updateOnAnyChange = true; // SyncEntity grabs the wrapped entity via GET // (the PUT-request needs ot be in the same format) // SyncEntity returns a proxy triggering PUT-requests as needed, // and receiving updates via socket alike! let note = await SyncEntity('/api/note/1', updateOnAnyChange) // if `updateOnAnyChange` is true, every change will be broadcasted setTimeout(()=> { note.content += '!'; updateOnAnyChange = false; }, 1000) // however, we usually want to trigger on specific events const binder = new HTMLBinder(note) // e.g. on form submission binder.toForm('#my-form') // or directly on the element-level binder.toElements({ '#my-input':{ property: 'content', event: 'blur' } })
鸣谢
代理逻辑基于Sindre Sorhus修改的版本 on-change。请确保留下星标 ;-)