Retrieve Child Objects - php

I want a table of comments like so
id | comment | parent_id
--------------------------
1 text1 0
2 text2 1
3 text3 2
4 text4 3
5 text5 3
6 text6 5
I want to construct an array displaying the hierarchy of the parents and children. The tree should go back a undetermined number of generations. I don't want to use nesting foreach loops as I'm not sure how deep it goes. That is why I'm here, I'm not sure of the best practice for a problem like this. I also want to display the depth in the array. Below is an example. It doesn't really relate to table above, but hopefully gives you an idea of what I need.
array(
"depth"=> 4
"parent" => array(
"id"=> 1,
"comment" => "sometext1"
"child_count" => 2,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
),
1 => array(
"id" => 3
"comment" => "sometext3"
"child_count" => 1,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 2,
"children" => array(
0 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
),
1 => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 1,
"children" => array(
"id" => 2
"comment" => "sometext2",
"child_count" => 0,
"children" => null
)
)
)
)
)
)
)
)
I was going to use foreach and do a SQL statement to retrive that parent/childs children. ie
$sql = "SELECT * FROM comments WHERE parent = $parent_id";
Im not really looking for the code for all this, just a pseudo code solution.

This can be easily done in PHP... For this you need two arrays and a two while loops.
This code will make a tree the way you wanted and for an undetermined depth and number of children.
Pastebin to the working code.
Using references, lets imagine everything is saved in an array $data with this structure: (id, comment, parent_id) where parent_id points to an id.
Code to build the tree.
$tree = array();
reset($data);
while (list($k, $v) = each($data))
if (0 == ($pid = $v['parent_id']))
$tree[$k] =& $data[$k]; else
$data[$pid]['children'][$k] =& $data[$k];
And to generate the depth and child count.
reset($data);
while (list($k, $v) = each($data))
if (0 != $v['parent_id'])
{
$ref =& $data[$k];
$depth = 0;
do
{
if ($depth) $ref =& $data[$ref['parent_id']];
$dre =& $ref['depth'];
if (!isset($dre) || $dre <= $depth) $dre = $depth++;
if (isset($ref['children']))
$ref['child_count'] = count($ref['children']);
else
{
$ref['child_count'] = 0;
$ref['children'] = null;
}
}
while ($ref['parent_id']);
}
All my code has been written on the fly and not even tested, so if there are any errors please forgive meeeeeeeee!!!!!!!!!!! ← Forget that, I tried it, fixed a couple of issues and now works perfectly.
Note
For this code to work, the index of every item has to be equal to its ID.
The array I used to try the code.
$data = array(
'1' => array('id' => '1', 'comment' => 'a', 'parent_id' => 0),
'2' => array('id' => '2', 'comment' => 'b', 'parent_id' => 0),
'3' => array('id' => '3', 'comment' => 'c', 'parent_id' => 1),
'4' => array('id' => '4', 'comment' => 'd', 'parent_id' => 1),
'5' => array('id' => '5', 'comment' => 'e', 'parent_id' => 2),
'6' => array('id' => '6', 'comment' => 'f', 'parent_id' => 2),
'7' => array('id' => '7', 'comment' => 'g', 'parent_id' => 5),
'8' => array('id' => '8', 'comment' => 'h', 'parent_id' => 7)
);

This is the problem when you use Adjacency list for trying to retrieve all child nodes in the hierarchy. It just doesn'y handle recursion very well if you are using mysql. (Oracle is another matter).
Creating the structure is simple, you should not really concern yourself with how to create the array structure just yet, first you want to try and create an efficient query and effiecient models that play perfectly to the type of queries that you will be making.
For example, you say that you want to retrieve all child nodes. Well then you should probably be using nested set models instead or in addition to adjacency list.
Take a look at some of these resources...
Is there a simple way to query the children of a node?
The idea of a nested set, is that you store the lft and right edge values of a node, meaning that retrieving any child nodes, is incredibly simple, beause you just select nodes which have a lft value greater than the target nodes lft value, and smaller than the rgt value.
Once you retrieve your result set, creating your array structure will be effortless.
See here : http://en.wikipedia.org/wiki/Nested_set_model
Once you have your results, then take a look at this question, which I asked a year or so ago, which is exactly what you want. PHP > Form a multi-dimensional array from a nested set model flat array
Example
id | comment | parent_id | lft | rgt |
-------------------------------------------------
1 World null 1 12
2 Europe 1 2 11
3 England 2 3 10
4 Kent 3 4 5
5 Devon 3 6 9
6 Plymouth 5 7 8

