Laravel Eloquent Nested Group by its Relation - php

Please help me how to add another nested group by based on game category relation. I have 3 tables related using laravel 5.4 eloquent.
Game Providers Table
+----+-------------+--------------+------------------+
| id | game_name | game_type_id | game_category_id |
+----+-------------+--------------+------------------+
| 1 | Sample | 1 | 1 |
| 1 | Sample 0 | 1 | 2 |
| 2 | Sample 1 | 2 | 1 |
| 3 | Sample 2 | 2 | 2 |
+----+-------------+--------------+------------------+
Game Types
+----+-------------+
| id | name |
+----+-------------+
| 1 | Chess |
| 2 | Poker |
+----+-------------+
Game Categories
+----+-------------+
| id | name |
+----+-------------+
| 1 | Recommended |
| 2 | Optional |
+----+-------------+
I'm done of for first nested for game type relation but i dont know how to add another group by for game categories
$game_providers = GameProvider::all();
$game_providers = $game_providers->groupBy(function ($game_provider) {
return $game_provider->game_type->name;
})->all();
and its output
Array{
'Chess' => Array{
0 => Array{
'id' => 1,
'game_name' => 'Sample',
'game_type_id' => 1,
'game_category_id' => 2
},
1 => Array{
'id' => 2,
'game_name' => 'Sample 0',
'game_type_id' => 1,
'game_category_id' => 2
},
},
'Poker' => Array{
0 => Array{
'id' => 3,
'game_name' => 'Sample 1',
'game_type_id' => 2,
'game_category_id' => 1
},
1 => Array{
'id' => 4,
'game_name' => 'Sample 2',
'game_type_id' => 2,
'game_category_id' => 2
},
},
}
My expected output
Array{
'Chess' => Array{
'Recommended' => Array{
0 => Array{
'id' => 1,
'game_name' => 'Sample',
'game_type_id' => 1,
'game_category_id' => 2
}
},
'Optional' => Array{
0 => Array{
'id' => 2,
'game_name' => 'Sample 0',
'game_type_id' => 1,
'game_category_id' => 2
}
}
},
'Poker' => Array{
'Recommended' => Array{
0 => Array{
'id' => 3,
'game_name' => 'Sample 1',
'game_type_id' => 2,
'game_category_id' => 1
}
},
'Optional' => Array{
0 => Array{
'id' => 4,
'game_name' => 'Sample 2',
'game_type_id' => 2,
'game_category_id' => 2
}
}
}
}

With L5, one way of acieving this can be:
GameProvider::with('game_categories.game_types')
->get()
->groupBy([
'gameTypes.name',
'gameCategories.name'
]);

Should be something along the lines of :
GameProvider::with('game_categories.game_types')->get()->map(function ($game) {
return $game->game_categories->groupBy('name')->map(function ($catGame) {
return $catGame->map(function ($category) {
return $category->game_types->groupBy('name');
});
});
});

Related

PHP array duplicate add value to that index

