Hello for 5 days i really been searching and trying, but i think i cant array the tree or i cant really understand how to echo a select box with tree format like
<option>Workstations</option>
<option>--Macs</option>
<option>--Windows</option>
<option>Software</option>
<option>--Image editing</option>
<option>----Pro</option>
<option>----Semi pro</option>
My database estructure is
id | parent_id | name
I have been really close for example here im just missing a 3er level symbol, and so on.
https://stackoverflow.com/questions/16474767/asign-symbol-to-subcategory-inside-subcategory-in-selectbox-php
EDIT
how do you build an array like this from my database estructure, im learning, i havent learn arrays
$datas = array(
array('id' => 1, 'parent' => 0, 'name' => 'Page 1'),
array('id' => 2, 'parent' => 1, 'name' => 'Page 1.1'),
array('id' => 3, 'parent' => 2, 'name' => 'Page 1.1.1'),
array('id' => 4, 'parent' => 3, 'name' => 'Page 1.1.1.1'),
array('id' => 5, 'parent' => 3, 'name' => 'Page 1.1.1.2'),
array('id' => 6, 'parent' => 1, 'name' => 'Page 1.2'),
array('id' => 7, 'parent' => 6, 'name' => 'Page 1.2.1'),
array('id' => 8, 'parent' => 0, 'name' => 'Page 2'),
array('id' => 9, 'parent' => 0, 'name' => 'Page 3'),
array('id' => 10, 'parent' => 9, 'name' => 'Page 3.1'),
array('id' => 11, 'parent' => 9, 'name' => 'Page 3.2'),
array('id' => 12, 'parent' => 11, 'name' => 'Page 3.2.1'),
);
This array would make this code works, =( , i think
<?PHP
$datas = mysql_query("SELECT id, parent_id, name FROM category");
function generatePageTree($datas, $depth = 0, $parent = 0){
if($depth > 1000) return ''; // Make sure not to have an endless recursion
$tree = '';
for($i=0, $ni=count($datas); $i < $ni; $i++){
if($datas[$i]['parent'] == $parent){
$tree .= str_repeat('-', $depth);
$tree .= $datas[$i]['name'] . '<br/>';
$tree .= generatePageTree($datas, $depth+1, $datas[$i]['id']);
}
}
return $tree;
}
echo(generatePageTree($datas));
?>
I would use a few for loops and recursive function to do this. Pretty much what it'll do is take each result from your query, and search for children in the results. Use a query that gets the id and parent_id for all the rows. You'll also want a function that turns the results into a 2-d array with the first layer is the row, and then the column i.e. $result[0]['ID']; would be the id for the first row.
You could use a query like
SELECT id, parent_id, name from YOUR_TABLE_HERE;
$num=count($results);
for($i=0;$i<$num;$i++) {
$id=$results[$i]['id'];
if($results[$i]['parent_id']===null) {
echo "<option>".$results[$i]['name']."</option>";
}
for($j=0;$j<$num;$j++) {
if($results[$j]['parent_id']==$id) {
search($results[$j][$id],$results,"-");
}
}
}
//the level_delim is just the string that signifies the level i.e. ---
function search($id, $results,$level_delim) {
$num=count($results);
for($i=0;$i<$num;$i++) {
if($results[$i]['parent_id']==$id) {
echo "<option>".$level_delim."-".$results[$i]['name']."</option>"
search($results[$i]['id],$results,$level_delim."-");
}
}
}
function allResults(mysqli_result $result) {
$array=array();
for($row=0;$row<mysqli_num_rows($result);$row++) { //get all the rows and gett array
$array[$row]= mysqli_fetch_assoc($result);
}
return $array;
}
Related
I have a hierarchical database table like below
ID Name Subcategory ParentID
1 ABC 0
2 DEF QFE 0
3 QFE XYZ 2
4 XYZ MNJ 3
From Thant I have got PHP array like below
$array_name = array(
array('ID' => '1', 'Name' => 'ABC', 'Subcategory' => '', 'ParentID' => '0'),
array('ID' => '2', 'Name' => 'DEF', 'Subcategory' => 'QFE', 'ParentID' => '0'),
array('ID' => '3', 'Name' => 'QFE', 'Subcategory' => 'XYZ', 'ParentID' => '2'),
array('ID' => '4', 'Name' => 'XYZ', 'Subcategory' => 'MNJ', 'ParentID' => '3')
);
but I want array like below
$array_name = array(
array('ID' => '1', 'Name' => 'ABC', 'Subcategory' => '', 'ParentID' => '0'),
array('ID' => '2', 'Name' => 'DEF', 'Subcategory' => array('ID' => '3', 'Name' => 'QFE', 'Subcategory' => array('ID' => '4', 'Name' => 'XYZ', 'Subcategory' => 'MNJ', 'ParentID' => '3'), 'ParentID' => '2'), 'ParentID' => '0'),
);
I want a function which checks is that row have some Subcategory or not and if a row has Subcategory then get that subcategory row as an array and make one array with all category and Subcategory
for that, I have tried to make a function which is given below
function find_subcategory($ID,$con){
$table_name ="SELECT * FROM `table_name` WHERE `parent_id` = '$ID'";
$table_name_result = mysqli_query($con,$table_name);
$category_array = array();
if(mysqli_num_rows($table_name_result)) {
while($row = mysqli_fetch_assoc($table_name_result)) {
$Subcategory= $row['Subcategory'];
$ID = $row['ID'];
if ($Subcategory== '') {
$find_subcategory = find_subcategory($ID,$con);
$row['Subcategory'] = $find_subcategory;
$category_array[] = $row;
}else{
$category_array[] = $row;
}
}
}
return json_encode(array('tbl_category'=>$category_array));
}
but this function is not working to get all the subcategories of one category.
can anybody help me with this
Rather than create a recursive routine, which executes the SQL for each level, this instead reads all of the categories in and them assembles them into the hierarchy.
Note that it reads them in reverse order so that when it assembles them, each subcategory is always read before the parent (More details in code comments)...
$table_name ="SELECT * FROM `category` ORDER BY parent_id DESC, id desc";
$table_name_result = mysqli_query($con,$table_name);
$categories = mysqli_fetch_all($table_name_result, MYSQLI_ASSOC);
$output= [];
foreach ( $categories as $category) {
// If there is a parent for this item
if ( !empty ($category['parent_id']) ) {
// Set basic details
$output[$category['parent_id']]['Subcategory'][$category['id']] = $category;
// If there is already some data (subcategories)
if ( isset($output[$category['id']]) ){
// Copy subcategories
$output[$category['parent_id']]['Subcategory'][$category['id']] +=
$output[$category['id']];
// Remove old node
unset ( $output[$category['id']] );
}
}
else {
// Add in category data (allow for existing data to be added
$output[$category['id']] = $category + ($output[$category['id']]??[]);
}
}
I successfully implemented and tested a recursive routine to solve this. However, for performance reasons I had to decouple the access to the database from the recursive call.
First, you fetch your query into an array as you already have and then recursively rearrange the elements so that the keys are nested in the proper order.
Pretty much of the explanations I'd like to put here are put as comments in the code.
$array_name = array(
array('ID' => '1', 'Name' => 'ABC', 'Subcategory' => '', 'ParentID' => '0'),
array('ID' => '2', 'Name' => 'DEF', 'Subcategory' => 'QFE', 'ParentID' => '0'),
array('ID' => '3', 'Name' => 'QFE', 'Subcategory' => 'XYZ', 'ParentID' => '2'),
array('ID' => '4', 'Name' => 'XYZ', 'Subcategory' => 'MNJ', 'ParentID' => '3'),
array('ID' => '5', 'Name' => 'XYY', 'Subcategory' => 'MNJ', 'ParentID' => '1')
);
// recreate nested array
function get_nested_array($arr) {
$new_arr = array(); // new array to collect each top level element with nesting
foreach ($arr as $key => $value) {
// only top level elements would appear here as they would not be nested
if($value['ParentID'] == '0') {
array_push($new_arr, get_nested_item($value, $arr));
}
}
return $new_arr;
}
// recursive function to perform nesting on each element
function get_nested_item($hay, $stack) {
foreach ($stack as $key => $value) {
if ($hay['ID'] == $value['ParentID']) {
$index = get_key($hay, $stack);
// reduce $stack size by removing the HAY from the STACK
// recursion terminates when $stack size is 0
$stack = $index >= 0 ? array_splice($stack, $index) : [];
// update subcategory of the found nesting
$hay['Subcategory'] = get_nested_item($value, $stack);
}
}
return $hay;
}
// get the position of $hay in a $stack using the ID
function get_key($hay, $stack) {
foreach ($stack as $key => $value) {
if($hay['ID'] == $value['ID']) return $key;
}
return -1;
}
// print array so that it understandable
function print_array($arr) {
foreach ($arr as $key => $value) {
print_r($value);
echo "<br>";
}
}
// Test case
// print array before nesting
print_array($array_name);
echo"<br>";
// print array after nesting
$new_array = get_nested_array($array_name);
print_array($new_array);
I just want some help in displaying the correct structure of the image data below. Basically what i want is to display it in nested form. From the data below, I would like it to display like this:
Engel (parent which parent_id = 0)
Chest Fridge - Freezers
Small Engel
digital platinum
Upright Fridge
Built-in fridge
Fridge Accessories
Blankets
Carry handles
I hope anyone can help me. Im using php fyi.
Do it recursively
// For example, data fetched from database:
$data = [
['id' => 1, 'sku' => 'name1', 'parent_id' => null],
['id' => 2, 'sku' => 'name12', 'parent_id' => 1],
['id' => 3, 'sku' => 'name12', 'parent_id' => 1],
['id' => 4, 'sku' => 'name2', 'parent_id' => null],
['id' => 5, 'sku' => 'name123', 'parent_id' => 2],
];
// Recursive function
function outTree($data, $parentId = null) {
$str = '';
foreach ($data as $row) {
if ($row['parent_id'] == $parentId) {
$str .= '<li>' . $row['sku'];
$str .= outTree($data, $row['id']);
$str .= '</li>';
}
}
if ($str) {
$str = '<ul>' . $str . '</ul>';
}
return $str;
}
echo outTree($data);
I would like to diplay comments on my site like this:
<li>Parent
<ul>
<li>child one</li>
<li>child two
<ul>
<li>grandchild</li>
<li>other grandchild</li>
</ul>
</li>
</ul>
<li>Another parent with no children</li>
<li>
I have read the following article, however it doesn't use <li>. So is there a way to display comments like I've done before with an array like so? Thanks.
$comments = array(
array('id'=>1, 'parent_id'=>NULL, 'text'=>'Parent'),
array('id'=>2, 'parent_id'=>1, 'text'=>'Child'),
array('id'=>3, 'parent_id'=>2, 'text'=>'Child Third level'),
array('id'=>4, 'parent_id'=>NULL, 'text'=>'Second Parent'),
array('id'=>5, 'parent_id'=>4, 'text'=>'Second Child')
);
I asssume your comment table has id, parent_id, comment, ... and my suggestion goes like this;
Select you comments like;
$sql = "SELECT *FROM comments ORDER BY id DESC";
$rows = mysql_query($sql);
And next step is array operations.You can see the following code below and try working demo here;
$rows = your_select_result;//I assumed that you have done these stuffs
$comments = $row;
/**
This is test data, please remove this array while you are
running own application.Since you will use the data one you get your db
**/
$comments = array(
1 => array('id' => 1, 'parent_id' => 0, 'childs' => array()),
2 => array('id' => 2, 'parent_id' => 0, 'childs' => array()),
3 => array('id' => 3, 'parent_id' => 0, 'childs' => array()),
5 => array('id' => 5, 'parent_id' => 0, 'childs' => array()),
11 => array('id' => 11, 'parent_id' => 0, 'childs' => array()),
17 => array('id' => 17, 'parent_id' => 0, 'childs' => array()),
23 => array('id' => 23, 'parent_id' => 0, 'childs' => array()),
28 => array('id' => 28, 'parent_id' => 0, 'childs' => array()),
4 => array('id' => 4, 'parent_id' => 1, 'childs' => array()),
6 => array('id' => 6, 'parent_id' => 1, 'childs' => array()),
8 => array('id' => 8, 'parent_id' => 2, 'childs' => array()),
9 => array('id' => 9, 'parent_id' => 2, 'childs' => array()),
7 => array('id' => 7, 'parent_id' => 3, 'childs' => array()),
12 => array('id' =>12, 'parent_id' => 7, 'childs' => array()),
13 => array('id' => 13, 'parent_id' => 12, 'childs' => array()),
);
/** Comment prepare start */
foreach ($comments as $k => &$v) {
if ($v['parent_id'] != 0) {
$comments[$v['parent_id']]['childs'][] =& $v;
}
}
unset($v);
foreach ($comments as $k => $v) {
if ($v['parent_id'] != 0) {
unset($comments[$k]);
}
}
/** Comment prepare end */
//Your indent pattern
function indent($size) {
$string = "";
for ($i = 0; $i < $size; $i++) {
$string .= "#";
}
echo $string;
}
function printComments($comments, $indent = 0) {
foreach ($comments as $comment) {
echo indent($indent + 1).' I am comment '.$comment['id']."\n";
if (!empty($comment['childs'])) {
printComments($comment['childs'], $indent + 1);
}
}
}
printComments($comments);
For demo please see here
BTW, in case of using Materialized Path technique, you won't need no recursion nor nested array or stuff.
Just plain linear outpur from the database.
To do that just create a field named path in your database and fill it with all the parent id's, padded to some considerabe length.
Say, example tree may look like
id 1 root path
id 3 root 1 path 000000001
id 5 root 1 path 000000001000000003
id 4 root 1 path 000000001
id 2 root path 000000002
id 6 root 2 path
so, querying your table by simple ORDER BY root DESC, path ASC
you will get your tree as a simple already ordered list
This function will only need the parent_id and id key present in each comment's array.
$comments = array(
array('id'=>1, 'parent_id'=>NULL, 'text'=>'Parent'),
array('id'=>2, 'parent_id'=>1, 'text'=>'Child'),
array('id'=>3, 'parent_id'=>2, 'text'=>'Child Third level'),
array('id'=>4, 'parent_id'=>NULL, 'text'=>'Second Parent'),
array('id'=>5, 'parent_id'=>4, 'text'=>'Second Child')
);
This will return a multidimensional array. If one item has no children, $comment['children'] will equal NULL, otherwise the respective array of children will be attached.
function arrangecomments($comments){
$tree = array();
/* We get all the parent into the tree array */
foreach ($comments as &$node) {
/* Note: I've used 0 for top level parent, you can change this to == 'NULL' */
if($node['parent_id']=='0'){
$tree[] = $node;
unset($node);
}
}
/* This is the recursive function that does the magic */
/* $k is the position in the array */
function findchildren(&$parent, &$comments, $k=0){
if (isset($comments[$k])){
if($comments[$k]['parent_id']==$parent['id']){
$com = $comments[$k];
findchildren($com, $comments); // We try to find children's children
$parent['children'][] = $com;
}
findchildren($parent, $comments, $k+1); // And move to the next sibling
}
}
/* looping through the parent array, we try to find the children */
foreach ($tree as &$parent) {
findchildren($parent, $comments);
}
return $tree;
}
I know it can be improved a lot, but it works, and I haven't found any bugs so far. Hope it helps!
hi i have a database table , i want to set that as a tree structure and get the leaf nodes of that tree .
in this table i have PreferenceID and PreferenceParentID.
in this case i want to built a tree .
level 1 should be fashion and music , because they have the PreferenceParentID = 0
in 2 nd level men's clothing should be under fashion because it's parent preference id is fashion . and Artists sholud be under music .
in 3 level couture and denims should be under men's clothing and african and afrobeat shoul be under Artists.
and i want to get all the leaf node values . in this case i want to get
couture and denims and africanandafrobeat`.
tree may grow up to n levels .
please help me . any suggestion is welcome ....................... :D
In response to Chauhan's linked article, I'd like to post a much simpler solution:
// sample data (from one big query selecting them in one go)
$rows = array(
array('id' => 971, 'parent_id' => 3, 'label' => 'Genres'),
array('id' => 972, 'parent_id' => 3, 'label' => 'Movie Stars'),
array('id' => 1, 'parent_id' => 0, 'label' => 'Fashion'),
array('id' => 32, 'parent_id' => 1, 'label' => 'Men\'s Clothing'),
array('id' => 45, 'parent_id' => 32, 'label' => 'Couture'),
array('id' => 55, 'parent_id' => 32, 'label' => 'Denims'),
array('id' => 2, 'parent_id' => 0, 'label' => 'Music'),
array('id' => 970, 'parent_id' => 2, 'label' => 'Artists'),
array('id' => 1118, 'parent_id' => 970, 'label' => 'African'),
array('id' => 1119, 'parent_id' => 970, 'label' => 'Afrobeat'),
);
// build map and collect ids
$map = array();
$ids = array();
foreach ($rows as $row) { // one could use the typical mysql_fetch_* stuff here
if (!isset($map[$row['parent_id']])) {
$map[$row['parent_id']] = array();
}
$map[$row['parent_id']][] = $row;
$ids[] = $row['id'];
}
// recursive helper display
function helper($map, $parentId = 0) {
echo '<ul>';
foreach ($map[$parentId] as $entry) {
printf('<li>[%s] %s', $entry['id'], $entry['label']);
if (isset($map[$entry['id']])) {
helper($map, $entry['id']);
}
echo '</li>';
}
echo '</ul>';
}
// create ul
helper($map);
// the leaf nodes
print_r(
array_diff($ids, array_keys($map))
);
I also like to say, that, if such database structures cannot be avoided, recursive queries is probably the worst thing to do, performance wise.
Recursive function can help you to generate parent/child tree. Find below link for more detail:
http://psoug.org/snippet/Recursive_function_to_generate_a_parentchild_tree_338.htm
i want to do discus/reddit/ like commenting system, i have an "id_answer" (set to 0 by defaut) field in my comment database and when user answer to another comment this field is the "id" of the parent comment.
I have the comments of the thread in an array but i dont know how to filter filter each loop for get something like this :
comment lvl 1 ($array[id_answer] is 0)
------- comment lvl 2 ($array[id_answer] is id_of_level_one_comment)
--------------- comment lvl 3 ...
Use three fields in your database;
"id", unique for each comment
"parent_id", which is either 0 (top level comment) or the "id" of the parent comment
"thread_id", which is the id of whatever you are commenting on
Let's say you want to show the comment tree for your news article with id "123"
When selecting from mysql, select everything with this thread_id:
SELECT id, parent FROM comments WHERE thread_id = 123
Then you should pre-parse your array to give the child comments to their parents, and use a recursive display to show each comment and its child list.
For exemple:
// getting the comments from mysql, I'm obviously not bothering
// to check the return value, but in your code you should do it
$result = mysqli_query("SELECT id, parent FROM comments WHERE thread_id = 123");
$comments = array();
while ($row = mysqli_fetch_array($result)) {
$row['childs'] = array();
$comments[$row['id']] = $row;
}
// This is the array you get after your mysql query
// Order is non important, I put the parents first here simply to make it clearer.
/*
$comments = array(
// some top level (parent == 0)
1 => array('id' => 1, 'parent' => 0, 'childs' => array()),
5 => array('id' => 5, 'parent' => 0, 'childs' => array()),
2 => array('id' => 2, 'parent' => 0, 'childs' => array()),
10 => array('id' => 10, 'parent' => 0, 'childs' => array()),
// and some childs
3 => array('id' => 3, 'parent' => 1, 'childs' => array()),
6 => array('id' => 6, 'parent' => 2, 'childs' => array()),
4 => array('id' => 4, 'parent' => 2, 'childs' => array()),
7 => array('id' => 7, 'parent' => 3, 'childs' => array()),
8 => array('id' => 8, 'parent' => 7, 'childs' => array()),
9 => array('id' => 9, 'parent' => 6, 'childs' => array()),
);
*/
// now loop your comments list, and everytime you find a child, push it
// into its parent
foreach ($comments as $k => &$v) {
if ($v['parent'] != 0) {
$comments[$v['parent']]['childs'][] =& $v;
}
}
unset($v);
// delete the childs comments from the top level
foreach ($comments as $k => $v) {
if ($v['parent'] != 0) {
unset($comments[$k]);
}
}
// now we display the comments list, this is a basic recursive function
function display_comments(array $comments, $level = 0) {
foreach ($comments as $info) {
echo str_repeat('-', $level + 1).' comment '.$info['id']."\n";
if (!empty($info['childs'])) {
display_comments($info['childs'], $level + 1);
}
}
}
display_comments($comments);
This give the following result:
- comment 1
-- comment 3
--- comment 7
---- comment 8
- comment 5
- comment 2
-- comment 6
--- comment 9
-- comment 4
- comment 10
I leave the ORDER BY and such to you, as it should not pose any problem.