Related

Restructure array from sql query so that I can echo proper values

I'm trying to get the content I need from a joined query and properly use values as an array key so that I can build some DIV lists properly
My php query and array:
$getTickers = "
SELECT d.ID as displayID, d.display_name as display, l.location_name as locationName, d.location_id as location, t.id as ticker, tc.id as contentID, tc.content
FROM displays d
INNER JOIN locations l on d.location_id = l.id
INNER JOIN tickers t on d.id = t.display_id
INNER JOIN ticker_content tc on t.id = tc.ticker_id;
";
$tickers = $mysqlConn->query($getTickers);
$tickerDisplays = array();
foreach($tickers as $subArray) {
if(!array_key_exists($subArray['displayID'], $tickerDisplays)) {
$tickerDisplays[$subArray['displayID']] = array();
}
// here you add `display_name` under key `display_id`
$tickerDisplays[$subArray['displayID']][$subArray['location']] = $subArray['display'];
}
All examples and code below, but I don't need the html structure help with this, just how to restructure the array/key to give me the desired results and how I should loop them on the front end.
I'm getting 4 divs as I expect right now (one for each unique display/location)
but I need to figure out how to correcty arrange it so I can echo the DIsplay name as the h4, the location as h5, and then each content in my list
So the query result gives me this:
displayID | display | locationName | location | ticker | contentID | content |
1 Office Building 4 4 1 1 testing content
2 Lobby Building 4 4 2 2 testing content 2
3 Lobby Building 1 1 3 3 testing content 3
4 Office Building 1 1 4 4 testing content 4
4 Office Building 1 1 4 5 testing content again
I'm trying to loop on this with the expected result of having a a div for each location/display combo like so:
OFFICE
Building 4
testing content
---------------
LOBBY
Building 4
testing content 2
------------------
LOBBY
Building 1
testing content 3
------------------
OFFICE
Building 1
testing content 4
testing content again
----------------------
Here's the way I'm currently trying to loop that
<?php foreach($tickerDisplays as $key => $ticker):?>
<h4><?php echo $key ?></h4> //so this should be the display Name (office, lobby)
<h5><?php echo //location?></h5> //this should be the location name (Building 1, Building 4)
//This will be another foreach for any content associated with the location/display
<ul class="tickerContent">
<li>
</ul>
</div>
</div>
<?php endforeach;?>
The approach here is to make a child array for each display line to contain all
the multiple content records.
// Dummy the data from the query
$tickers = [
['displayID' => 1, 'display' => 'Office', 'locationName' => 'Building 4', 'location' => 4, 'ticker' => 1, 'contentID' => 1, 'content' => 'testing content'],
['displayID' => 2, 'display' => 'Lobby', 'locationName' => 'Building 4', 'location' => 4, 'ticker' => 2, 'contentID' => 2, 'content' => 'testing content 2'],
['displayID' => 3, 'display' => 'Lobby', 'locationName' => 'Building 1', 'location' => 1, 'ticker' => 3, 'contentID' => 3, 'content' => 'testing content 3'],
['displayID' => 4, 'display' => 'Office', 'locationName' => 'Building 1', 'location' => 1, 'ticker' => 4, 'contentID' => 4, 'content' => 'testing content 4'],
['displayID' => 4, 'display' => 'Office', 'locationName' => 'Building 1', 'location' => 1, 'ticker' => 4, 'contentID' => 5, 'content' => 'testing content again']
];
// A place to keep the reorganized data
$tickerDisplays = [];
// Walk through the query result
foreach($tickers as $row) {
$displayID = $row['displayID']; // for convenience and readability
$location = $row['location']; // for convenience and readability
$display = $row['display'];
$contentID = $row['contentID'];
if ( ! array_key_exists($row['displayID'], $tickerDisplays) ) {
$tickerDisplays[$displayID] = [
'displayID' => $row['displayID'],
'display' => $row['display'],
'ticker' => $row['ticker'],
'contentID' => $row['contentID'],
'content' => $row['content'],
'location' => $row['location'],
'locationName' => $row['locationName'],
'#content' => [] // to store the content data
];
}
$tickerDisplays[$displayID]['#content'][$contentID] = ['content' => $row['content']];
}
print_r($tickerDisplays);
foreach ( $tickerDisplays as $key => $ticker ) {
// Output the display and location name
out($ticker['display']);
out($ticker['locationName']);
// Output all the content records.
foreach ( $ticker['#content'] as $contentID => $content ) {
out($content['content']);
}
out('------------');
}
// Just a utility function
function out($msg) {
echo "$msg\n";
}
Output:
Office
Building 4
testing content
------------
Lobby
Building 4
testing content 2
------------
Lobby
Building 1
testing content 3
------------
Office
Building 1
testing content 4
testing content again
------------

