How do I receive data when the client initially joins a channel?
Something like this:
Echo.channel('channel-name')
.onjoin(function (data) {
console.log(data) // Data received from server
})
As soon when the client joins, the server should respond with data, preferably with PHP.
Presence channels return information about the users in the channel at the time the client subscribes.
If you require other data from your server then you could send a post request to your server to get the information. You could invoke this in a pusher:subscription_succeeded binding so it occurs as soon as the subscription is established.
Edit:
.here will display the data per user connected, which is not what I want.
I thought presence channel was what I was looking for. https://laravel.com/docs/8.x/broadcasting#presence-channels
// Define channel
Broadcast::channel('channel-name', function () {
if (/* Condition if user is allowed to join channel */) {
return ['data' => 'your Data'];
}
});
// Join channel
Echo.join('channel-name')
.here(function(data) {
console.log(data)
})
// Event
class Event implements ShouldBroadcast
{
public function broadcastOn()
{
return new PresenceChannel('channel-name');
}
}
Related
SO i am trying to listen to event that create channel dynamically with the the ids of the two users involved. I ma using pusher and echo for this purpose
the event successfully fired from my controller and is being recorded but echo does not listens to that event.
I am using guards as the conversation will be between two admins
My channel.php code is
Broadcast::channel('chatchannel.{reciever_id}.{sender_id}', function ($user, $reciever_id, $sender_id) {
if((int) auth()->guard('admin')->user()->id === (int) $reciever_id || (int) auth()->guard('admin')->user()->id === (int) $sender_id){
return true;
}else{
return false;
}
});
app.js file looks like this
Echo.private('chatchannel.'+app_sender_id+'.'+app_reciever_id)
.listen('.chatEvent', (e) => {
console.log('subscribed');
});
I did this change in my broadcastingerviceprovider.php file according to online soultions but it did not work
Broadcast::routes(['middleware' => 'auth:admin']);
I looked for all the solutions online but could not find anything that is of actual help. Can anyone guide me on how to get it working.
Your broadcast channel is chatchannel.{reciever_id}.{sender_id}.
However your client channel is chatchannel.'+app_sender_id+'.'+app_reciever_id
This means, for a sender of A and receiver of 2 you would have the following channels:
Broadcast - chatchannel.2.A
Client - private-chatchannel.A.2.
Channel names must match for the client to receive the broadcast event. You should ensure the sender and receiver Id are in the same order on both systems and that you are using private channels in both scenarios.
In my app with Laravel on back-end users can send messages to each other.
I want to send push notification to app users on new inbox message, but I need to send messages only if user hadn't already read this message.
So I see it that way
On every message sended I need to schedule Laravel notification after 1 minute
if user already received this message I need to cancel this notification
How can dismiss scheduled notification in Laravel? Is this approach fine and actual now?
Class extends Notification
public function via($notifiable)
{
if($this->dontSend($notifiable)) {
return [];
}
return ['mail'];
}
public function dontSend($notifiable)
{
return $this->appointment->status === 'cancelled';
}
Maybe there is more convenient way to handle it? For example, to send push every time but somehow dismiss it showing from app if it's already launched?
One way to do it would be something like this;
Before you trigger your notification create a unique identifier(sha1 could be an option) with the combination of user_id. Let's say it is SgiA7EfBQBFQK3pjRWtaxB1CkSf7gf4lSixvei3jU3ydHJ39ZGjhhdUUCnHRno3C. Send it to the notification. Both notification and message will be send at the same time, but notification will have one minute delay.
$identifier = Str::random(64);
$delay = now()->addMinute();
$user->notify((new MyNotification($identifier))->delay($delay));
// send a request that contains identifier.
You set this to the Redis with TTL of 2 minutes. It will be gone if there is no action.
Redis::set('SgiA7EfBQBFQK3pjRWtaxB1CkSf7gf4lSixvei3jU3ydHJ39ZGjhhdUUCnHRno3C', 1, 120);
While sending a message to the user, attach this identifier to the message. When user read that message, you make a request to your /read endpoint with all the parameters + the identifier.
When you receive the request, delete the key from Redis. (user received the message)
Redis::del('SgiA7EfBQBFQK3pjRWtaxB1CkSf7gf4lSixvei3jU3ydHJ39ZGjhhdUUCnHRno3C');
In your Notification class, implement a small method to check whether the key exists in Redis.
Redis::exists('SgiA7EfBQBFQK3pjRWtaxB1CkSf7gf4lSixvei3jU3ydHJ39ZGjhhdUUCnHRno3C');
class MyNotification extends BaseNotification
{
use Queueable;
private $identifier;
public function __construct($identifier)
{
$this->identifier = $identifier;
}
public function via()
{
return $this->isValid() ? ['mail'] : [];
}
public function isValid()
{
return Redis::exists($this->identifier);
}
public function toMail()
{
// details..
}
}
It doesn't have to be Redis but it is a perfect match for these kind of key/value structure.
I am following the Presence Channels section in Laravel docs.
1.Authorizing Presence Channels-I created I function to check is user is authorized to access them.
Broadcast::channel('chat', function ($user) {
...
return user_info;
})
2.Joining Presence Channels-They say I must use Echo's join method. So I did.
Echo.join('chat')
.here((users) => {
console.log('hello',users)
this.users = users;
})
.joining((user) => {
console.log('hey you', user)
this.users.push(user);
})
.leaving((user) => {
this.users.splice(this.users.indexOf(user), 1);
})
Here's the part that confuses me. "The data returned by the authorization callback will be made available to the presence channel event listeners in your JavaScript application". I assume that I suppose to have this Javascript. part and it should be an event listener. I just can't understand where should it be and how I must call it. Have it something to do with a function I use when user logged in?
So, help me understand how to implement these 'presence channel event listeners in your JavaScript application.'
"The data returned by the authorization callback will be made available to the presence channel event listeners in your JavaScript application."
https://laravel.com/docs/5.8/broadcasting#authorizing-presence-channels
This means that the data returned by your authorization callback Broadcast::channel(...) which is $user_info will be available to the joining() and leaving() listeners, or any custom listeners, within your JavaScript application.
The currently defined listeners are waiting to hear another user join or leave the chat channel. Therefore, each user must also fire the corresponding events within their own instance of the application.
// join the channel — trigger joining()
Echo.join('chat');
// leave the channel — trigger leaving()
Echo.leave('chat');
I want to add server response message in CRUD response toaster. For Example when we do an update, we will get 'Element updated' toaster message. Instead of it I want to show some dynamic (not static) server responded message.
This is only supported for error messages currently. If this is really important, please open a feature request and we'll consider it.
A slightly long winded way to do this. But definitely possible.
1) Write a custom restWrapper or RestClient
https://marmelab.com/admin-on-rest/RestClients.html
2) Handle the request and response from it like below.
function handleRequestAndResponse(url, options={}, showAlert={}) {
return fetchUtils.fetchJson(url, options)
.then((response) => {
const {headers, json} = response;
//admin on rest needs the {data} key
const data = {data: json}
if (headers.get('x-total-count')) {
data.total = parseInt(headers.get('x-total-count').split('/').pop(), 10)
}
// handle get_list responses
if (!isNaN(parseInt(headers.get('x-total-count'), 10))) {
return {data: json,
total: parseInt(headers.get('x-total-count').split('/').pop(), 10)}
} else {
return data
}
})
}
3) you now have a place in your code where you can intercept the data from the server. In above code you can define and shoot actions containing your data whenever you need. Create a reducer that takes the data from your action and populates a field in the state you can call it notification.
4) Use the redux-saga select method
How to get something from the state / store inside a redux-saga function?
You can now access the notification data from the store and show custom toaster messages to your heart's content :)
I'm trying to broadcast an event in a case where two user share a conversation (like a chat) where only the two of the can access and get notified when a new message comes.
I think, after reading the documentation that the presence channel is the best option (private is for one people and the server and channel is for something plublic without checking ?)
So in my routes/channels.php I have something like this:
Broadcast::channel('conversation.{conversation}', function ($user, Conversation $conversation) {
if ($user->id === $conversation->user1_id || $user->id === $conversation->user2_id) {
return $user;
}
return null;
});
In the client side a Component I have:
Echo
.join('conversation.${conversation.id}')
.here((users) => {
this.usersInRoom = users;
})
.joining((user) => {
this.usersInRoom.push(user);
})
.leaving((user) => {
this.usersInRoom = this.usersInRoom.filter(u => u != user);
})
.listen('MessagePosted', (e) => {
this.messages.push({
id :e.message.id,
user_id :e.message.user_id,
conversation_id :e.message.conversation_id,
user :e.user,
text :e.message.text,
created_at :e.message.created_at,
updated_at :e.message.updated_at,
});
});
And the class that emit the even MessagePosted :
public function broadcastOn()
{
return new PresenceChannel('conversation.'.$this->message->conversation_id);
}
So I now that previously I used a PresenceChannel without any checking, so if two people where in there conversation they would get notification from everyone. not the right thing.
In the server side, I have the 'conversation.{conversation}' that was mentioned in the documentation to make a separated channel. But I also saw something like 'conversation.*'.
And on the client side I have join('conversation.${conversation.id}') but here I am not sure at all I just know that I have in the props (props : ['user', 'friend', 'conversation']) a conversation which is an object with the id of the conversation.
So When, when everyone was on the same channel with no restriction everything was working perfectly and now, I think I have an error which make the whole thing not work.
I have two 500 server side error when I load a client conversation :
ReflectionException in Broadcaster.php line 170:
Class Conversation does not exist
(And in the route/channels.php I import the Conversation class use App\Conversation;)
and
HttpException in Broadcaster.php line 154:
I found the following solution to my problem. I think I saw something in the documentation saying that you might need to use the Path of the class you want to broadcast. So I tried something like this :
In the routes/channel.php
Broadcast::channel('App.Conversation.{id}', function ($user, $id) {
$conversation = Conversation::findOrFail($id);
if ($user->id === $conversation->user1_id || $user->id === $conversation->user2_id) {
return $user;
}
return null;
});
In the client side in the vue component :
Echo
.join('App.Conversation.'+this.conversation.id)
...
In the class that emit the event MessagePosted :
public function broadcastOn()
{
return new PresenceChannel('App.Conversation.'.$this->message->conversation_id);
}