Hierarchy tree to get parent slug - php

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

Related

Issue with the loop foreach php

sorry if my question seems stupid, I'm new to php.
I try to create a loop on my array but the loop returns me only the last value.
I don't understand and I tried everything
$categories = array('name' => 'mamals', 'id' => '1');
$categories = array('name' => 'birds','id' => '2');
$categories = array('name' => 'fishs', 'id' => '3');
$categories = array('name' => 'reptiles', 'id' => '4');
$category = $categories;
foreach($category as $key =>$categ){
echo $categ;
}
It return only "reptiles 4" !
Thank you for you answers
You are overwriting the variable categories, i modified the code by initializing the categories with an empty array, then pushing your entries in it.
$categories = [];
array_push($categories, array('name' => 'mamals', 'id' => '1'));
array_push($categories, array('name' => 'birds','id' => '2'));
array_push($categories, array('name' => 'fishs', 'id' => '3'));
array_push($categories, array('name' => 'reptiles', 'id' => '4'));
foreach($categories as $key=>$categ){
echo "ID: " . $categ["id"] . ", NAME: " . $categ["name"];
}
I response to shunz19's anwser where I said:
It would help to show the shorthand for this mechanism as well. I don't think anyone would use array_push in this sitation.
Here is a more concise solution:
Cause:
You are overwriting your variable - $categories - each time you use =.
So after line 3 the only value in $categories is :
categories = array('name' => 'reptiles', 'id' => '4');
Step By Step:
You look like you want to be adding entries to the Categories multidimensional array. Therefore you need to tell PHP to add not to overwrite, typically with the [] indicating the value is to be inserted into a new (incremental) variable key.
$categories = array('name' => 'mamals', 'id' => '1');
$categories[] = array('name' => 'birds','id' => '2');
This will increment the key index (numeric) by 1 and set the value of array into that key.
It is standard practise to establish numeric arrays and then populate them with this style of referencing.
But this isn't quite simple...
Because your parent array contains sub-arrays, your foreach will give warnings and errors because:
Warning: Array to string conversion in /home/user/scripts/code.php on line XX
Can you see why?
Yes, because your foreach is only opening the parent array, not the child arrays so the data types within are still arrays, but you want to output them as if they're strings.
How can you do this? With a fun little function called print_r().
Concise Solution and Fix:
$categories = []; // Establish the var type is an array.
$categories[] = array('name' => 'mamals', 'id' => '1'); // Add to the array.
$categories[] = array('name' => 'birds','id' => '2'); // add more,...
$categories[] = array('name' => 'fishs', 'id' => '3');
$categories[] = array('name' => 'reptiles', 'id' => '4');
$category = $categories;
foreach($category as $key =>$categ){
print_r($categ);
}
Output:
Array
(
[name] => mamals
[id] => 1
)
Array
(
[name] => birds
[id] => 2
)
Array
(
[name] => fishs
[id] => 3
)
Array
(
[name] => reptiles
[id] => 4
)
Code Example:
You can alternatively just access the array names from the froeach such as:
foreach($category as $key =>$categ){
print $categ['name']."\n"; // will list each name starting at the lowest array key.
}
See my test code here.

Adaptive parent relative to children's attributes in a recursive array

I'm trying to make a simple tree structure where every task has a certain percentage of completion and its parent has to inherit average completion of its direct children, as seen conceptually on the picture below. (0s are percentages of completion, for example subtask2 could be 100% and subtask2 0%, which would give task1 50% completion and therefore stackoverflow would have 25%, given task2 is at 0)
The issue I'm having is that I need to start, apparently, from the deepest children, but I can't seem to figure out how to implement such reversal traversal from leafs to root.
I have tried with normal recursive as well as double for loop and both only achieve first level calculations (in the picture example task1 is calculated, but stackoverflow will remain 0).
Note: Only leafs can actually have completion percentage, since every other element, which is not a leaf, inherits percentage from its children. (how paradoxical)
If any of you have any ideas on how to implement such an algorithm, be it conceptually or actual code, I would very much appreciate any input.
Below is structure of this array (only kept relevant information):
[0] => Array
(
[title] => stackoverflow
[completion] => 0
[children] => Array
(
[0] => Array
(
[title] => task2
[completion] => 0
)
[1] => Array
(
[title] => task1
[completion] => 0
[children] => Array
(
[0] => Array
(
[title] => subtask2
[completion] => 100
)
[1] => Array
(
[title] => subtask1
[completion] => 0
)
)
)
)
)
I seem to be having a similar issue than the issue in this thread: Percentages and trees however, I need my task to have actual percentages, not only completed/non-completed. All math is completely linear, meaning that parent's percentage = (addition of all percentages of children) / (number of children)
Also var_export:
array (
0 =>
array (
'uuid' => '157ed2b2-0d0c-4f0c-b1d2-7126255f4023',
'title' => 'stackoverflow',
'completed' => '0',
'parent' => NULL,
'children' =>
array (
0 =>
array (
'uuid' => '72ce49a6-76e5-495e-a3f8-0f13d955a3b5',
'title' => 'task2',
'completed' => '0',
'parent' => '157ed2b2-0d0c-4f0c-b1d2-7126255f4023',
),
1 =>
array (
'uuid' => '4975d08d-55f0-4cd8-9de5-2d056111ec2d',
'title' => 'task1',
'completed' => '0',
'parent' => '157ed2b2-0d0c-4f0c-b1d2-7126255f4023',
'children' =>
array (
0 =>
array (
'uuid' => 'ac5e9d37-8f14-4169-bcf2-e7b333c5faea',
'title' => 'subtask2',
'completed' => '0',
'parent' => '4975d08d-55f0-4cd8-9de5-2d056111ec2d',
),
1 =>
array (
'uuid' => 'f74b801f-c9f1-40df-b491-b0a274ffd301',
'title' => 'subtask1',
'completed' => '0',
'parent' => '4975d08d-55f0-4cd8-9de5-2d056111ec2d',
),
),
),
),
),
)
Here is a recursive function that passes the parent by reference until it finds a leaf and updates totals working backward.
function completionTree(&$elem, &$parent=NULL) {
// Handle arrays that are used only as a container... if we have children but no uuid, simply descend.
if (is_array($elem) && !isset($elem['uuid'])) {
foreach($elem AS &$child) {
completionTree($child, $elem);
}
}
// This array has children. Iterate recursively for each child.
if (!empty($elem['children'])) {
foreach ($elem['children'] AS &$child) {
completionTree($child, $elem);
}
}
// After recursion to handle children, pass completion percentages up to parent object
// If this is the top level, nothing needs to be done (but suppress that error)
if (#$parent['completed'] !== NULL) {
// Completion must be multiplied by the fraction of children it represents so we always add up to 100. Since values are coming in as strings, cast as float to be safe.
$parent['completed'] = floatval($parent['completed']) + (floatval($elem['completed']) * (1/count($parent['children'])));
}
}
// Data set defined statically for demonstration purposes
$tree = array(array (
'uuid' => '157ed2b2-0d0c-4f0c-b1d2-7126255f4023',
'title' => 'stackoverflow',
'completed' => '0',
'parent' => NULL,
'children' =>
array (
0 =>
array (
'uuid' => '72ce49a6-76e5-495e-a3f8-0f13d955a3b5',
'title' => 'task2',
'completed' => '0',
'parent' => '157ed2b2-0d0c-4f0c-b1d2-7126255f4023',
),
1 =>
array (
'uuid' => '4975d08d-55f0-4cd8-9de5-2d056111ec2d',
'title' => 'task1',
'completed' => '0',
'parent' => '157ed2b2-0d0c-4f0c-b1d2-7126255f4023',
'children' =>
array (
0 =>
array (
'uuid' => 'ac5e9d37-8f14-4169-bcf2-e7b333c5faea',
'title' => 'subtask2',
'completed' => '0',
'parent' => '4975d08d-55f0-4cd8-9de5-2d056111ec2d',
),
1 =>
array (
'uuid' => 'f74b801f-c9f1-40df-b491-b0a274ffd301',
'title' => 'subtask1',
'completed' => '100',
'parent' => '4975d08d-55f0-4cd8-9de5-2d056111ec2d',
),
),
),
),
),
);
// Launch recursive calculations
completionTree($tree);
// Dump resulting tree
var_dump($tree);
Though this is answered, I'd like to leave a solution that seems a bit more intuitive (IMHO). Instead of passing down the parent, just handle the children first:
/**
* #param array $nodes
*
* #return array
*/
function calcCompletion(array $nodes): array {
// for each node in nodes
return array_map(function (array $node): array {
// if it has children
if (array_key_exists('children', $node) && is_array($node['children'])) {
// handle the children first
$node['children'] = calcCompletion($node['children']);
// update this node by *averaging* the children values
$node['completed'] = array_reduce($node['children'], function (float $acc, array $node): float {
return $acc + floatval($node['completed']);
}, 0.0) / count($node['children']);
}
return $node;
}, $nodes);
}
Well, this might be a little overhead, but you can use RecursiveArrayIterator. First, you must extend it to handle your tree structure:
class MyRecursiveTreeIterator extends RecursiveArrayIterator
{
public function hasChildren()
{
return isset($this->current()['children'])
&& is_array($this->current()['children']);
}
public function getChildren()
{
return new static($this->current()['children']);
}
}
Then using RecursiveIteratorIterator you can create an iterator which will process your tree starting from leaves:
$iterator = new RecursiveIteratorIterator(
new MyRecursiveTreeIterator($tasks),
RecursiveIteratorIterator::CHILD_FIRST
);
Then with this one, you can add your calculation logic:
$results = [];
$temp = [];
$depth = null;
foreach ($iterator as $node) {
if ($iterator->getDepth() === 0) {
// If there were no children use 'completion'
// else use children average
if (
is_null($depth)
|| !isset($temp[$depth])
|| !count($temp[$depth])
) {
$percentage = $node['completed'];
} else {
$percentage = array_sum($temp[$depth]) / count($temp[$depth]);
}
$results[$node['title']] = $percentage;
continue;
}
// Set empty array for current tree depth if needed.
if (!isset($temp[$iterator->getDepth()])) {
$temp[$iterator->getDepth()] = [];
}
// If we went up a tree, collect the average of children
// else push 'completion' for children of current depth.
if ($iterator->getDepth() < $depth) {
$percentage = array_sum($temp[$depth]) / count($temp[$depth]);
$temp[$depth] = [];
$temp[$iterator->getDepth()][] = $percentage;
} else {
$temp[$iterator->getDepth()][] = $node['completed'];
}
$depth = $iterator->getDepth();
}
Here is a demo.

PHP Arrays looping and creating multi dimensional arrays

I have an array of items listed bellow
array (
[0] => array(
'order' => 'order001',
'qty' => 90
),
[1] => array(
'order' => 'order002',
'qty' => 100
)
)
I also have a quantity(Q) that is to be fetched from the list above and the array have to be looped from top to bottom without even skipping a single item.
The loop will go through the first item to see if it can get the total requested and if the first loop cant meet the total then the it will return the total(T) got from the first item store it somewhere and then move to the next item in the array with a new value which lets say its (Q-T) and see if can find the quantity in the next item.
Now the problem is i cant actually figure out how to make hold and return the array as a list like in the case below.
Lets say i need a total of 120.
Array(
Array(
'order' => 'order001',
'qty' => 90
),
Array(
'order' => 'order002',
'qty' => 30
)
);
Maybe something like this?
https://iconoun.com/demo/temp_tonywiz.php
<?php // demo/temp_tonywiz.php
/**
* Working with arrays
*
* https://stackoverflow.com/questions/45264342/php-arrays-looping-and-creating-multi-dimensional-arrays
*/
error_reporting(E_ALL);
echo '<pre>';
$qty = 120;
$arr = [ ['order' => 'order001', 'qty' => 90], ['order' => 'order002', 'qty' => 100] ];
$out = [];
foreach ($arr as $sub)
{
if ($qty <= 0) break;
if ($sub['qty'] <= $qty)
{
$out[] = $sub;
$qty = $qty - $sub['qty'];
}
else
{
$sub['qty'] = $qty;
$out[] = $sub;
}
}
print_r($arr);
print_r($out);

Given this array, how can I reformat it to look like this

If I had an array:
$data = array(
array(
'manufacturers_id' => 29,
'manufacturers_name' => 'Quicksilver',
'products_quantity' => 1,
'products_price' => 15.6000,
'products_cost' => 8.0000,
),
array(
'manufacturers_id' => 29,
'manufacturers_name' => 'Quicksilver',
'products_quantity' => 2,
'products_price' => 4.6722,
'products_cost' => 2.4000,
)
);
How can I reformat this to provide the structure
Array
(
[Quiksilver] => Array
(
[brands_sales] => $brandsSalesVal
[brands_products_sold] => $brandsSoldVal
[brands_costs] => $brandsCostsVal
)
$brandsSalesVal = A sum of all the products_price * products_quantity (for each manufacturer_id)
$brandsSoldVal= A sum of all the products_quantity for each manufacturer
$brandsCostsVal= A sum of all the products_costs for each manufacturer
Any help is greatly appreciated and I am thankful for anyone to take time to answer my rather lengthy query. I am still getting to grips with reformating arrays.
You need to use a foreach loop like so:
// Declare the totals array and
// the manufacturers->id map
$totals = array();
$manufacturers = array();
// Loop through the array of products and populate
// the totals array
foreach($data as $value){
// Set the key to the manufacturers name
$key = $value['manufacturers_name'];
// If the array has not been built yet, then ensure the
// values are set to 0 and add the manufacturer to the
// manufacturers map if it is not already there
if(!isset($totals[$key])){
// Add the manufacturer to the map
$manufacturers[$value['manufacturers_id']] = $key;
// Default the values to 0
$totals[$key]['brand_sales'] = 0;
$totals[$key]['brands_products_sold'] = 0;
$totals[$key]['brands_costs'] = 0;
}
// Calculate the brand sales
$totals[$key]['brand_sales'] += ($value['products_price']*$value['products_quantity']);
// Calculate the brand sales
$totals[$key]['brands_products_sold'] += $value['products_quantity'];
// Calculate the brand sales
$totals[$key]['brands_costs'] += $value['products_cost'];
}
In order to access the information stored in the array generated above, you can use another foreach loop like so:
// Loop through the $totals array and print the result
foreach($totals as $key => $value){
// Print the manufacturers name and ID
echo "\n".$key." (ID: ".array_search($key,$manufacturers).")";
// Print the totals for the current manufacturer
echo "\n\tBrand Sales: ".$values['brand_sales'];
echo "\n\tBrand Products Sold: ".$values['brands_products_sold'];
echo "\n\tBrand Costs: ".$values['brands_costs'];
}
The array_search function is used to look up the ID of the manufacturer based on the manufacturers name stored in the $manufacturers array. You can alter the code so that it does not need the array_search function, but I have done it like this because traditionally you would map the ID->NAME, not NAME->ID. It is just personal preference...
For more information on the foreach loop, see here
$data = array(
array(
'manufacturers_id' => 29,
'manufacturers_name' => 'Quicksilver',
'products_quantity' => 1,
'products_price' => 15.6000,
'products_cost' => 8.0000,
),
array(
'manufacturers_id' => 29,
'manufacturers_name' => 'Quicksilver',
'products_quantity' => 2,
'products_price' => 4.6722,
'products_cost' => 2.4000,
)
,
array(
'manufacturers_id' => 30,
'manufacturers_name' => 'Different Brand',
'products_quantity' => 2,
'products_price' => 4.6722,
'products_cost' => 2.4000,
)
);
$sortedData = array();
foreach($data as $num => $row){
$manufacturersName = $row['manufacturers_name'];
//If we don't have an array made for the manufacturer yet, make one
if(!isset($sortedData[$manufacturersName])){
$sortedData[$manufacturersName] = array(
'brands_sales' => 0,
'brands_products_sold' => 0,
'brands_costs' => 0
);
};
//Make a reference to the relevant manufacturer sorted data
$manufacturerData = &$sortedData[$manufacturersName];
$qty = $row['products_quantity'];
//
$manufacturerData['brands_sales'] += $qty * $row['products_price'];
$manufacturerData['brands_products_sold'] += $qty;
$manufacturerData['brands_costs'] += $row['products_cost'];
}
var_dump($sortedData); // <- your result.
Result:
array (size=2)
'Quicksilver' =>
array (size=3)
'brands_sales' => float 24.9444
'brands_products_sold' => int 3
'brands_costs' => float 10.4
'Different Brand' =>
array (size=3)
'brands_sales' => float 9.3444
'brands_products_sold' => int 2
'brands_costs' => float 2.4

How to sort flat array into multidimensional tree

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

Categories