Mysql one Parent multiple Child result without repeating Parent rows

I am building a CMS with Codeigniter and MYSQL. and have a table like this.
CREATE TABLE parent
(`parentId` int, `parentName` varchar(50));
INSERT INTO parent
(`parentId`, `parentName`)
VALUES
(1, 'Movie'),
(2, 'Food'),
(3, 'Sports');
CREATE TABLE child
(`childId` int, `parentId` int,`childName` varchar(50));
INSERT INTO child
(`childId`, `parentId`, `childName`)
VALUES
(1, 1, 'Harry Potter'),
(2, 3, 'Foot Ball'),
(3, 2, 'Pizza'),
(4, 2, 'Burger'),
(5, 1, 'Avengers'),
(6, 1, 'Fury'),
(7, 3, 'Cycling');
And want output to be printed output like this
foreach($parent as $parentData):
echo"<h4>".$parentData->parentName."</h4>";
echo"<ul>";
foreach($child as childData):
echo"<li>".$childData->childName."</li>";
endforeach;
echo"</ul>"
endforeach;
which produces this
<h4>Movie</h4>
<ul>
<li>Harry Potter</li>
<li>Avengers</li>
<li>Fury</li>
</ul>
<h4>Food</h4>
<ul>
<li>Pizza</li>
<li>Burger</li>
</ul>
<h4>Sports</h4>
<ul>
<li>Foot Ball</li>
<li>Cycling</li>
</ul>
Any tweaking of the code is welcomed.
As i have been trying this for the past few hours.
Thanks in advance.
Update:
I implemented the answer to my code as CodeGodie suggested and added a view like this.
foreach ($result as $arr) {
if (!isset($final[$arr["parentName"]])) {
$final[$arr["parentName"]] = array();
}
array_push($final[$arr["parentName"]], $arr);
}
foreach ($final as $parent=> $childs) {
echo $parent."<br>";
foreach ($childs as $child) {
print_r($child) ;
}
}
Now i got the result i was expecting
There are multiple ways of doing this. However I would use the following approach:
You need to create the following SQL query:
SELECT * FROM parent p
JOIN child c ON c.parentId = p.parentId
ORDER BY parentName
Or in Codeigniter:
$this->db->select("*");
$this->db->from("parent p");
$this->db->join("child c", "c.parentId = p.parentId ");
$this->db->order_by("parentName");
$q = $this->db->get();
return $q->result_array();
which will give you a result of something like this:
$result = array(
array(
"parentId" => 2,
"parentName" => "Food",
"childId" => 3,
"childName" => "Pizza",
),
array(
"parentId" => 2,
"parentName" => "Food",
"childId" => 4,
"childName" => "Burger",
),
array(
"parentId" => 1,
"parentName" => "Movie",
"childId" => 1,
"childName" => "Harry Potter",
),
array(
"parentId" => 1,
"parentName" => "Movie",
"childId" => 5,
"childName" => "Avengers",
)
);
Iterate through your results:
foreach ($result as $arr) {
if (!isset($final[$arr["parentName"]])) {
$final[$arr["parentName"]] = array();
}
array_push($final[$arr["parentName"]], $arr);
}
var_dump($final);
this will give you a result like this which you can then iterate to build your HTML:
array (size=2)
'Food' =>
array (size=2)
0 =>
array (size=4)
'parentId' => int 2
'parentName' => string 'Food' (length=4)
'childId' => int 3
'childName' => string 'Pizza' (length=5)
1 =>
array (size=4)
'parentId' => int 2
'parentName' => string 'Food' (length=4)
'childId' => int 4
'childName' => string 'Burger' (length=6)
'Movie' =>
array (size=2)
0 =>
array (size=4)
'parentId' => int 1
'parentName' => string 'Movie' (length=5)
'childId' => int 1
'childName' => string 'Harry Potter' (length=12)
1 =>
array (size=4)
'parentId' => int 1
'parentName' => string 'Movie' (length=5)
'childId' => int 5
'childName' => string 'Avengers' (length=8)
Hope this helps
I think you are looking for group concat
https://www.percona.com/blog/2013/10/22/the-power-of-mysqls-group_concat/
Using this, you can select a comma separated list of child values. Then in your PHP you would simply need to explode on the comma and then loop through that.
Bear in mind the default group_concat limit is often quite low so you will probably need to increase this - https://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_group_concat_max_len
This query will get all the data:
SELECT parent.parentName, child.childName
FROM parent
INNER JOIN child on parent.parentId = child.parentId;
And return it as:
------------------------------
parentname | childName
------------------------------
Movie | Harry Potter
Movie | Avengers
Movie | Fury
et cetera...

