Quickly accessing variables between clients in Socket.IO - socket.io

(I'm asking and answering this question because I think it might be useful, but if anything here is flawed let me know.)
Setting and getting custom variables in Socket.IO's socket object is super convenient for ephemeral data you want to associate with that connection.
In the chatroom example, (in this instance I'm using PHP but it should be readily translatable) the script stores user names there:
$socket->on('add user', function ($username) use ($socket) {
$socket->username = $username;
Which you can then use in your broadcast:
$socket->broadcast->emit('user joined', array(
'username' => $socket->username,
'numUsers' => $numUsers
));
The question I've had is how to 'share' the variable data between sockets (connections) without (or before) emitting it? This would be useful for managing more complex chatrooms, or something like a game where you may want to work with this data and not emit.
There are approaches I can think of that could do the job, such as managing distinct arrays, or storing and retrieving with a database -- but they seem redundant if you don't explicitly need to do so.
I wasn't able to find much documentation on this.

Sticking with the chatroom example, this is what I came up with:
Let's say you want to set and get the age of everyone in a particular room:
$socket->on('add user', function ($username,$age) use ($socket) {
$socket->age = $age;
I made a function to collect the unique connection id's of everyone who's in a room:
function clients_in_the_room($room)
{
GLOBAL $io;
$clients_in_the_room = $io->sockets->adapter->rooms[$room];
$clients_in_the_room = array_keys($clients_in_the_room);
return $clients_in_the_room;
}
$io->sockets->adapter->rooms[$room]; is just going to give us an array with booleans, so I've caught the array_keys, which are the id's I want, those are very useful.
$clients_in_the_room = clients_in_the_room('Lobby');
Now we have those id's, we can access those socket variables I wanted:
function socket_age($socketid) {
GLOBAL $io;
$age = $io->sockets->connected[$socketid]->age;
return $age;
}
Beautiful. For clarity, I could emit all this data...
foreach($clients_in_the_room as $clientsId) {
$age = socket_age($clientsId);
$output = "Connection ID: $clientsId Age: $age.";
$socket->broadcast->emit('new message', array(
'username' => $socket->username,
'message' => $output
));
};
But obviously we don't want to do that usually. It's just super useful to know how to quickly access those variables. Hope this is useful.

Related

Getting Stripe Upcoming Invoice Line Items with Laravel Cashier

I'm attempting to use Laravel Cashier to retrieve line items of the client's upcoming invoice. I'm having difficulty obtaining the invoice in the first place. Though I've found the undocumented public function "upcomingInvoice," I can't get any of its protected properties out.
Even with it, I'm having trouble understanding how to use the poorly documented "asStripe..." functions, presumably asStripeInovice(), to return the line items.
I've tried a whole host of things and it would muddle things up to write them all out, so I figure it might be better just to ask how to go about it.
Thanks!
Try this one liner code in laravel 7 or 8 with cashier.
$user->upcomingInvoice()
And you're good getting all upcoming invoices details.
As up update, I was able to get this to work just using the Stripe client, like so:
$stripe = new StripeClient(env('STRIPE_SECRET'));
$upcomingLineItems = $stripe->invoices
->upcomingLines(['customer' => $customer['stripe_id']]);
I'll still leave this open in case there's a way to do it with Cashier's methods, but it now doesn't seem necessary.
Similarly, I wanted to be able to display the "amount due today" to a user prior to switching subscription plans (which takes into account proration as well as any credit applied to the customer's account). I was able to do this in Laravel using the following:
$stripe_client = new StripeClient(config('stripe.secret'));
$items = [
[
'id' => $user->subscription()->items()->first()->stripe_id,
'price' => $selected_plan, # Switch to new price
],
];
$invoice = $stripe_client->invoices->upcoming([
'customer' => $user->stripe_id,
'subscription' => $user->subscription()->stripe_id,
'subscription_items' => $items,
'subscription_proration_date' => Carbon::now()->timestamp
]);
$amount_due = $invoice->amount_due; // and there it is

Hide API Resource Field / Belongs To Many Through Deep Relationship Problem

It seems as if the tutorial right here doesn't work as intended https://hackernoon.com/hiding-api-fields-dynamically-laravel-5-5-82744f1dd15a
I am aware of how to load relationships only if necessary by making use of "whenLoaded", but for simple field parameters that do not involve a relationship, I am unable to dynamically load these fields.
Below is a snippet of Agency.php
'expected_num_of_b_positive_donors' => $this->getExpectedNumOfDonors("B+"),
'elligible_to_schedule_mbd' => $this->
'donors' => $this->getDonors(),
'contact_persons' => $this->getContactPersons(),
'last_mbd' => $this->getLastMBD(),
'average_number_of_donors_per_day' => $this->getAverageNumberofDonorsPerDay()
This would all have been extremely easy, if Laravel came out of the box with a Belongs To Many Through Deep Relationship, as I could have easily used:
'donors' => $this->whenLoaded("donors")
instead of:
'donors' => $this->getDonors(),
For context, here is a snippet of my getDonors()
$donors = [];
// MBD -> Schedule -> Donation List -> Donor
foreach($this->mbds as $mbd){
foreach($mbd->mbd_schedules as $schedule){
foreach($schedule->donation_list as $donation_list){
if(!in_array($donation_list->donation->donor, $donors)){
array_push($donors, new UserResource($donation_list->donation->donor));
}
}
}
}
return $donors;
Since Belongs To Many Through does not exist, I had to create a custom laravel relationship where I can get All Donors of an Agency. Now, I have 2 Questions.
Is there a way for me to dynamically load the getDonors()?
// I am aware that this is wrong, I'd just like to give context if it's possible to do something like this
'donors' => $this->whenLoaded("donors", $this->getDonors()),
Is there an elegant way for me to make a custom Belongs To Many Relationship? So that I could just simply do
'donors' => $this->whenLoaded("donors")
I am aware that third party packages exist for Belongs To Many Relationships, but I'd like to know which one of these are best in your opinions as I am afraid of using a potentially wrong package and end up screwing my system much more.
Thanks Laracasts!

Auto increment in Rethinkdb

Does RethinkDb support AUTO_INCREMENT on a integer column similar to AUTO_INCREMENT in Mysql. https://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
No, RethinkDB doesn't support it. The reason is because of its distribution. It's hard to have an auto increment number on such that environment because you have to check on multiple machines for next incremental value.
Now, let's think what problem auto increment solve? On MySQL, We want to use it for primary key so it needs to be unique. That's all about it. Auto increment doesn't give you anything else.
In RethinkDB, UUID guarantees the uniqueness, especially in the case of primary key.
Auto Increment is also predictable, probably it isn't cause any harmful but ideally, it gives people a sense of what's next value to attack. For example, take a poor design application, where we can visit some URL like /this/is/a/sensitive/part/123, someone can hit /this/is/a/sensitive/part/124. Of course, this is the fault of application for not having a solid authentication system. However, UUID may help reduce this a bit because UUID isn't predictable.
we archive like below example
```
r.db('autoInc').table('testauto')
.insert(r.do(function() {
return {
autoVal:r.branch(
r.db('FlowzEngine').table('task_worker').isEmpty().not()
.and(r.db('FlowzEngine').
table('task_worker').hasFields('autoVal')
.isEmpty().not()),
r.db('FlowzEngine').table('task_worker')
.hasFields('autoVal').max('autoVal')
.do(function(doc){
return doc('autoVal').add(1)
}),
1)}
}))
```
you can achieve this using a counter table like below:
r.table('counters')
.get(id)
.update({
count: r.row('count')
.default(0)
.add(1)
}).run(conn, callback);
An example based on Chirag's answer, for php, if using Daniel Mewes php-rql..
Chirag's answer for some reason is showing using separate tables, this isn't required, not sure if it's an oversight in the example or not..
$result = \r\table('user')
->insert(array(
'username' => $username, /* other data for example */
'password' => $password,
'userId' =>
\r\rDo(null, function($arg) {
return \r\branch(
\r\table('user') /* if */
->isEmpty()->not()
->rAnd(
\r\table('user')
->hasFields('userId')
->isEmpty()->not()
),
\r\table('user') /* then */
->hasFields('userId')
->max('userId')
->rDo(function($arg) {
return $arg('userId')->add(1);
}),
1); /* else */
})
))
->run($db);
I thought I would add it as it took me more than a few minutes to get this working on PHP, syntactical differences can be annoying.

Saving a model with multiple foreign keys in Laravel 4

I understand that in order to save a foreign key, one should use the related model and the associate() function, but is it really worth the trouble of going through this
$user = new User([
'name' => Input::get('name'),
'email' => Input::get('email')
]);
$language = Language::find(Input::get('language_id');
$gender = Gender::find(Input::get('gender_id');
$city = City::find(Input::get('city_id');
$user->language()->associate($language);
$user->gender()->associate($gender);
$user->city()->associate($city);
$user->save();
when one can simply do this?
User::create(Input::all());
I feel like I'm missing something here, maybe there's an even simpler and cleaner way to handle foreign keys in controllers (and views)?
You can use push() method instead which would allow you to push to related models.
This link should answer your query.
Eloquent push() and save() difference
I really don't see anything wrong at all with doing User::create(Input::all());.
Obviously you'd want some validation, but it's doing the same thing.
I think the associate() method is more useful for the inverse of your situation.
For example, say you had a form which a user could fill out to add their city to your app, and upon doing so, they should automatically be assigned to that city.
$city = City::create(Input::all()); would only achieve the first half of your requirements because the user has not yet been attached as city does not have a user_id column.
You'd then need to do something like $city->user()->associate(User::find(Auth::user()->id));

Codeigniter: Passing form data from view to controller

Which is right? notice in the second option, I'm passing the form values using the $_POST variable. Whereas the first option, I call and assign variables for each form field.
I've seen this ...
<validation code> ....
$todo = array(
'name'=>$this->input->post('title'),
'description'=>$this->input->post('description')
);
$this->Todo_model->add($todo);
But I've also seen the following ...
$records['email'] = "trim|required|min_length[4]|xss_clean";
...
...
$this->validation->set_rules($records);
if ($this->validation->run())
{
$this->account_model->saveAccountSettings("sam", $_POST);
$this->session->set_flashdata('message', 'Done!');
redirect('account/settings');
} else {
...
}
I tend to use a mix of your two examples. I'm pretty sure things like trim won't modify the actual post data, so you can only take advantage of it if you go through the validation framework to get the data. I actually never access POST directly anymore using CI.
Plus I'd be worried in your second example about just shoving POST into my model. What happens if someone clever adds "lastname" to the post data sent in and your db column is named the same? Even though you weren't expecting to deal with that data now you've got unvalidated data coming in. That's why I employ part of your first example and manually pull out the items I want to save into an array first.
So I'd recommend a hybrid.
Normally my code looks something like this:
$fields['email'] = "trim|required|valid_email|min_length[4]|xss_clean";
...
...
$this->validation->set_rules($fields);
if ($this->validation->run())
{
$account = new array();
$account['id'] = $accountId; //wherever you get the Id from
$account['email'] = $this->validation->email;
$this->account_model->save($account);
$this->session->set_flashdata('message', 'Done!');
redirect('account/settings');
} else {
...
}
The first option is better easy to read or trace
Pass values using post variables is better option
What the real benefit to use this
$account['email'] = $this->validation->email;
Instead of
$account['email'] = $this->input->post('email');

Resources