Ranking based on users placement instead of score - php

I have a issue that I cannot wrap my head around.
I am using the Laravel Framework.
I am trying to make a ranking table based on placement (Meaning the user does not have any SCORE, they just have placements)
How I want it to work is the following way:
User A = Placement: 1
User B = Placement: 10
User B wins over User A, then User B gets placed as number 1 and User A gets placed as number 2, and then I want it to update all the other users accordingly.
I can't seem to find a reliable way of doing this.

I don't think this is a Laravel challenge but an SQL one. And it may be simple to solve: basically, you will ask for the actual position of the defeated person, if the position is greater than the winner, you do nothing, otherwise you will assign the position of the loser to the new winner and update the rest of the table with a +1 in the position column.
In code it would be something like this:
$winner_player = User::where('id', userA->id)->first();
$loser_player = User::where('id', userB->id)->first();
if($winner_player->position < $loser_player->position) {
//Update the rest of the users.
//We add 2 because we need space for the new winner and for
//the loser that is still above of the rest of the players.
DB::table('users')
->where('position', '>', $loser_player->position)
->update(DB::raw('position+2'));
//Set the winner with the actual position of the loser.
$winner_player->position = $loser_player->position;
$winner_player->save();
//Set the looser with the new position (+1 of his actual).
$loser_player->position = $loser_player->position + 1;
$loser_player->save();
}
UPDATED LOGIC
As Classified pointed out, it moves the rows around but doesn't do it correctly, so I'm updating the logic to make it work as it is supposed to, and it will be a little simpler too.
$winner_player = User::where('id', userA->id)->first();
$loser_player = User::where('id', userB->id)->first();
if($winner_player->position < $loser_player->position) {
//Set the winner with the actual position of the loser.
$winner_player->position = $loser_player->position;
//Update the users between the swap. There is no need to update
//the whole table, we only update the records between the swap.
DB::table('users')
->where([['position', '<', $winner_player->position],
['position', '>=', $loser_player->position]])
->update(DB::raw('position+1'));
//Save the value of the winner AFTER updating the positions
//between winner and loser.
$winner_player->save();
}

Related

How to check whether a number lies between 2 values using Laravel query

I have to trigger a mail when student crosses several stages . I have two tables
studentreward_point_categories and
student_reward_points.
If any student reaches a stage then need to send a mail. How to get category from db .
Reward point Category table.
Student reward point table.
If for student_id = 19 have 345 points How to get his reward category. i have tried below code.
$total_point = StudentRewardPoint::where('student_id', $request->student_id)
->sum('points');
if(!empty($total_point)){
return $pointCategory = RewardPointCategory::where('from_value','>=', $total_point)
->where('to_value','<=',$total_point)
->where('status',1)
->first();
}
Using this query I'm not able to get user reward point category.
You are querying it totally wrong!! From my point of view swap your '<=' and '>='
return $pointCategory = RewardPointCategory::where('from_value','<=',$total_point)-
>where('to_value','>=',$total_point)->where('status',1)->first();

Make unique ID using Laravel

I want to generate a unique id in Laravel.
EX: PO-12010001
PO = product,
12 = the month,
01 = the year,
0001 = ID of product.
I have tried googling and the answer is using UUID but could not understand.
Your ID will always be 4 digits at the end, so we can pluck those last four characters using substr(). When you increment that by one, it will lose its padding. So 0001+1=2. We therefor pad it back using str_pad() with a length of four.
$string = 'PO-12010001';
$id = substr($string, -4, 4);
$newID = $id+1;
$newID = str_pad($newID, 4, '0', STR_PAD_LEFT);
echo "PO-1201".$newID;
Live demo at https://3v4l.org/55RTL
Since it is not clear where the last 4 characters (ID of product) come from, there are 2 different outcomes based on their origin, I am assuming that "PO" is a constant in all your products:
1.If you're auto-generating the Product ID:
$id = "PO-".date('my') . substr(uniqid(), 9, 12);
date('my') will return a two-digits form of the current month and a two-digits form of the current year.
uniqid() returns a unique identifier based on the current time in microseconds, the identifier is usually a mix of letters and digits, and it is usually 13 characters long, so we use substr() to only return the last 4 characters of the string.
NOTE: we are using the last characters of uniqid() because they change every millisecond.
2.If you already have a Product ID:
$id = "PO-".date('my') . $product_id;
When like this situation first how you want to make your ID
Item Type
Month
Year
Product ID
Get product type in your controller
if Product = PO /
Service = SE
Create a New Date using PHP
$date2 = date('Y-m-d');
and get date substring with your requirement and get the last id of the product table and concat all the variable and use as Unique ID.
First, I dopn't know. So maybe it has a similar concept. But anyway, user defined+designed unique are most likely not unique.
My recommendation is to let the database create an unique id with the autoincrement feature. This is usually the only way to guarantee unique ideas in a multi tasking environment.
The, in an second step, you can create an human readable id and use it for displaying it at the suer interface. Such query can be something like:
update table set nice_id = concat("prefix-",main_id)
where main_id = $last_inserted_id
... or any other calculation based on counting the the number of same entries since beginning of month.
There are other solutions based on try to create an nice_id, insert it into the database, and if this fails, create the next one .. and loop until successful. But simple integers created by autoincrement are more performant on queries and for keys.
it's called Human code which can be unique identify beside an Id column in db table.
$idColumn = 1;
$dateCode = date('ym');
$newHumanCode = 'PO-'.$dateCode.substr('0000'.$idColumn, -4);
return $newHumanCode;
also you can use randome number instead of use $idColumn,
for example:
$idColumn = mt_rand();
You can use the Laravel ID generator.
First Install it:
composer require haruncpi/laravel-id-generator
Import the class in your controller.
use Haruncpi\LaravelIdGenerator\IdGenerator;
Now simply use it
$prefix = "PO-".date("my");
$id = IdGenerator::generate(['table' => 'your_table_name', 'length' => 11, 'prefix' =>$prefix]);
Output
PO-12010001
PO-12010002
PO-12010003
...

