How to save information about a Client on Server-Side?
Hi
What is the proper way to save infomartions about a connected client on the Server-Side.
Lets say we have a chat-app and want to keep the username somewhere.
In the tutorial we have the $this->clients... can we just add some additional data here? And how would we do this?
Hi, Using SplObjectStorage you can attach additional data to connection:
<?php
//...
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onMessage(ConnectionInterface $from, $msg) {
// set username
$this->clients->attach($from, $username);
// reading
$username = $this->clients[$from];
// updating
$this->clients[$from] = $newUsername;
}
Because SplObjectStorage stores mixed type, you can set any structure. See https://www.php.net/manual/en/class.splobjectstorage.php
you could also add public properties to the connection object:
<?php
//...
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$conn->someProperty = 'someValue';
$conn->someOtherProperty = 'someothervalue'; //set properties before attaching the connection to the storage
$this->clients->attach($conn);
}
Just be carefull if you deside to not give every connection the same parameters to check for their existance when accessing them again.
Hi guys,
I'm trying to figure out a way to attach some datas to the client too, but I'm kind of stuck... since too long now.
public function onOpen(ConnectionInterface $conn)
{
$this->clients->attach($conn);
$querystring = $conn->httpRequest->getUri()->getQuery();
parse_str($querystring, $queryarray);
$this->users[isset($queryarray['token']) && $queryarray['token'] != '' ? $queryarray['token'] : $conn->resourceId] = $conn;
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg)
{
$numRecv = count($this->clients) - 1;
echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n", $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
// Data from the SENDER SIDE
$dataArray = json_decode($msg, true);
/** @var User $userModel */
$userModel = new User($this->database);
$listUserChannel = $userModel->listUserChannel($dataArray['workshopId']);
$this->clients->attach( (object) $listUserChannel);
// SEND TO USERS WITH THE SAME CHANNEL
if (isset($dataArray['workshopId']) && $dataArray['workshopId'] > 0) {
$this->sendMessageToChannel($from, $msg);
// SEND TO EVERYBODY
} else {
print_r("SEND TO EVERYBODY");
$this->sendMessageToAll($from, $msg);
}
}
But... it does not seems to work. So what I need to do is to attach $listUserChannel to the client, and compare a value $dataArray['workshopId'] to the attached value, to know if I send my message to everybody or only to the users with the same workshopId.
Can somebody help me maybe ?
Thank you very much
What's the purpose of creating User (I guess this is something like repository) on each message?
$userModel = new User($this->database);
What is listUserChannel? Array of users attached to given workshopId? If so you already have everything you need. Just iterate over array, and send message to those users.
Also you are mixing listUserChannel with Connection data:
$this->clients->attach($conn);
$this->clients->attach( (object) $listUserChannel);
@taavit
The purpose of:
$userModel = new User($this->database);
$listUserChannel = $userModel->listUserChannel($dataArray['workshopId']);
is to be able to retrieve a list of users, from the database since I need to select all the users with a certain worskhopId.
If $user['workshopId'] = $data["worskhopId"]
Than, you send this message to every users with this workshopID.
I'm not so use to the use of the SplObjectStorage. I think it's part of my issue..
My logic: I wanted to add the value of $user['workshopId'] to $client, in order to send the message only to list of users.
I'm not so use to the use of the SplObjectStorage. I think it's part of my issue.. My logic: I wanted to add the value of $user['workshopId'] to $client, in order to send the message only to list of users.
Yes that's exactly your problem.
in your above example you're attaching the $dataArray basically as a new client instead of "appending" it to an existing connection. The confusing part here is probably the attach() method of the SplObjectStorage Object.
See my comment from above on one way to add information to the actual connection.
Another way would be for you to extend ratchets WsConnection object and use them instead. You could then add any property (and method) you like directly to the connections. This would however require you to modify ratchet itself to use the new objects.
Hi, Using SplObjectStorage you can attach additional data to connection:
<?php //... public function __construct() { $this->clients = new \SplObjectStorage; } public function onMessage(ConnectionInterface $from, $msg) { // set username $this->clients->attach($from, $username); // reading $username = $this->clients[$from]; // updating $this->clients[$from] = $newUsername; }Because SplObjectStorage stores mixed type, you can set any structure. See https://www.php.net/manual/en/class.splobjectstorage.php
SplObjectStorage uses hash of the object as key, updating username will change the key for connection object. What is the implication of frequently updating username of large number of connections?