Pull count of records in a table that have the same value with Codeigniter Active Record

I am working on a site where I have a table with "catches" (people have caught fish with a particular lure). The lure_used category is an integer.
I want to find the users "best lure". So i want to loop through all the user_catches rows and return an array that has each lure and how many times it was used.
So for example we might have
catch_1 | lure_used = 5,
catch_2 | lure_used = 3,
catch_3 | lure_used = 6,
catch_4 | lure_used = 3,
so from that i would like to know that 5 and 6 occur 1 time while 3 occurs twice. Therefore 3 is the most successful lure.
I know that I could probably use "MAX" in mysql queries, but i'm not really farmiliar with it and attempts have failed.
I have been able to create an array of lures used like:
$lures = array(5, 3, 6, 3);
So maybe i could just loop through that and output something like...
5 = 1, 3 = 2, 6 = 1.
I guess i'm grasping at straws haha, anyone have a better idea on how to get this done?
Here are all the fields in the "user_catches" table:
'id' => $row->id,
'user_id' => $row->user_id,
'species' => $row->species,
'season' => $row->season,
'lure_used' => $row->lure_used,
'depth' => $row->depth,
'exact_depth' => $row->exact_depth,
'presentation' => $row->presentation,
'catch_weight' => $row->catch_weight,
'length' => $row->length,
'fishing_from' => $row->fishing_from,
'moon_phase' => $row->moon_phase,
'water_temp' => $row->water_temp,
'water_quality' => $row->water_quality,
'notes' => $row->notes,
'rod' => $row->rod,
'reel' => $row->reel,
'line' => $row->line,
'rig' => $row->rig,
'catch_image' => $row->catch_image,
'weather' => $row->weather,
'temp' => $row->temp,
'humidity' => $row->humidity,
'wind' => $row->wind,
'pressure' => $row->pressure,
'visibility' => $row->visibility,
'location' => $row->location,
'weather_icon' => $row->weather_icon,
'catch_date' => $row->catch_date,
SELECT lure, count (*) as count
from user_catches
GROUP BY lures
ORDER BY count;