How to implement tree like structure in mysql and laravel

A question struck in my mind for 2 days and wondering whether it is possible to implement this type of tree structure in laravel and MySQL.
(First, take a look at the image attached. Thanks)
Suppose our platform uses refer system, and initially, a user 'A' join. Now, this user 'A' further refers 3 persons 'B','C','D'. Now, the total refer on A is 3 (because it refers 3 persons).
Now, let B further refers 'E','F' and 'C' further refers 'G','H', 'I' and 'D' refers 0. So, now refer of each person is "D = 0", "C = 3", "B = 2". and these refers will also add up on "A". So, it has "A = 8".
Now, 'G' refers 'J', so 'G' gets +1 and 'C' also gets +1 and 'C' is referred by 'A', so 'A' also gets +1. Now, total refer to each person is :
"j = 0","G=1","H=0","I=0", "D=0","E=0","f=0","B=2","C=4 (beacuse G refers J also)","A=9(beacuase 9 childers are refered by him)"
The chain continues until A gets total refer of 40.
In simple, if a person refers another person then it will get +1 and it's parent whom he gets refer also get +1 and so on until parent reaches 40, the chain continues.
I know, this is One-Many relationship between a user and refer and we can use a pivot table, but, How can we implement this type of logic. Give me some hints. Thanks.
I have written out something that should hopefully help you with this, using a while loop.
public function totalReferredBy(User $user)
{
// Initialise the queue to contain only the provided user
$queue = collect([$user]);
// This collection will eventually contain all of the "child"/referred users
$results = collect();
while ($queue->isNotEmpty() > 0) {
// Run a where in query to select all the referred users of the users in the queue.
$referredUsers = User::whereIn('referred_by', $queue->pluck('id'))->get();
// Merge the referredUsers we have found in the database with the results collection, so we can later count.
$results = $results->merge($referredUsers);
// Make the referredUsers we have just found in the database, the new queue. If the query did not return any
// referred users, the queue count would be 0 and the loop will exit.
$queue = $referredUsers;
}
// Now we should have all of the given user's "children" and "children of children" in the $results collection.
// We just need to return the count of that collection to get the total number of users that have been referred.
return $results->count();
}
You can use it like this:
$user = User::find(1);
$totalReferred = $this->totalReferredBy($user);
Then if your application does something when the user reaches 40 or more referred, you can just do:
if ($this->totalReferredBy($user) > 40) {
// Do something
}
This assumes that you have a referred_by column on the users table.

How to get around Undefined offset: 1 - Laravel 5.2

I'am working on a API right now, and I'm on a part where I have to get a Players last matches score. Usually there are ATLEAST 2 teams in every match OR more. But I came across a playlist where there is only 1 team for the whole match.
I'am calling for the score of both teams like this:
// Get the Score AND Team ID of First team
$Warzonescore = $warzoneLastMatch->TeamStats[0]->Score;
$WarzonescoreTeamId = $warzoneLastMatch->TeamStats[0]->TeamId;
// Get the Score AND Team ID of Second team
$Warzonescore2 = $warzoneLastMatch->TeamStats[1]->Score;
$Warzonescore2TeamId = $warzoneLastMatch->TeamStats[1]->TeamId;
My problem is, in some matches, there is only 1 team, and if I load up a plyers gamertag, and if that person only played a match with one kind of team ( all players are on the same team), it gives me this error:
Undefined offset: 1
because TeamStats[1] does not exist for that player.
How can I get around that API call and check if that value is null, or if it exists?
I tried to insert it into a (if else) statement, and checked with ( ->exists(), === null, != 0, != "")
Doesn't make sense to hardcode your accessor methods in this way when you can do a simple loop on TeamStats
$Warzonescores = [];
foreach($warzoneLastMatch->TeamStats as $idx => $stats){
$Warzonescores[$idx]['Score'] = $stats->Score;
$warzonescores[$idx]['TeamId'] = $stats->TeamId
}
This seems like a more efficient and clean way to go about your approach. As it's an API, you can now do a simple and safe return on your data
return response()->json($Warzonescores);

Redis zscore zadd uri wrong score

Im currently working on assigning groups to a special url, with their groupId as score.
create group-url:
$this->cache->redis->zadd("group_route",$groupId,$groupUrl);
search if it is a group-url, and get the group:
function isCostumUrl($groupUrl) {
$group = $this->cache->redis->zrank("group_route",$groupUrl);
if ($group) {
return $group;
} else {
return false;
}
}
Problem My problem is that somehow the result-groupid is wrong.
I am searching for katt, that has id 4, but it reply with 3 wich acually belongs to group-url fisk.
how can i acually make it return the right result?
The rank is not the same with the score. The rank is zero -0- based, so in the case above rank 3 is correct for group_route katt. For example you can have different scores of your items 2, 3, 4 and 5, but the rank (or index) will always be the same. Take a look at the Redis rank command
But zscore would work correct for you (you actually put zscore in title, but use zrank in example)

Categories