am just trying to fix my problem. Exactly: I have array that has been filled up by database (music playlist). That array contains duplicates what am trying to achieve is (example rows from database):
-- ID: 0 | ARTIST: SOMETHING1 | TITLE: SOMETHING1 | TIME: 04:00 | REPEAT: 1 |
-- ID: 1 | ARTIST: SOMETHING2 | TITLE: SOMETHING2 | TIME: 02:40 | REPEAT: 1 |
-- ID: 2 | ARTIST: SOMETHING3 | TITLE: SOMETHING3 | TIME: 03:20 | REPEAT: 1 |
-- ID: 3 | ARTIST: SOMETHING1 | TITLE: SOMETHING1 | TIME: 04:00 | REPEAT: 1 |
-- ID: 4 | ARTIST: SOMETHING1 | TITLE: SOMETHING1 | TIME: 04:00 | REPEAT: 1 |
-- ID: 5 | ARTIST: SOMETHING1 | TITLE: SOMETHING1 | TIME: 04:00 | REPEAT: 1 |
-- ID: 6 | ARTIST: SOMETHING1 | TITLE: SOMETHING1 | TIME: 04:00 | REPEAT: 1 |
So those values would be in array now how would I check for those duplicates in that array. If there would be duplicate I'd want to remove that duplicate but leave only one and add +1 to repeat for each duplicate. Example from above rows:
-- ID: 0 | ARTIST: SOMETHING1 | TITLE: SOMETHING1 | TIME: 04:00 | REPEAT: 5 |
-- ID: 1 | ARTIST: SOMETHING2 | TITLE: SOMETHING2 | TIME: 02:40 | REPEAT: 1 |
-- ID: 2 | ARTIST: SOMETHING3 | TITLE: SOMETHING3 | TIME: 03:20 | REPEAT: 1 |
Am sorry if there is already post but couldn't find way to explain it better.
You can use this function. Kindly make sure you change the ARTIST key to meet your need.
function remove_duplicates($playlist){
$filtered = [];
foreach($playlist as $music){
$array_exist = array_filter($filtered, function($val) use ($music) {
return ($val['ARTIST'] === $music['ARTIST']) &&
($val['TITLE'] === $music['TITLE']);
});
if( empty($array_exist) ){
$filtered[] = $music;
}else{
foreach($array_exist as $index => $arr){
$filtered[$index]['REPEAT'] += 1;
}
}
}
return $filtered;
}
Example
$music_playlist = [
['ID' => 1, 'ARTIST' => 'SOMETHING1', 'TITLE' => 'SOMETHING1', 'TIME' => '04:00', 'REPEAT' => 1],
['ID' => 2, 'ARTIST' => 'SOMETHING2', 'TITLE' => 'SOMETHING2', 'TIME' => '02:40', 'REPEAT' => 1],
['ID' => 3, 'ARTIST' => 'SOMETHING3', 'TITLE' => 'SOMETHING3', 'TIME' => '03:20', 'REPEAT' => 1],
['ID' => 4, 'ARTIST' => 'SOMETHING1', 'TITLE' => 'SOMETHING1', 'TIME' => '04:00', 'REPEAT' => 1],
['ID' => 5, 'ARTIST' => 'SOMETHING1', 'TITLE' => 'SOMETHING1', 'TIME' => '04:00', 'REPEAT' => 1],
['ID' => 6, 'ARTIST' => 'SOMETHING1', 'TITLE' => 'SOMETHING1', 'TIME' => '04:00', 'REPEAT' => 1],
['ID' => 7, 'ARTIST' => 'SOMETHING1', 'TITLE' => 'SOMETHING1', 'TIME' => '04:00', 'REPEAT' => 1]
];
print_r(remove_duplicates($music_playlist));
You can use a for/foreach loop with every data you have. Then add the new data when something is not there. And put an auto increment on the ID with primary key.
If it has to be in PHP and not SQL, then how about:
$keys=[];
foreach($rows as $row) {
$id=$row['ARTIST'].$row['TITLE'];
if ( !isset($keys[$id]) ) $keys[$id]=$row;
else {
$rowX=$keys[$id];
$rowX['REPEAT']++;
$keys[$id]=$rowX;
}
}
See http://sandbox.onlinephpfunctions.com/code/8558cf3ae956ac358962bf3c83ecabc299a38af3 for a working example

Built a multidimensional array with PHP from an SQL query

Form a SQL query i receive the following datas from two differences tables.
|----------------|----------|--------------|
|CON_ContinentId | FRU_Name | FRU_Quantity |
|----------------|----------|--------------|
| 1 | Apple | 100 |
| 1 | Banana | 200 |
| 2 | Peach | 300 |
| 2 | Cherry | 400 |
| 3 | Coconut | 500 |
| 4 | Grape | 1100 |
| 5 | Pear | 1500 |
|----------------|----------|--------------|
I need to get an array like this:
$datas = [
1 => [
[
'FRU_Name' => 'Apple',
'FRU_Quantity' => '100'
],
[
'FRU_Name' => 'Banana',
'FRU_Quantity' => '200'
]
],
2 => [
[
'FRU_Name' => 'Peach',
'FRU_Quantity' => '300'
],
[
'FRU_Name' => 'Cherry',
'FRU_Quantity' => '400'
]
],
3 => [
[
'FRU_Name' => 'Coconut',
'FRU_Quantity' => '500'
]
],
4 => [
[
'FRU_Name' => 'Grape',
'FRU_Quantity' => '1000'
]
],
5 => [
[
'FRU_Name' => 'Pear',
'FRU_Quantity' => '1100'
]
],
]
So, basically, I need to groupe the rows with the same CON_ContinentId and list the FRU_Name and FRU_Quantity.
What I try:
$datas = [];
while ($fetch = $query->fetch(PDO::FETCH_ASSOC)){
$CON_ContinentId = $fetch['CON_ContinentId'];
$FRU_Name = $fetch['FRU_Name'];
$FRU_Quantity = $fetch['FRU_Quantity'];
if (!in_array($CON_ContinentId, $datas)) {
$datas = array(
'CON_ContinentId' => $CON_ContinentId,
'FRU_Name' => $FRU_Name,
'FRU_Quantity' => $FRU_Quantity
);
}
}
But it doesn't work.
Could you please help me ?
Thanks.
There are a few different problems in your code:
Your desired array structure isn't valid, so it's unclear what you want.
$datas isn't initialized. Use $datas = [] instead.
$FRU_Name is being set twice? Did you mean $FRU_Quantity?
This code won't group multiple fruits under their continent ID--it'll put them into an associative array alongside their continent ID.
Every iteration of your results set, just use the CON_ContinentID value as the key, then [] to auto-index the subarrays.
There is no need to declare resultset values to new variables, just apply them to the $datas declaration and move on.
while ($fetch = $query->fetch(PDO::FETCH_ASSOC)){
$datas[$fetch['CON_ContinentId']][]=['FRU_Name'=>$fetch['FRU_Name'],'FRU_Quantity' =>$fetch['FRU_Quantity']];
}
a bit more explanation...
// hard-coded keys -vvvvvvvv-----------------------vvvvvvvvvvvv
$datas[$fetch['CON_ContinentId']][]=['FRU_Name'=>$fetch['FRU_Name'],'FRU_Quantity' =>$fetch['FRU_Quantity']];
// id-^^^^^^^^^^^^^^^^^^^^^^^^^ ^^-auto-index ^^^^^^^^^^^^^^^^^^------------------^^^^^^^^^^^^^^^^^^^^^^-resultset data
// ^^^^^^^^^^-keys start from zero, and increment by one at each new pushed subarray)

