I have a table like
id catagory suboff
1 software 0
2 programming 1
3 Testing 1
4 Designing 1
5 Hospital 0
6 Doctor 5
7 Nurses 5
9 Teaching 0
10 php programming 2
11 .net programming 2
How to write a code to get all these information in a multidimensional array based on the suboff as follows,
-software
--programming
---php programming
--- .net programming
--testing
--designing
-hospital
--doctor
--nurses
-teaching
Assuming MySQL as your DB engine:
// We'll need two arrays for this
$temp = $result = array();
// Get the data from the DB
$table = mysql_query("SELECT * FROM table");
// Put it into one dimensional array with the row id as the index
while ($row = mysql_fetch_assoc($table)) {
$temp[$row['id']] = $row;
}
// Loop the 1D array and create the multi-dimensional array
for ($i = 1; isset($temp[$i]); $i++) {
if ($temp[$i]['suboff'] > 0) {
// This row has a parent
if (isset($temp[$temp[$i]['suboff']])) {
// The parent row exists, add this row to the 'children' key of the parent
$temp[$temp[$i]['suboff']]['children'][] =& $temp[$i];
} else {
// The parent row doesn't exist - handle that case here
// For the purposes of this example, we'll treat it as a root node
$result[] =& $temp[$i];
}
} else {
// This row is a root node
$result[] =& $temp[$i];
}
}
// unset the 1D array
unset($temp);
// Here is the result
print_r($result);
Use references for a job like this.
Demo: http://ideone.com/vk4po
$array = array(
array('1','software','0'),
array('2','programming','1'),
array('3','Testing','1'),
array('4','Designing','1'),
array('5','Hospital','0'),
array('6','Doctor','5'),
array('7','Nurses','5'),
array('9','Teaching','0'),
array('10','php programming','2'),
array('11','.net programming','2')
);
function menu_sort($results, $master = 0)
{
$open = array();
$return = NULL;
foreach($results as $result)
{
if($result[2] == $master){
if(!$open){
$return .= '<ul>';
$open = true;
}
$return .= '<li>'.$result[1];
$return .= menu_sort($results, $result[0]);
$return .= '</li>';
}
}
if($open)
$return .= '</ul>';
return $return;
}
echo menu_sort($array);
Result...
software
programming
php programming
.net programming
Testing
Designing
Hospital
Doctor
Nurses
Teaching
The way I would do that:
First you need to parse this table. I assume you can do it yourself; if not, Google "regular expressions", they are your friends.
The data structure you are working with is a classical tree. You will need two arrays to work with it. First is an array of nodes, $nodes, where the keys are the node IDs and values are node names, and $links, where each key is a parent node and each value is an array of children ($links[$id][] = $suboff for each element would suffice).
Now you have to recursively descent the tree you have. You introduce a function with a signature like this:
function print_node( $nodeID, $level = 1 )
This function should print the node itself (info stored in $nodes) with $level padding dashes and call itself to render all children nodes. They will in turn render all their subnodes, etc. You just have to call this function for top-level nodes.
This class converst a flat category array into a structured tree array:
<?php
/**
* Creates a structured tree out of a flat category list
*/
class CategoryTree {
/**
*
* #var array
*/
protected $categories = array();
/**
*
* #var array
*/
protected $tree = array();
/**
* Default constructor
* #param array $categories
*/
function __construct(array $categories) {
$this->categories = $categories;
}
/**
* Process a subtree
* #param array $categories
* #param integer $parentId
* #return array
*/
protected function getSubtree(array $categories, $parentId = 0) {
$tree = array();
foreach($categories as $category) {
if($category['suboff'] == $parentId) {
$tree[$category['id']] = $category;
$tree[$category['id']]['children'] = $this->getSubtree($categories, $category['id']);
}
}
return $tree;
}
/**
* Get the category tree as structured array
* #return array
*/
public function getTree() {
if(empty($this->tree)) {
$this->tree = $this->getSubtree($this->categories, 0);
}
return $this->tree;
}
/**
* Get the category tree as string representation
* #return string
*/
public function __toString() {
return "<pre>" . print_r($this->getTree(), true) . "</pre>";
}
}
// Now, use the class with the givven data:
$categories = array(
array(
'id' => 1,
'category' => 'software',
'suboff' => 0
),
array(
'id' => 2,
'category' => 'programming',
'suboff' => 1
),
array(
'id' => 3,
'category' => 'Testing',
'suboff' => 1
),
array(
'id' => 4,
'category' => 'Designing',
'suboff' => 1
),
array(
'id' => 5,
'category' => 'Hospital',
'suboff' => 0
),
array(
'id' => 6,
'category' => 'Doctor',
'suboff' => 5
),
array(
'id' => 7,
'category' => 'Nurses',
'suboff' => 5
),
array(
'id' => 9,
'category' => 'Teaching',
'suboff' => 0
),
array(
'id' => 10,
'category' => 'php programming',
'suboff' => 2
),
array(
'id' => 11,
'category' => '.net programming',
'suboff' => 2
)
);
$myTree = new CategoryTree($categories);
echo $myTree;
?>
This is what I just wrote for my app, and it works like a charm :)
$array = [
'i' => ['key' => 'i', 'name' => 'php programming', 'parent' => 'b'],
'g' => ['key' => 'g', 'name' => 'Nurses', 'parent' => 'e'],
'j' => ['key' => 'j', 'name' => '.net programming', 'parent' => 'b'],
'b' => ['key' => 'b', 'name' => 'programming', 'parent' => 'a'],
'a' => ['key' => 'a', 'name' => 'software', 'parent' => 'asd'],
'c' => ['key' => 'c', 'name' => 'Testing', 'parent' => 'a'],
'd' => ['key' => 'd', 'name' => 'Designing', 'parent' => 'a'],
'e' => ['key' => 'e', 'name' => 'Hospital', 'parent' => 'asd'],
'f' => ['key' => 'f', 'name' => 'Doctor', 'parent' => 'e'],
'h' => ['key' => 'h', 'name' => 'Teaching'],
];
function getAsTree(array &$array)
{
foreach ($array as $key => $item) {
if (isset($item['parent']) && isset($array[$item['parent']])) {
$array[$item['parent']]['children'][] = $item;
unset($array[$key]);
return getAsTree($array);
}
}
return $array;
}
And here is the result:
--- a: software
------ b: programming
--------- i: php programming
--------- j: .net programming
------ c: Testing
------ d: Designing
--- e: Hospital
------ g: Nurses
------ f: Doctor
--- h: Teaching
IMHO the logic is:
Get all the roots element (software, hospital and so on)
Foreach root take the subelement(s) (for the software you'll take programming, testing and designing)
Add the subelement(s) as subarray
Loop recursively on the subarray(s) you just add
You'll want to read the whole table into memory and turn it into a tree where each node can be identified with its corresponding id number. Then do a pre-order traversal of the tree to print it out.
In PHP wenn i get the data from a Database:
"SELECT* FROM Table WHERE suboff LIKE 0"
foreach(item..)
"SELECT* FROM Table WHERE suboff LIKE item.ID"
foreach(item2..)
$result[item][item2]
Here is a different approach that should be very easy to understand. It requires you to have the table ordered by suboff, i.e.
SELECT * FROM table ORDER BY suboff
Assuming the result is stored in $table, you can use this very concise php code:
// this will hold the result
$tree = array();
// used to find an entry using its id
$lookup = array();
foreach($table as $row){
if($row['suboff'] === 0){
// this has no parent, add it at base level
$tree[$row['category']] = array();
// store a reference
$lookup[$row['id']] =& $tree[$row['category']];
}else{
// find the right parent, add the category
$lookup[$row['suboff']][$row['category']] = array();
// store a reference
$lookup[$row['id']] =& $lookup[$row['suboff']][$row['category']];
}
}
This solution works fine for me.
$array = array(
array('1','software','0'),
array('2','programming','1'),
array('3','Testing','1'),
array('4','Designing','1'),
array('5','Hospital','0'),
array('6','Doctor','5'),
array('7','Nurses','5'),
array('9','Teaching','0'),
array('10','php programming','2'),
array('11','.net programming','2')
);
$newArray = getTree($array);
function getTree( $rows, $suboff = 0) {
$return = array();
foreach($rows as $row) {
if($row[2] == $suboff){
$newrow = $row;
$subs = $this->getTree($rows, $row[0]);
if ( !empty($subs) ) {
$newrow['subs'] = $subs;
}
$return[] = $newrow;
}
}
return $return;
}
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 want to convert this:
$arr = [
[
'type' => 'fruit',
'name' => 'apple',
'cost' => 1
],
[
'type' => 'fruit',
'name' => 'orange',
'cost' => 2
],
[
'type' => 'vegetable',
'name' => 'carrot',
'cost' => 2.5
],
[
'type' => 'vegetable',
'name' => 'avocado',
'cost' => 3.5
]
];
Into this:
$arr = [
[
'type' => 'fruit',
'apple' => '1',
'orange' => 2
],
[
'type' => 'vegetable',
'carrot' => 2.5,
'avocado' => 3.5
]
];
As you can see, I'm needing to group each type in a single array and pivoting fruit name and cost.
Here's a method for obtaining that exact array structure in the output. This was a touch trickier than I thought it would be:
//first build groups by type
$groups = array();
foreach($arr as $key => $array){
//$type is not necessary, it's just for clarity below
$type = $array['type'];
if( !isset($groups[$type]) ){
$groups[$type] = array();
$groups[$type]['type'] = $array['type'];
}
$groups[$type][$array['name']] = $array['cost'];
}
//then combine the groups into a master array
$out = array();
foreach($groups as $g){
$out[] = $g;
}
echo '<pre>'. print_r($out, true).'</pre>';
For something like this simply looping through your array as Rizier suggests should do the trick. If you're grouping by type, it would probably be easiest to use the type as the array key, so the format would be slightly different than you've requested. You'd be able access your resulting array like this:
$fruitItems = $newArr['fruit'];
Here's sample code:
$size = count($itemArray);
$newArr = []; //The array you want to create
for ($i = 0; $i < $size; $i++)
{
$item = $itemArray[$i];
$type = $item['type'];
$name = $item['name'];
$cost = $item['cost']
//If your new array doesn't have this type yet, make a sub-array
//with the type as key
if (!isset($newArr[$type]))
$newArr[$type] = [];
$newArr[$type][$name] = $cost; //In your type sub-array, add the new item
}
If you absolutely have to create an array with that structure, you can tweak the above code a little bit to search through your array and find the sub-array with the correct type. However, that seems a little over complicated.
In case someone needs a little more generic approch and has to handle multiple values in the same column I enlarged #larsAnders solution a bit.
Usage (to get the exact required output):
$pivot_fruits = arr_pivot($arr, 'type', 'name', 'cost', 'sum', false, false);
Function:
function arr_pivot(
$arr,
$arr_key_to_pivot_for_rows,
$arr_key_to_pivot_for_columns,
$arr_key_to_pivot_for_values,
$grouping_method = "sum",
$add_missing_columns=true,
$sort_columns=true){
if(!is_array($arr)) return false;
$pivot_row = $arr_key_to_pivot_for_rows;
$pivot_col = $arr_key_to_pivot_for_columns;
$pivot_val = $arr_key_to_pivot_for_values;
//first build groups by $col_name_to_pivot_for_rows
$row_groups = [];
$columns=[];
foreach ($arr as $row_key => $row) {
$group_label = $row[$pivot_row];
$col_label = $row[$pivot_col];
$value = $row[$pivot_val];
if( !isset($row_groups[$group_label]) ){
$row_groups[$group_label]=[];
$row_groups[$group_label][$pivot_row] = $group_label;
}
if(!isset($columns[$col_label])) $columns[$col_label]=[];
$row_groups[$group_label][$col_label][]=$value;
}
//then combine the groups into a return array
$arr_pivoted = [];
foreach($row_groups as $row_group){
//all columns except of the first one are pivoted columns. split into the row name and the columns itself
$row_group_columns = $row_group;
$row_group_row = array_shift($row_group_columns);
//ensure that all groups have all columns
if($add_missing_columns) $row_group_columns = array_merge($columns,$row_group_columns);
if($sort_columns) ksort($row_group_columns);
$row_group_columns_grouped=[];
//apply grouping function to columns
foreach ($row_group_columns as $column_name => $row_group_column){
$acount=count($row_group_column);
switch ($grouping_method){
default:
case 'sum':
$row_group_columns_grouped[$column_name] = array_sum($row_group_column);
break;
case 'avg':
$row_group_columns_grouped[$column_name] = $acount == 0 ? 0 : array_sum($row_group_column) / count($row_group_column);
break;
case 'count':
$row_group_columns_grouped[$column_name] = count($row_group_column);
break;
case 'max':
$row_group_columns_grouped[$column_name] = $acount == 0 ? 0 : max($row_group_column);
break;
case 'min':
$row_group_columns_grouped[$column_name] = $acount == 0 ? 0 : min($row_group_column);
break;
case 'concat':
case 'implode':
$row_group_columns_grouped[$column_name] = implode(',',$row_group_column);
break;
}
}
$arr_pivoted[] = array_merge([$pivot_row=>$row_group_row],$row_group_columns_grouped);
}
return $arr_pivoted;
}
PHPDoc:
/**
* Turns 2 dimensional array in a pivoted version
*
* #param array $arr 2 dimensional to pivot
* #param string $arr_key_to_pivot_for_rows input array key to use as rows
* #param string $arr_key_to_pivot_for_columns input array key to use as columns
* #param string $arr_key_to_pivot_for_values input array key to use as values
* #param string $grouping_method method to use on values out of sum|count|avg|min|max|concat. If values are not numeric use count or concat
* #param bool $add_missing_columns if true all occurring columns in any row are added if missing
* #param bool $sort_columns if true all columns will be sorted by column name (=key)
* #return array|bool false if input is not an array otherwise the pivoted result as 2 dimensional array
*/
If someone feels the urge to improve coding style, input validation and/or variable naming I would be very glad.
This task is as simple as grouping related data using temporary first level keys.
$array = [
['type' => 'fruit', 'name' => 'apple', 'cost' => 1],
['type' => 'fruit', 'name' => 'orange', 'cost' => 2],
['type' => 'vegetable', 'name' => 'carrot', 'cost' => 2.5],
['type' => 'vegetable', 'name' => 'avocado', 'cost' => 3.5]
];
$result = [];
foreach ($array as $row) {
$result[$row['type']]['type'] = $row['type'];
$result[$row['type']][$row['name']] = $row['cost'];
}
var_export(array_values($result));
Contrary to what is demonstrated by other answers on this page, parent elements do not need to be instantiated/declared before assigning a child element. (The same cannot be said for when assigning child properties in an object.) There is also no need for conditions or multiple loops for this basic task.
Output:
array (
0 =>
array (
'type' => 'fruit',
'apple' => 1,
'orange' => 2,
),
1 =>
array (
'type' => 'vegetable',
'carrot' => 2.5,
'avocado' => 3.5,
),
)
You can also abuse a body-less foreach() loop's destructuring syntax to perform the pivot. (Demo)
$array = [
['type' => 'fruit', 'name' => 'apple', 'cost' => 1],
['type' => 'fruit', 'name' => 'orange', 'cost' => 2],
['type' => 'vegetable', 'name' => 'carrot', 'cost' => 2.5],
['type' => 'vegetable', 'name' => 'avocado', 'cost' => 3.5]
];
$result = [];
foreach ($array as ['type' => $type, 'type' => $result[$type]['type'], 'name' => $name, 'cost' => $result[$type][$name]]);
var_export(array_values($result));
This provides the same result as above. Notice how the type key is written twice while destructuring -- it looks invalid, but it actually works.
Im trying to list categories with sub categories in my app - I can use either PHP or Javascript / Jquery for the following:
I have an array of categories with sub categories appended as additional arrays
the trick is that it can go as deep as there are sub categories.
and sub categories can also have sub categories.
Therefore for each category it can have as many children each of whom can have many children arrays.
What would be the best way to loop through them to create a dropdown list?
Here is the structure when dumping the main array:
array (size=2)
0 =>
array (size=4)
'id' => int 1
'name' => string 'Stationery' (length=10)
'parent_id' => int 0
'childs' =>
array (size=1)
0 =>
array (size=4)
...
1 =>
array (size=3)
'id' => int 4
'name' => string 'boots' (length=5)
'parent_id' => int 0
notice sub zero has a "childs" array
when dumping this array i get:
array (size=1)
0 =>
array (size=4)
'id' => int 2
'name' => string 'pens' (length=4)
'parent_id' => int 1
'childs' =>
array (size=1)
0 =>
array (size=4)
...
Notice this too has a child attached which when dumped looks like:
array (size=1)
0 =>
array (size=4)
'id' => int 3
'name' => string 'penfillers' (length=10)
'parent_id' => int 2
'childs' =>
array (size=1)
0 =>
array (size=3)
...
Sneaky - this one also has another child!
This can go as deep as there are sub categories
How would i loop through them and have the output in a dropdown list?
Im stumped as to how to loop infinitely until the chain ends.
Thanks
Jason
You should recursively yield all the options in the array. There are 2 ways to implement it. Depends on your PHP version.
To make the core logic cleaner, let's say we'd render the output with these utilities:
//
// some function to tidy up outputs
//
// simply make the recursive level visible
function pad_level($string, $level) {
// no pad for 0 level
if ($level == 0) return $string;
// pad some '-' to show levels
$pad = str_repeat('-', $level);
return $pad . ' ' . $string;
}
// render a leaf into standardized info array for an option
function option_from($item, $level) {
return array(
'value' => $item['id'],
'display_value' => pad_level($item['name'], $level),
);
}
// render options into HTML select
function render_select($name, $options) {
$output = '';
foreach ($options as $option) {
$output .= ' '.
'<option value="'.htmlspecialchars($option["value"]).'">'.
htmlspecialchars($option["display_value"]).
'</option>'."\n";
}
return '<select name="'.htmlspecialchars($name).'">'."\n".
$output."</select>\n";
}
// render options into plain text display
function render_plain_text($name, $options) {
$output = '';
foreach ($options as $option) {
$output .= $option["value"].' => '.$option["display_value"]."\n";
}
return $output;
}
These are the 2 methods:
//
// core logic
//
// Method 1: Generator. Available with PHP 5 >= 5.5.0
function options_in($array, $level=0) {
foreach ($array as $leaf) {
yield option_from($leaf, $level);
// yield the children options, if any
if (isset($leaf['childs']) && is_array($leaf['childs'])) {
foreach (options_in($leaf['childs'], $level+1) as $option) {
yield $option;
}
}
}
}
// Method 2: Normal recursion then merge arrays. For PHP 4 or after
function get_options($array, $level=0) {
$output = array();
// yield for the option array
foreach ($array as $leaf) {
$output[] = option_from($leaf, $level);
// yield the children
if (isset($leaf['childs']) && is_array($leaf['childs'])) {
$childs = get_options($leaf['childs'], $level+1);
$output = array_merge($output, $childs); // this could be slow
}
}
return $output;
}
And this is how you actually render some HTML from it:
// dummy input
$input = array(
array(
'id' => 1,
'name' => 'Stationery',
'parent_id' => 0,
'childs' => array(
array(
'id' => 2,
'name' => 'Pencil',
'parent_id' => 1,
),
array(
'id' => 3,
'name' => 'Pen',
'parent_id' => 1,
),
array(
'id' => 5,
'name' => 'Notepad',
'parent_id' => 1,
'childs' => array(
array(
'id' => 8,
'name' => 'Blue Pad',
'parent_id' => 3,
),
array(
'id' => 9,
'name' => 'Red Pad',
'parent_id' => 3,
),
array(
'id' => 10,
'name' => 'iPad',
'parent_id' => 3,
),
),
),
),
),
array(
'id' => 4,
'name' => 'boots',
'parent_id' => 0,
),
);
// method 1, preferred
echo "\nMethod 1\n";
echo render_select('mySelect', options_in($input));
echo render_plain_text('mySelect', options_in($input));
// method 2
echo "\nMethod 2\n";
echo render_select('mySelect', get_options($input));
echo render_plain_text('mySelect', get_options($input));
Here is a really simple example of how you could do it using recursion. I'm sure there is better ways but this is a very simple function so you can see the concept. The function calls itself until the job is done (I'm using the square bracket array notation here so make sure your PHP version supports it)
<?php
function getItems(array $items)
{
$return = [];
foreach ($items as $item) {
$return[] = $item;
if (isset($item['childs']) && count($item['childs']) > 0) {
$return = array_merge(
$return,
getItems($item['childs'])
);
}
}
return $return;
}
$array = [
0 => [
'id' => 1,
'childs' => []
],
1 => [
'id' => 2,
'childs' => [
0 => [
'id' => 3,
'childs' => []
]
]
]
];
print_r(getItems($array));
Then just loop over the results to create your select options. Hope this helps
create a sub function, input of the sub function would be object ,this function will check if it is an array or a simple element, if it is an array then it will call the function again on that element else return the element.
just elaborate "Gerald Schneider"'s answer.
Array
(
[1] => Array
(
[id] => 1
[parent_id] => 0
[name] => Men
[slug] => men
[status] => 1
)
[2] => Array
(
[id] => 2
[parent_id] => 1
[name] => Shoes
[slug] => shoes
[status] => 1
)
[3] => Array
(
[id] => 3
[parent_id] => 2
[name] => Sports
[slug] => sports
[status] => 1
)
)
Here is my function to make a sidebar menu tree.
function ouTree($array, $currentParent, $currentLevel = 0, $previousLevel = -1)
{
foreach ( $array as $categoryId => $category)
{
if ( $currentParent == $category['parent_id'])
{
if ( $currentLevel > $previousLevel) echo "<ul>";
if ( $currentLevel == $previousLevel) echo "</li>";
echo "<li><a href='/category/{$category['slug']}' title='{$category['name']}'>{$category['name']}</a>";
if ( $currentLevel > $previousLevel)
$previousLevel = $currentLevel;
$currentLevel++;
ouTree ($array, $categoryId, $currentLevel, $previousLevel);
$currentLevel--;
}
}
if ( $currentLevel == $previousLevel) echo "</li></ul>";
}
ouTree($array, 0);
Current function will call only current slug Men. How do I retrieve or repeat the parent slug to current list order? So it will be like this
Men
Shoes
Sports
OK, here's a script to sink your teeth into as been as i had a few minutes. Look at the comments! it explains everything in the script. It to be honest, should work straight away as i've copied your array structure, but please read it and understand it, don't just copy and paste blindly, you wont learn anything that way (i wouldn't normally provide full working code, but this ones pretty hard to explain).
<?php
/**
* Heres your categories array structure, they can be in any order as we will sort them into an hierarchical structure in a moment
*/
$categories = array();
$categories[] = array('id'=>5, 'parent_id' => 4, 'name' => 'Bedroom wear', 'slug' => 'bwear', 'status' => 1);
$categories[] = array('id'=>6, 'parent_id' => 3, 'name' => 'Rolex', 'slug' => 'rolex', 'status' => 1);
$categories[] = array('id'=>1, 'parent_id' => 0, 'name' => 'Men', 'slug' => 'men', 'status' => 1);
$categories[] = array('id'=>2, 'parent_id' => 0, 'name' => 'Women', 'slug' => 'women', 'status' => 1);
$categories[] = array('id'=>3, 'parent_id' => 1, 'name' => 'Watches', 'slug' => 'watches', 'status' => 1);
$categories[] = array('id'=>4, 'parent_id' => 2, 'name' => 'Bras', 'slug' => 'bras', 'status' => 1);
$categories[] = array('id'=>7, 'parent_id' => 2, 'name' => 'Jackets', 'slug' => 'jackets', 'status' => 1);
/**
* This function takes the categories and processes them into a nice tree like array
*/
function preprocess_categories($categories) {
// First of all we sort the categories array by parent id!
// We need the parent to be created before teh children after all?
$parent_ids = array();
foreach($categories as $k => $cat) {
$parent_ids[$k] = $cat['parent_id'];
}
array_multisort($parent_ids, SORT_ASC, $categories);
/* note: at this point, the categories are now sorted by the parent_id key */
// $new contains the new categories array which you will pass into the tree function below (nothign fancy here)
$new = array();
// $refs contain references (aka points) to places in the $new array, this is where the magic happens!
// without references, it would be difficult to have a completely random mess of categories and process them cleanly
// but WITH references, we get simple access to children of children of chilren at any point of the loop
// each key in this array is teh category id, and the value is the "children" array of that category
// we set up a default reference for top level categories (parent id = 0)
$refs = array(0=>&$new);
// Loop teh categories (easy peasy)
foreach($categories as $c) {
// We need the children array so we can make a pointer too it, should any children categories popup
$c['children'] = array();
// Create the new entry in the $new array, using the pointer from $ref (remember, it may be 10 levels down, not a top level category) hence we need to use the reference/pointer
$refs[$c['parent_id']][$c['id']] = $c;
// Create a new reference record for this category id
$refs[$c['id']] = &$refs[$c['parent_id']][$c['id']]['children'];
}
return $new;
}
/**
* This function generates our HTML from the categories array we have pre-processed
*/
function tree($categories, $baseurl = '/category/') {
$tree = "<ul>";
foreach($categories as $category) {
$tree .= "<li>";
$tree .= "<a href='".$baseurl.$category['slug']."'>".$category['name']."</a>";
// This is the magci bit, if there are children categories, the function loops back on itself
// and processes the children as if they were top level categories
// we append the children to the main tree string rather tha echoing for this reason
// we also pass the base url PLUS our category slug as the "new base url" so it can build the URL correctly
if(!empty($category['children'])) {
$tree .= tree($category['children'], $baseurl.$category['slug'].'/');
}
$tree .= "</li>";
}
$tree .= "</ul>";
return $tree;
}
///echo "<pre>"; print_r(preprocess_categories($categories)); die();
echo tree( preprocess_categories( $categories ) );
?>
Heres a pastebin link if you like pretty coloured code: http://pastebin.com/KVhCuvs3
I have a MySQL database in this format :
table name : btree_mst
fields : id, parent_id, left_node_id, right_node_id, user_name
Now what I have to do is print it in the Un-ordered list format like below
Root Node
Node A
Node A Left
Node A Right
Node B
Node B Left
Node B Right
I tried to make a recursive function for that but didn't work as expected.
Any suggestions ?
Here is the Code I made, http://pastebin.com/X15qAKaA
The only bug in this code is, it is printing UL every time. It should print only when the Level is changed.
Thanks in advance.
If you do not have ordered list in your DB, recursion is suitable.
class A
{
private $a = array(
array(
'id' => 1,
'parent_id' => 0,
'title' => 'ROOT'
),
array(
'id' => 2,
'parent_id' => 1,
'title' => 'A'
),
array(
'id' => 3,
'parent_id' => 1,
'title' => 'B'
),
array(
'id' => 4,
'parent_id' => 2,
'title' => 'A left'
)
);//your database values
public function buildTree()
{
$aNodes = array();
$iRootId = 1;//your root id
foreach ($this->a AS $iK => $aV)
{
if($aV['id'] == $iRootId)
{
unset($this->a[$iK]);
$aNodes[$aV['id']] = $aV;
$aNodes[$aV['id']]['childs'] = $this->getChilds($aV['id']);
}
}
print_r($aNodes);//print tree
}
private function getChilds($iParentId)
{
$aChilds = array();
foreach ($this->a AS $iK => $aV)
{
if($aV['parent_id'] == $iParentId)
{
unset($this->a[$iK]);
$aChilds[$aV['id']] = $aV;
$aChilds[$aV['id']]['childs'] = $this->getChilds($aV['id']);
}
}
return $aChilds;
}
}
$o = new A();
$o->buildTree();