How to get around Undefined offset: 1 - Laravel 5.2 - php

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);

Related

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.

Ranking based on users placement instead of score

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();
}

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)

Complex Zend Query from same user table

I have a rather unique set of conditions and orders in which I need to retrieve data from a "sellers" table for an application I'm building in Zend framework.
The client is basically requesting an application where the directory page lists sellers in a very particular order, which is:
Sellers who have been approved in the last 7 days (then order by #4 below)
Then, selllers who have paid for upgraded features on the site, and are more the 7 days old (then order by #4 below)
Then, Sellers who are more than 7 days old and are more than 7 days old (then order by #4 below)
For all of the above, secondary order by would be their launch date, then alpha by business name
I'm trying to figure out the most effective way to write an action helper that will return the data in the correct sequence above, knowing that some of my views only need 1,2 (and 4), whereas other views within the application will need all 4.
Right now, I've been writing two or three separate queries, and passing them to 2 or 3 partialloop's inside the view, but I strive for properly written code, and would like to either combine my 3 queries into one object I can pass to one partial loop, or.... write one query. How can this be done?
Here's my helper at the moment:
class Plugin_Controller_Action_Helper_ListSellers extends Zend_Controller_Action_Helper_Abstract
{
//put your code here
public function direct($regulars = false, $filter = false)
{
$dateMod = $this->dateMod = new DateTime();
$dateMod->modify('-7 days');
$formattedDate = $dateMod->format('Y-m-d H:i:s');
// get sellers initialized in last 7 days
$sellerTable = new Application_Model_DbTable_Seller();
// get sellers initialized in last 7 days
$select = $sellerTable->select()->setIntegrityCheck(false);
$select->from(array('b' => 'seller'),array('sellerID', 'businessName','sellerPicture'));
// select firstName, lastName, picture from user table, and businessName and sellerID from seller table. All records from seller table
$select->join(array('u' => 'user'), 's.userID = u.userID', array('firstName', 'lastName'));
$select->order('s.launchDate DESC','s.businessName ASC');
$select->where('s.active = 1 AND s.contentApproval = 1 AND s.paymentApproval = 1');
$select->where('s.launchDate > ?', $formattedDate);
if($filter){ $select->where('s.categoryID = ?', $filter);}
$newSellers = $sellerTable->fetchAll($select);
$query = $sellerTable->select()->setIntegrityCheck(false);
$query->from(array('b' => 'seller'),array('sellerID', 'businessName','sellerPicture'));
// select firstName, lastName, picture from user table, and businessName and sellerID from seller table. All records from seller table
$query->join(array('u' => 'user'), 's.userID = u.userID', array('firstName', 'lastName'));
$query->order('s.launchDate DESC','s.businessName ASC');
$query->where('s.active = 1 AND s.contentApproval = 1 AND s.paymentApproval = 1 AND s.featured = 1');
$query->where('s.launchDate < ?', $formattedDate);
if($filter){ $select->where('s.categoryID = ?', $filter);}
$featuredSellers = $sellerTable->fetchAll($query);
if($regulars){
$where = $sellerTable->select()->setIntegrityCheck(false);
$where->from(array('b' => 'seller'),array('sellerID', 'businessName','sellerPicture'));
// select firstName, lastName, picture from user table, and businessName and sellerID from seller table. All records from seller table
$where->join(array('u' => 'user'), 's.userID = u.userID', array('firstName', 'lastName'));
$where->order('s.launchDate DESC','s.businessName ASC');
$where->where('s.active = 1 AND s.contentApproval = 1 AND s.paymentApproval = 1 AND s.featured IS NULL');
$where->where('s.launchDate < ?', $formattedDate);
$regularSellers = $sellerTable->fetchAll($where);
}
}
}
I don't see any limits being applied to your queries. So does that mean you really want to select all matching records? For scalability reasons I'd guess that the answer should be no, there will be limits applied. In this case, you may just have to do 3 different queries.
But if there are no limits to be applied, then you could do a single simple query that selects all sellers, unfiltered and unsorted, and do your sorting and filtering in view helpers or just in your views.
Regardless, I recommend not putting database queries inside your controller layer, assuming you want to use the Model-View-Controller pattern which Zend is built for. Controllers should be thin. Your models should handle all database queries and just spit out the results into your controllers. I use the Data Mapper pattern extensively. Something like:
$mapper = new Application_Model_SellerMapper();
$newSellers = $mapper->fetchNewSellers();
$featuredSellers = $mapper->fetchFeaturedSellers();
$regularSellers = $mapper->fetchRegularSellers();
Each of your fetchX() methods would return an array of Application_Model_Seller instances, rather than Zend_Db_Table_Row instances.
This way you maintain Separation of Concerns and Single Responsibility Principle better, for more maintainable code. Even if you're the only developer on the project over the long-term, 6 months from now you won't remember what you wrote and why. And if someone else comes on the project, clarity becomes really important.

Array help. Looking for a better way

EDIT::
Maybe I should be asking what the proper way to get a result set from the database is. When you have 5 joins where there is a 1:M relationship, do you go to the database 5 different times for the data??
I asked this question about an hour ago but haven't been able to get an answer that was fitting. I went ahead and wrote some code that does exactly what I need but am looking for a better way to do it
This array gives me multiple rows of which only some are needed once and others are needed many times. I need to filter these as I have done below but want a better way of doing this if possible.
Array
(
[0] => Array
(
[cid] => one line
[model] => one line
[mfgr] => one line
[color] => one line
[orderid] => one line
[product] => many lines
[location] => many lines
)
[1] => Array
(
.. repeats for as many rows as were found
)
)
This code works perfectly but again, I think there is a more efficient way of doing this. Is there a PHP function that will allow me to clean this up a bit?
// these are the two columns that produce more than 1 result.
$product = '';
$orderid = '';
foreach($res as $key)
{
// these produce many results but I only need one.
$cid = $key['cid'];
$model = $key['model'];
$mfgr = $key['mfgr'];
$color = $key['color'];
$orderid = $key['orderid'];
// these are the two columns that produce more than 1 result.
if($key['flag'] == 'product')
{
$product .= $key['content'];
}
if($key['flag'] == 'orderid')
{
$orderid .= $key['content'];
}
}
// my variables from above in string format:
Here is the requested SQL
SELECT
cid,
model,
mfgr,
color,
orderid,
product,
flag
FROM products Inner Join bluas ON products.cid = bluas.cid
WHERE bluas.cid = 332
ORDER BY bluas.location ASC
Without seeing your database structure it's a bit hard to decipher how you actually want to manipulate your data.
Perhaps this is what you're looking for though?
SELECT p.cid, p.model, p.mfgr, p.color, p.orderid, p.product, p.flag, GROUP_CONCAT(p.content SEPARATOR ', ')
FROM products AS p
INNER JOIN bluas AS b ON p.cid = b.cid
WHERE b.cid = 332
GROUP BY p.cid, p.flag
ORDER BY b.location ASC
So now for each product cid each flag will have an entry consisting of a comma separated list instead of there being many repeating for each flag entry.
Then after you're done with the string you can quickly turn it into an array for further manipulation by doing something like:
explode(', ', $key['content']);
Again it's really hard to tell what information you're trying to pull without seeing your database structure. Your SQL query also doesn't really match up with your code, like I don't even see you grabbing content.
At any rate I'm pretty sure some combination of GROUP BY and GROUP_CONCAT (more info) is what you're looking for.
If you can share more of your database structure and go into more detail of what information exactly you're trying to pull and how you want it formatted I can probably help you with the SQL if you need.

Categories