After reading more docs, I find it is easier setting broadcasting channels for Event with broadcastOn than with notifications.
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
@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 😁
Please or to participate in this conversation.