Echoing data vertical and horizontal from joined table mySql in PHP

I need your help. Maybe it's all about logical. So my case is:
I have mySql tables, they are:
record table
_______________________________________
Student ID | Question ID | Answer
_______________________________________
1 | 1 | A
2 | 1 | C
3 | 1 | E
1 | 2 | D
2 | 2 | B
3 | 2 | A
....... | .......... | ........
_______________________________________
and student table:
_________________________________
Student ID | Student Name
_________________________________
1 | Ronaldo
2 | Messi
3 | Neymar
.......... | .............
_________________________________
And I want to echoing them in my report page with table like this:
_________________________________________________
Student | Question and Answer
|____________________________________
| 1 | 2 | 3 | ... | ... | ... | ... |
_________________________________________________
Ronaldo | A | D | ...........................
Messi | C | B | ...........................
Neymar | E | A | ...........................
........ | ...................................
_________________________________________________
I use PHP so I repeat with foreach(){} function. But how to echoing data vertically and horizontally in once query?
Sorry for my bad php knowledge and logical. Thanks for your attention.
A simple way to do it (but by no means the only one) :
First fetch your users along with their answers :
SELECT
s.id AS student_id,
s.name AS student_name,
q.question_id,
q.answer
FROM
students AS s
INNER JOIN
questions AS q
ON
s.id = q.student_id;
You should get rows like that :
array(
'student_id' => '1',
'student_name' => 'Ronaldo',
'question_id' => 1,
'answer' => 'A',
)
OR
array(
'student_id' => '2',
'student_name' => 'Messi',
'question_id' => 1,
'answer' => 'C',
),
You could then loop through them to reorganize them :
$data = array();
foreach($rows as $row){
if(!isset($data[$row['student_id']])){
$data[$row['student_id']] = array(
'student_name' => $row['student_name'],
'questions' => array(),
);
}
$data[$row['student_id']]['questions'][] => array(
'question_id' => $row['question_id'],
'answer' => $row['answer'],
);
}
Which will give you this array :
$data = array(
'1' => array(
'student_name' => 'Ronaldo',
'questions' => array(
array(
'question_id' => 1,
'answer' => 'A',
),
array(
'question_id' => 2,
'answer' => 'D',
),
),
),
'2' => array(
'student_name' => 'Messi',
'questions' => array(
array(
'question_id' => 1,
'answer' => 'C',
),
array(
'question_id' => 2,
'answer' => 'B',
),
),
),
);
Finally, loop through the last array to display data the way you want :
foreach($data as $student){
echo $student['student_name'] . ' : ' ;
foreach($student['questions'] as $question){
echo 'Question ' . $question['question_id'] . ' : ' . $question['answer'] . "\n";
}
}
You will need to do some adaptation to suit your need.

Converting a flat array to a specific array format