How to reorder this array?

I have a database table as follows:
This returns all column titles in the pic, but the one's that are most important are slug, and parent (not sure about id_button).
The array gets ordered automatically by id_button ASC, which really irks me. But, anyways, this is not important, as I need to order it completely different, or re-order it after the array is populated.
The array returns this, by order of id_button:
$new_menu_buttons = array(
0 => array(
'id_button' => 1,
'parent' => 'help',
'position' => 'child_of',
'slug' => 'testing',
),
1 => array(
'id_button' => 2,
'parent' => 'packages',
'position' => 'after',
'slug' => 'sub_test_1',
),
2 => array(
'id_button' => 3,
'parent' => 'google.com',
'position' => 'after',
'slug' => 'another_test',
),
3 => array(
'id_button' => 4,
'parent' => 'testing'
'position' => 'child_of',
'slug' => 'google.com',
)
);
I need to order it so that if a slug is found within any parent, than the slug that is in the parent needs to be loaded before the one that has it defined within the parent.
Its not important if it is directly before it. For example, you see testing is the first slug that gets returned, and yet the parent for this is the last slug (google.com). So as long as the slug row where the parent is defined gets ordered so that it is BEFORE the row that has the slug value in the parent column, everything is fine.
So in this situation, it can be reordered as any of these 3 ordered arrays below:
$new_menu_buttons = array(
0 => array(
'id_button' => 1,
'parent' => 'help',
'position' => 'child_of',
'slug' => 'testing',
),
1 => array(
'id_button' => 2,
'parent' => 'packages',
'position' => 'after',
'slug' => 'sub_test_1',
),
2 => array(
'id_button' => 4,
'parent' => 'testing',
'position' => 'child_of',
'slug' => 'google.com',
),
3 => array(
'id_button' => 3,
'parent' => 'google.com'
'position' => 'after',
'slug' => 'another_test',
)
);
OR this...
$new_menu_buttons = array(
0 => array(
'id_button' => 1,
'parent' => 'help',
'position' => 'child_of',
'slug' => 'testing',
),
1 => array(
'id_button' => 4,
'parent' => 'testing',
'position' => 'child_of',
'slug' => 'google.com',
),
2 => array(
'id_button' => 2,
'parent' => 'packages',
'position' => 'after',
'slug' => 'sub_test_1',
),
3 => array(
'id_button' => 3,
'parent' => 'google.com'
'position' => 'after',
'slug' => 'another_test',
)
);
OR even this...
$new_menu_buttons = array(
0 => array(
'id_button' => 1,
'parent' => 'help',
'position' => 'child_of',
'slug' => 'testing',
),
1 => array(
'id_button' => 4,
'parent' => 'testing',
'position' => 'child_of',
'slug' => 'google.com',
),
2 => array(
'id_button' => 3,
'parent' => 'google.com'
'position' => 'after',
'slug' => 'another_test',
),
3 => array(
'id_button' => 2,
'parent' => 'packages',
'position' => 'after',
'slug' => 'sub_test_1',
)
);
All 3 of these ordered arrays will work because the array with the slug that matches the parent is before the array with the matching parent, and since the slug value, sub_test_1 doesn't match any of the parent values this array order is unimportant, so that array can be located anywhere within the array.
How can I do this? I'm thinking of just looping through the array somehow and trying to determine if the slug is in any of the parents, and just do a reordering somehow...
In short, the slug needs to be ordered before the parent ONLY if there is a parent that matches a slug within the array. Otherwise, if no match is found, the order isn't important.
As Niko suggested, databases support powerful sorting functionality, so you normally can best solve this by telling the database in which order to return the data. If the data is queried with SQL, that's the ORDER BY clause. This is specified in the documentation of your database, assuming you're using MySQL 5.0: http://dev.mysql.com/doc/refman/5.0/en/sorting-rows.html
If you can not influence the order on the database level, you're in the need to sort the array in PHP. You actually have an array of arrays, in which the outer array is just a list having the id (primary key) of each row and the other fields as a fieldname -> value array as a value (inner array).
Your sort is *user-defined` - you specify the sort order. A common way is to have a sort function that compares two entries which each other. That sort function needs to decide which of those two is of a higher sort-order than the other (or both have the same weight). In you case one item is higher than the other if one is the child of the other.
That's the general principle. You define the sort function that decides (the so called callback function), and PHP takes care to feed it with the array data to sort with the usortDocs function.
A sub-problem you need to solve then is to decide whether or not a child exists in the whole array (an item with a slug having the same value as parent). As this all looks like it can be a bit more complex, it's wise to encapsulate this all into a class of it's own.
Example / Demo:
class menuButtons
{
/**
* #var array
*/
private $buttons;
public function __construct(array $buttons)
{
$this->buttons = $buttons;
}
public function sortChildsFirst()
{
$buttons = $this->buttons;
usort($buttons, array($this, 'sortCallback'));
return $buttons;
}
private function sortCallback($a, $b)
{
// an element is more than any other if it's parent
// value is any other slugs value
if ($this->slugExists($a['parent']))
return 1;
return -1;
}
private function slugExists($slug)
{
foreach($this->buttons as $button)
{
if ($button['slug'] === $slug)
return true;
}
return false;
}
}
$buttons = new menuButtons($new_menu_buttons);
$order = $buttons->sortChildsFirst();
Note: This code is exploiting the fact that your sort order is only roughly specified. You only wrote that you need to have children before parents, so if you take all children first, this will always be the case. It's not that each parent will directly follow the child.
Nevertheless, this skeleton class can work as a base to further improve the search functionality as it's fully encapsulated. You can even change the whole sort method, e.g. to completely write one of your own even w/o usort, like outlined below. The main code does not need to change as it's only making use of the sortChildsFirst method.
You can sort an array once populated using the usort() function.
http://php.net/manual/en/function.usort.php
Since your structure is tree-alike, the first thing that comes to mind is to build a tree out of it. It goes like this:
$tree = array();
foreach($array as $e) {
$p = $e['parent'];
$s = $e['slug'];
if(!isset($tree[$p]))
$tree[$p] = new stdclass;
if(!isset($tree[$s]))
$tree[$s] = new stdclass;
$tree[$s]->data = $e;
$tree[$p]->sub[] = $tree[$s];
}
This creates a set of objects, with the members data and sub = list of child objects.
Now we iterate the tree and for each "root" node, add it and its children to the sorted array:
$out = array();
foreach($tree as $node)
if(!isset($tree[$node->data['parent']]))
add($out, $node);
where add() is
function add(&$out, $node) {
if(isset($node->data))
$out[] = $node->data;
if(isset($node->sub))
foreach($node->sub as $n)
add($out, $n);
}
hope this helps.
Ok, first let me thank you all for your detailed explanations. They are very intuitive. However, I found another way, can you guys let me know if you spot anything wrong with this method here please?
Click here to see a Demo of this working!
$temp_buttons = array();
foreach($new_menu_buttons as $buttons)
$temp_buttons[$buttons['parent']] = $buttons['slug'];
dp_sortArray($new_menu_buttons, $temp_buttons, 'slug');
// The $new_menu_buttons array is now sorted correctly! Let's check it...
var_dump($new_menu_buttons);
function dp_sortArray(&$new_menu_buttons, $sortArray, $sort)
{
$new_array = array();
$temp = array();
foreach ($new_menu_buttons as $key => $menuitem)
{
if (isset($sortArray[$menuitem[$sort]]))
{
$new_array[] = $menuitem;
$temp[$menuitem['parent']] = $menuitem['slug'];
unset($new_menu_buttons[$key]);
}
}
$ordered = array();
if (!empty($new_array))
{
foreach ($new_array as $key => $menuitem)
{
if (isset($temp[$menuitem[$sort]]))
{
$ordered[] = $menuitem;
unset($new_array[$key]);
}
}
}
else
{
$new_menu_buttons = $new_menu_buttons;
return;
}
$new_menu_buttons = array_merge($ordered, $new_array, $new_menu_buttons);
}
Seems to work in all instances that I tested, but ofcourse, their could be a flaw in it somewhere. What do you all think of this?

how to show data from 3 combinational table using codeIgniter

I have three database tables, question_set, question and answer.
question_set contains set_name and set_id
question contains question and also question_set_id
answer contains answer , question_id
I can not work out a way to show all the data in one view file,
I tried joins but then question data is repeating with it prints because every question has three or four answer.
Just thought I would point out.
Your database design is horrible.
It will not scale well, and infact I do not think it would actually. work.
The way I would do it is
Three tables
sets => id, name
questions => id, set_id, question
answers => id, set_id, question_id, answer, points
Note that in my above example I am taking it one step further, rather than each answer being true or false, it can have an assigned point value.
hence, an answer that you deemed half correct could be given 5 points, where as a correct answer could be given 10 points, it also works as a boolean true, just have a correct answer as 1 point, and an incorrect answer as 0 points
Anyway.
With the above table design in mind.
You could do
$this->db->select('s.id as set, s.name as name, q.id as qid, q.question as qu, a.id as aid, a.answer as an, a.points as p')
->from('sets s')
->join('questions q', 'q.set_id = s.id')
->join('answers a', 's.set_id = s.id')
->where('s.id', 'SET ID');
$questions = $this->db->get();
$set = array('questions' => array());
foreach($questions as $s){
$set['id'] = $s->set;
$set['name'] = $s->name;
$set['questions'][$s->qid]['id'] = $q->qid;
$set['questions'][$s->qid]['question'] = $q->qu;
if(!isset($set['questions'][$s->qid]['answers']))
$set['questions'][$s->qid]['answers'] = array();
$set['questions'][$s->qid]['answers'][] = array(
'id' => $q->aid,
'answer' => $q->an',
'points' => $q->p
);
}
So then you end up with an array that looks something like
array(
'id' => 1,
'name' => 'My first quiz',
'questions' = array(
array(
'id' => 1,
'question' => 'What is 1+1+1?',
'answers' => array(
array(
'id' => 1,
'answer' => 1,
'points' => 0
),
array(
'id' => 2,
'answer' => 2,
'points' => 0
),
array(
'id' => 3,
'answer' => 3,
'points' => 1
)
)
),
array(
'id' => 2,
'question' => 'What is 2+2+2?',
'answers' => array(
array(
'id' => 4,
'answer' => 6,
'points' => 1
),
array(
'id' => 5,
'answer' => 2,
'points' => 0
),
array(
'id' => 6,
'answer' => 3,
'points' => 0
)
)
)
)
);
Then you can do.
echo '<h2>'.$set['name'].'</h2>';
foreach($set['questions'] as $q){
echo '<div class="question">';
echo '<h3>'.$q['question'].'</h3>';
echo '<div class="answers">';
foreach($q['answers'] as $a){
echo '<label for="a'.$a['id'].'">'.$a['answer'].'<input type="checkbox value="'.$a['id'].'" name="q'.$q['id'].'" /></label><br />';
}
echo '</div>';
echo '</div>';
}
The easiest way, but which of course requires more SQL calls, is to use nested loops for this.
1) Join the question set and question tables
2) For each entry in the result set, retrieve the answers for that entry and put it in a separate array, nested in a bigger array where the key is the id of the question.
Your view would then look something like this:
foreach($questions as $question)
{
//Print question information
$answers = $answers_array[$question['id']];
foreach($answers as $answer)
{
//Print answers information
}
}
Might not be best practice but it will do the trick.

Categories