Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

avrahamm's avatar

broadcasting/sending notification to different channels dynamically

Hello! I use Pusher and laravel-echo for notifications. I have several types of user roles should get different notifications - each role has its own channel. I saw App.User-{id} channel idea - yet it seems to me not efficient to notify each user, as I can notify once to role-channel for several users at once. Yet, I have difficulty with dynamically setting broadcasting channels, role channels in my case. I want to be able conditionally set specific role channel by type of event/notifications arrives. Is it possible? Thanks

0 likes
4 replies
avrahamm's avatar

After reading more docs, I find it is easier setting broadcasting channels for Event with broadcastOn than with notifications.

Tippin's avatar
Tippin
Best Answer
Level 13

@avrahamm I do exactly that, but I go one step further. I crafted my own BroadcastBroker and have each broadcast event class extend an abstract class I made, so I can dynamically set channels fluently.

Abstract Broadcast Event

abstract class BaseBroadcast implements BroadcastEvent, ShouldBroadcastNow
{
    use InteractsWithSockets,
        SerializesModels;

    protected array $resource;

    protected array $channels;

    abstract public function broadcastAs(): string;

    public function broadcastOn(): array
    {
        return $this->channels;
    }

    public function broadcastWith(): array
    {
        return $this->resource;
    }

    public function setResource(array $resource): self
    {
        $this->resource = $resource;

        return $this;
    }

    public function setChannels(array $channels): self
    {
        $this->channels = $channels;

        return $this;
    }
}

Then my broadcast event class only needs to extend my abstract above, and define the broadcastAs (not a fan of it using full class namespace)

Broadcast Event

class NewMessageBroadcast extends BaseBroadcast
{
    public function broadcastAs(): string
    {
        return 'new.message';
    }
}

My broker handles generating the channels on demand, based on which methods I chain.

Broker interface

interface BroadcastDriver
{
    public function toAllInThread(Thread $thread): self;

    public function toOthersInThread(Thread $thread): self;

    public function toSelected(Collection $recipients): self;

    public function to($recipient): self;

    public function toPresence($entity): self;

    public function toManyPresence(Collection $presence): self;

    public function with(array $with): self;

    public function broadcast(string $abstract): void;
}

Based on the TO method I call, I will generate the array of channels on demand, eg:

$this->broadcaster
    ->to($user)
    ->with($message->toArray())
    ->broadcast(NewMessageBroadcast::class);

So my BroadcastBroker takes what was given above, and creates all the private/presence channels, chunking at 100 (pusher limit per single broadcast)

public function broadcast(string $abstract): void
{
    if (! is_null($this->recipients)
        && $this->recipients->count()
        && is_subclass_of($abstract, BaseBroadcast::class)) {
        if ($this->usingPresence) {
            $this->generatePresenceChannels()->each(fn (Collection $channels) => $this->executeBroadcast($abstract, $channels));
        } else {
            $this->generatePrivateChannels()->each(fn (Collection $channels) => $this->executeBroadcast($abstract, $channels));

            $this->executePushNotify($abstract);
        }
    }
}

private function generatePrivateChannels(): Collection
{
    return $this->recipients
        ->map(fn ($recipient) => $this->generatePrivateChannel($recipient))
        ->filter()
        ->uniqueStrict()
        ->chunk(100);
}

private function generatePrivateChannel($recipient): ?string
{
    //private-messenger.user.{id}
    if ($recipient instanceof Ownerable
        || $recipient instanceof MessengerProvider) {
        return new MessengerPrivateChannel($recipient);
    }

    return null;
}

private function executeBroadcast(string $abstractBroadcast, Collection $channels): void
{
    try {
        broadcast(
            app($abstractBroadcast)
                ->setResource($this->with)
                ->setChannels($channels->values()->toArray())
        );
    } catch (Throwable $e) {
        // Should a broadcast fail, we do not want to
        // halt further code execution. Continue on!
    }
}

Hope this may give you some possible ideas to make your life easier 😁

1 like
Tippin's avatar

@avrahamm Of course, my example is missing some context. But in general, I just made a wrapper/flow so I can easily control what data and to whom my broadcast go to. If you have any questions however, feel free to ask. (I do use my own custom broadcast builder as above compared to using built in model broadcasting or notification broadcast channel...I like the control)

1 like

Please or to participate in this conversation.