Fellow PHP programmers, consider the following DB result:
+---------+-----------+---------------+--------+
| node_id | parent_id | path | branch |
+---------+-----------+---------------+--------+
| 1 | 0 | /1/ | NULL |
| 2 | 1 | /1/2/ | NULL |
| 3 | 2 | /1/2/3/ | 1 |
| 4 | 3 | /1/2/3/4/ | 1 |
| 8 | 4 | /1/2/3/4/8/ | 1 |
| 9 | 8 | /1/2/3/4/8/9/ | 1 |
| 7 | 4 | /1/2/3/4/7/ | 0 |
| 5 | 2 | /1/2/5/ | 0 |
| 6 | 5 | /1/2/5/6/ | 0 |
+---------+-----------+---------------+--------+
How does one get the following PHP array:
[
[
'id' => 1,
'parentId' => 0,
],
[
'id' => 2,
'parentId' => 1,
'nodes' => [
[ // when branch == 0
[
'id' => 5,
'parentId' => 2
],
[
'id' => 6,
'parentId' => 5
],
],
[ // when branch == 1
[
'id' => 3,
'parentId' => 2
],
[
'id' => 4,
'parentId' => 3,
'nodes' => [
[ // when branch == 0
[
'id' => 7,
'parentId' => 4
],
],
[ // when branch == 1
[
'id' => 8,
'parentId' => 4
],
[
'id' => 9,
'parentId' => 8
],
]
]
],
]
]
]
]
The function should work with unlimited depth.
Any help would be greatly appreciated as I've been hitting a wall.
Something like this:
function buildTree($arr, $parentID)
{
$children = [];
foreach ($arr as $item) {
if ($item['parent_id'] == $parentID) {
array_push($children, [
'id' => $item['node_id'],
'parentId' => $item['parent_id'],
'nodes' => buildTree($arr, $item['node_id'])
]);
}
}
return $children;
}
$tree = buildTree($flat, null);
UPD:
function getBranches($arr, $parentID)
{
$branches = array();
foreach ($arr as $item) {
if ($item['parent_id'] == $parentID) {
$bKey = $item['branch'];
$node = array(
'id' => $item['node_id'],
'parentId' => $item['parent_id']
);
$firstNodeChild = false;
if ($nodeChildren = getBranches($arr, $item['node_id'])) {
$hasKey = array_key_exists($bKey, $nodeChildren);
if ($hasKey && $nodeChildren[$bKey]) {
if (sizeof($nodeChildren[$bKey]) == 1) {
$firstNodeChild = $nodeChildren[$bKey][0];
unset($nodeChildren[$bKey]);
}
}
if ($nodeChildren) {
$node['nodes'] = $nodeChildren;
}
}
if (!array_key_exists($bKey, $branches)) {
$branches[$bKey] = array();
}
$branches[$bKey][] = $node;
if (false !== $firstNodeChild) {
$branches[$bKey][] = $firstNodeChild;
}
}
}
ksort($branches);
return $branches;
}
$tree = getBranches($arr, 0);

MySQL entries with self parent_id into sorted cascade array

I need help with an application I'm creating.
I have a table, looks kind like this:
+----+-----------+---------+
| id | parent_id | name |
+----+-----------+---------+
| 1 | null | test |
+----+-----------+---------+
| 2 | null | test2 |
+----+-----------+---------+
| 4 | 1 | test3 |
+----+-----------+---------+
| 5 | 2 | test4 |
+----+-----------+---------+
And now, I get all the data in one array. I would like to get kinda this structure (php array as an cascade):
array(
0 => array(
'id' => 1,
'parent_id' => null,
'name' => 'test',
'children' => array(
'id' => 4,
'parent_id' => 1,
'name' => 'test3'
)
),
1 => array(
'id' => 2,
'parent_id' => null,
'name' => 'test2',
'children' => array(
'id' => 5,
'parent_id' => 2,
'name' => 'test4'
)
)
)
So there will every entry with a "parent_id=null" be a parent, and every entry with an id in "parent_id" will be in a child array.
I started it like this:
$newArray = array();
foreach($names as $name) {
if($name['parent_id'] == null || $name['parent_id'] == 0) {
// entry is parent
$newArray[$name['id']] = $name['name'];
} else {
// entry is child
}
}
But here is also my end, I don't know how to do that. I think i have to use some kind of recursive loop function, but I don't know how to start.
Would be awesome if somebody could help me.
Kind regards,
Matt.
You can use a recursive function like this (I only added the code which is relevant for understanding):
function get_children($parentId) {
$array = array();
//Load/Find $children
foreach($children as $child) {
$array[] = array(
'id' => $child->id,
'name' => 'YourName',
'children' => get_children($child->id)
);
}
return $array;
}
If you save the data in such an array, it isn't necessary to save the parent_id, because you can get it by searching for the parent elements id.

Categories