There is no license information available for the latest version (v0.1.0) of this package.

Uses broadcasting simplified

Installs: 5

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 1

Forks: 0

Open Issues: 0



v0.1.0 2023-01-20 23:12 UTC

This package is auto-updated.

Last update: 2024-05-21 02:22:48 UTC


Keep multiple clients & your database in sync!

Designed for LENKRAD, but agnostic enough to be used in any framework.

Make any database a live-database


1. install package

composer require

2. Add required ENV-variables to your .env

  • JWT_SECRET (your encryption key)
  • SOCKET_SERVER_PORT (e.g. 3000)
  • SOCKET_SERVER_URL (e.g. "localhost")

3. Add the following script to your composer.json

"scripts": {
  "install-socket": "NeoanIo\\MarketPlace\\Broadcast\\NpmHandler::package"

4. Run said script

composer run install-socket

5. Install required node packages

yarn install or npm install

6. Test socket-server

yarn sockert-server or npm run socket-server


Client functionality

This package includes a client-library to automate synchronization with your database. In LENKRAD, you would typically expose the library via a route:


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
class Client implements Routable
    public function __invoke(): void
        // This will deliver a generated JS-file 

And then use it in whatever capacity you need at the front-end:

<script type="module" async>
    import {SyncEntity, HTMLBinder} from "/client.js";


Two things need to happen in order for the synchronization to work. Firstly, a returned entity must expose the socket-information (including auth). We can achieve this with ForClient::wrapEntity. A typical API-route could look like this:


namespace App\Note;

use Neoan\Request\Request;
use Neoan\Routing\Attributes\Get;
use Neoan\Routing\Interfaces\Routable;
use NeoanIo\MarketPlace\Broadcast\ForClient;

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())


Next, we want to set a hook for whenever the model is written to. In LENKRAD, we can use the Model::afterStore method to achieve this. Our Note-model could look like this:


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
    public int $id;

    public string $content;

    // will fire whenever the model is saved to the database
    protected function afterStore(): void
        // this broadcasts updates to the socket server


We don't have to worry about any specific code in our update routes. Given the example, it could look like this:


namespace App\Note;

use Neoan\Request\Request;
use Neoan\Routing\Attributes\Put;
use Neoan\Routing\Interfaces\Routable;

class PutNote implements Routable
    public function __invoke(): NoteModel
        $find = NoteModel::get(Request::getParameter('id'));
        $find->content = Request::getInput('content');
        return $find->store();

Frontend usage

// 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


// or directly on the element-level

        property: 'content',
        event: 'blur'


The proxy-logic is based on a modified version of Sindre Sorhus' on-change. Make sure to leave a star ;-)