-
Notifications
You must be signed in to change notification settings - Fork 10.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[8.x] More Convenient Model Broadcasting #37491
Conversation
This allows HasBroadcastChannel instances to be passed to broadcast routes.
Awesome, It's clean! |
* @param string $event | ||
* @return \Illuminate\Broadcasting\PendingBroadcast|null | ||
*/ | ||
protected function broadcastIfBroadcastChannelsExistForEvent($instance, $event) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@taylorotwell rather than having this (relatively) long method name, what would you think to having a method shouldBroadcastEvent($event)
and then using this in bootBroadcastsEvents
? E.g.
/**
* Boot the event broadcasting trait.
*
* @return void
*/
public static function bootBroadcastsEvents()
{
// code…
static::created(function ($model) {
if ($this->shouldBroadcastEvent(‘created’)) {
$this->broadcastCreated();
}
});
// more code…
}
I am currently working on a similar concept. The biggest problem is getting events for models in some form of relationship with another model. there are so many edge cases that a simple approach like yours currently means some models have to publish up to 20 events, and some models would have to do extensive database lookups to get all related models. To be honest, i still don‘t have an easy solution. |
@tpetry not sure if this would solve your issue, but sounds like a use case for |
Yeah, kind of. This is in concept the same solution as Taylor's approach: public function broadcastOn($event)
{
return [$this, $this->user];
} And as i said this concept is working, and i have a very similar solution live on an application. So @taylorotwell your approach is good and has been proven to work for us. But it's quite messy if you have models which are in a relationship with many models. Take for example updated user information, the user may be in a relationship with many models. I don't know of any solution solving this problem efficiently. There are databases like RethinkDB with a really good approach but all these approaches do not fit laravel's architecture. I just wanted to add one of my learnings i had when doing this in the hope someone has a brilliant idea to solve it. |
This PR adds some convenience features around broadcasting model state changes - inspired by @tonysm's work on his Turbo + Laravel integration.
Broadcasting Model Events
There is a new trait which can be added to models to allow for the easy broadcasting of model events (created, updated, trashed, restored, deleted). Before adding this feature I previously used to create event classes for these model events, such as a
DeploymentUpdated
event in Laravel Vapor. These events would then be marked asShouldBroadcast
. If you are using these events for other purposes in your application that approach works great but if you only need the event so that it can be broadcast to your frontend then the new EloquentBroadcastsEvents
trait can save you some boilerplate code.Usage of the trait looks like this:
Note that the
broadcastOn
method receives the event type (string ofcreated
,updated
, etc.) and returns the channels that the event should be broadcast on. Also note that you may simply return Eloquent instances as channels. Of course, you can still return fullChannel
orPrivateChannel
instances. This brings me to the next point...Eloquent model channel conventions... If you provide an Eloquent model instance in place a channel, the framework will automatically derive the channel name by calling the
broadcastChannel
method on the instance and create aPrivateChannel
instance for that channel string. All Eloquent models now implement theIlluminate\Broadcasting\HasBroadcastChannel
interface which dictates they implement this method. The base implementation will return a string channel name of the given format:App.Models.ModelName.{id}
where, of course, the actual model name and ID value are replaced in the string with their actual values.Often, you will want to broadcast an event on the model's own channel as well as its parent channel. For example, when a deployment is updated in Vapor, we broadcast that on the deployment's own channel as well as the environment's channel so that the list of deployments on the environment page can be live updated. With this new feature, you may simply return the model itself as well as the related model from the
broadcastOn
method:Of course, using the new PHP 8
match
construct, it is easy to disable broadcasting for certain events:Broadcast Routes
To leverage the automatic determination of broadcast channel routes for models when actually registering your channel authentication callbacks, you may now pass an Eloquent model instance or class name into the
Broadcast::channel
method:Listening For Model Events
Since there is not an actual event class that corresponds to these events that are automatically broadcasted, you need to listen to them slightly differently in Echo's client (I may improve this a bit in a separate PR). By convention, the events will be broadcast using the following convention:
ModelNameCreated
,ModelNameUpdated
, etc. Since these events are broadcast outside of any namespace, you must prefix them with a.
in Echo (I would like to improve this UX). The events will have a publicmodel
property where you can access the corresponding model attributes in your client side JavaScript application:So, listening to the events looks like the following: