PHP Array parent/child display/inherit - php

I have an piece of my array here:
[0] => stdClass Object
(
[id] => 8005
[parentid] => 8004
[name] => a, b
[level] => 1
[prodtypename] => 1, 2, 3, 4
)
[1] => stdClass Object
(
[id] => 8006
[parentid] => 8005
[name] => c
[level] => 2
[prodtypename] =>
)
[2] => stdClass Object
(
[id] => 8007
[parentid] => 8005
[name] => d
[level] => 2
[prodtypename] =>
)
In my form I display them like:
<?php foreach ($this->myArray as $item): ?>
<?php echo $item->prodtypename ?>
it displays me current category and its current type. I need to display parent "prodtypename" next to child type, so we can know, what is parents types for current child category. Im trying to make display look something like this:
[1] => stdClass Object
(
[id] => 8006
[parentid] => 8005
[name] => c
[level] => 2
[prodtypename] => 1,2,3,4
)
Because parents "prodtypename" have 1.2.3.4, so the child inherits it. Thanks.

Based on the array you have already something like this might work assuming that you can rely on parents always appearing in the array before their children:
$prodTypeNames = array();
foreach ($this->myArray as $item) {
$prodTypeName = $item->prodtypename;
if( is_null( $item->prodtypename ) && isset( $prodTypeNames[$item->parentid] ) ) {
$prodTypeName = $prodTypeNames[$item->parentid];
}
$prodTypeNames[$item->id] = $prodTypeName;
echo $prodTypeName;
}
But you're probably better off getting the data in a better format to begin with.

Related

Best way to build multidimensional array (categories ; sub-categories; sub-sub-categories etc.)

Hello I have this response from my sql query :
Array
(
[0] => Array
(
[id] => 1
[name] => Category #1
[parent] => 0
)
[1] => Array
(
[id] => 2
[name] => Category #2
[parent] => 0
)
[2] => Array
(
[id] => 3
[name] => Category #3
[parent] => 0
)
[3] => Array
(
[id] => 4
[name] => Category #4
[parent] => 0
)
[4] => Array
(
[id] => 5
[name] => Sub category of category #1
[parent] => 1
)
[5] => Array
(
[id] => 6
[name] => Sub category of category #2
[parent] => 2
)
[6] => Array
(
[id] => 7
[name] => Sub category of category #6 (which is sub category of category #2)
[parent] => 6
)
)
After converting the response must looks like this :
array
(
array
(
[id] => 1
[name] => Category #1
[parent] => 0
[children]=> array
(
[id] => 5
[name] => Sub category of category #1
[parent] => 1
)
)
array
(
[id] => 2
[name] => За дома
[parent] => 0
[children]=> array
(
[id] => 6
[name] => Sub category of category #2
[parent] => 2
[children] => array
(
[id] => 7
[name] => Sub category of category #6 (which is sub category of category #2)
[parent] => 6
)
)
)
array
(
[id] => 3
[name] => Category #3
[parent] => 0
)
array
(
[id] => 4
[name] => Category #4
[parent] => 0
)
)
My question is - what is the best way to build such a multidimensional array (in php for example).
Try something like this
$arr = 'Your array';
$new = array();
foreach ($arr as $a){
$new[$a['parent']][] = $a;
}
$data = createMyTree($new, array($arr[0]));
print_r($data);
function createMyTree(&$list, $parent){
$tree = array();
foreach ($parent as $k=>$l){
if(isset($list[$l['id']])){
$l['children'] = createMyTree($list, $list[$l['id']]);
}
$tree[] = $l;
}
return $tree;
}
You can just store the data in a regular array and use code to traverse it back. So each node has its parentId in it, and as long as the parentId is not 0 you traverse back another parent till you get to the root parent of a given node.
you really do not need to think of it as a multi-dimensional array; which you will not be able to do any how because of the infinite dimensions. In other languages, such as C, you could just build a tree implementation (a classic data structure) using pointers. But in PHP i would just use a flat array, store the parentId, and use code to recurse.

Deep array walk and output indentation

I have the following array structure, which is generated from a database:
Array
(
[0] => stdClass Object
(
[id] => 1
[parent] => 0
[children] => Array
(
[0] => stdClass Object
(
[id] => 2
[parent] => 1
[children] => Array
(
[0] => stdClass Object
(
[id] => 3
[parent] => 2
)
)
)
[1] => stdClass Object
(
[id] => 7
[parent] => 1
)
)
)
[1] => stdClass Object
(
[id] => 4
[parent] => 0
[children] => Array
(
[0] => stdClass Object
(
[id] => 5
[parent] => 4
[children] => Array
(
[0] => stdClass Object
(
[id] => 6
[parent] => 5
)
)
)
)
)
)
What I'd like to do is present this information in a HTML <select> box, with correct indentation to indicate the structure. So, for the given example, the result should look something like this:
- Select category
- Category 1
- Category 2
- Category 3
- Category 7
- Category 4
- Category 5
- Category 6
I am currently looping over the content using PHP's RecursiveIteratorIterator() class, which works to output all of them, but I can't figure out how to include the indentation. Here's the code I have now:
$html = '<select>';
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($tree), RecursiveIteratorIterator::SELF_FIRST);
foreach($iterator as $i => $cat)
{
if($cat->id != '')
{
$option = new self($this->_db, $cat->id);
$html.= '<option value="'.$cat->id.'"';
$html.= '>'.$option->name;
$html.= '</option>';
}
}
$html.= '</select>';
return $html;
Can anyone point me in the right direction. Essentially, all I want to do is pad the option text by x spaces per nest depth.
If you are just wanting to pad the option name, you could use RecursiveIteratorIterator::getDepth and add the padding multiplied by the current depth:
$option_padding = str_repeat(" ", 4 * $cat->getDepth() );

Recursive loop for category

I'm trying to implement a category system on my website. The problem is that a category can have child.
So far, my table category looks like that :
id, name, parent_id
So far, I made a loop, but it only works for 2 levels. Here is my code :
for($i=0;$i<count($data);$i++){
$tree[$data[$i]->name] = array();
for($j=0;$j<count($data);$j++){
if($data[$j]->parent_id == $data[$i]->id){
$tree[$data[$i]->name][] = $data[$j]->name;
}
}
}
It return me an array as it :
Array
(
[0] => Array
(
[1] => Cat1
[children] => Array
(
[12] => sub cat 1
[13] => sub cat 2
[14] => sub cat 3
)
)
[1] => Array
(
[2] => Cat2
)
[2] => Array
(
[3] => Cat3
)
)
How can I make it efficient and recursive to have something more like :
Array
(
[0] => Array
(
[1] => Cat1
[children] => Array
(
[12] => sub cat 1
[13] => sub cat 2
[14] => sub cat 3
[children] => Array
(
[1] => sub sub cat 1
)
)
)
[1] => Array
(
[2] => Cat2
)
[2] => Array
(
[3] => Cat3
)
)
Thanks for your help
EDIT
I'm working on Zend, and it return me the data as it :
Zend_Db_Table_Rowset Object
(
[_data:protected] => Array
(
[0] => Array
(
[id] => 1
[name] => Cinema
[type] => category
[slug] => cinema
[parent_id] => -1
)
[1] => Array
(
[id] => 2
[name] => Horror
[type] => category
[slug] => horror
[parent_id] => 1
)
If you want to apply this type of structure best to use child in other table with parent id as a foreign key.
so with that u can have recursive category posting.
so the table structure will be like this
ch_id, parent_id, child
You should check out Nested Sets, a methodology to store and retrieve date trees in/out of relational databases (what in fact your categories are). For this, you have to adapt your database scheme a little bit (as described in the link or in the several tutorials about nested sets). For PHP, there are several libraries providing Nested Set capabilities, for instance this list.
This should help you out.
It Iterates over every member of the array and checks it's position in the tree structure per level and dependency.
function get_children($data, $parent_id = false) {
$result = array();
foreach ($data as $i => $content) {
if ($parent_id != false && $content['id'] != $parent_id) # other levels
continue;
if ($parent_id === false && !empty($content['parent_id'])) # top level
continue;
$leaf = array(
'id' => $content['id'],
'parent_id' => $content['parent_id'],
'name' => $conten['name']
);
$leaf['children'] = get_children($data, $leaf['id']);
$result[$leaf['id']] = $leaf;
}
return $result;
}
$result = get_children($data);
print_r($result);
Edit: bug fixes

Recursively sort array to levels

I've been working on a site that uses binary mlm system.
Illustration here
So I have a two tables in database, users anad relationships. There is ID and personal data columns in users. Relationships has 4 columns: ID, parentID, childID, pos. Where pos is either left or right.
I have succesfully written a function that recursively lists all children of given pid (parentID). However I need to sort it in levels (for display and calculation purposes).
I have an array of children of user ID = 1:
Array
(
[0] => Array
(
[id] => 2
[parentID] => 1
[pos] => l
)
[1] => Array
(
[id] => 4
[parentID] => 2
[pos] => l
)
[2] => Array
(
[id] => 8
[parentID] => 4
[pos] => l
)
[3] => Array
(
[id] => 5
[parentID] => 2
[pos] => p
)
[4] => Array
(
[id] => 3
[parentID] => 1
[pos] => p
)
[5] => Array
(
[id] => 6
[parentID] => 3
[pos] => l
)
[6] => Array
(
[id] => 7
[parentID] => 3
[pos] => p
)
)
Now I have function named get_levels that returns an multidimensional array that should look like this:
Array
(
[0] => Array
(
[0] => Array
(
[id] => 2
[parentID] => 1
[pos] => l
)
[1] => Array
(
[id] => 3
[parentID] => 1
[pos] => p
)
)
[1] => Array
(
[0] => Array
(
[id] => 4
[parentID] => 2
[pos] => l
)
[1] => Array
(
[id] => 5
[parentID] => 2
[pos] => p
)
[2] => Array
(
[id] => 6
[parentID] => 3
[pos] => l
)
[3] => Array
(
[id] => 7
[parentID] => 3
[pos] => p
)
)
ETC.
)
Here's the function:
function get_levels($pid,$level, $level_id){
$children = children_array($pid,1);
if (sizeof($children) > 0):
foreach ($children as $child):
if ($child["parentID"] == $pid):
get_levels($child["id"], $level, $level_id+1);
$level[$level_id][] = $child;
endif;
endforeach;
endif;
return $level;
}
function children_array($pid, $depth) returns the children ... for $depth = 1 it returns immediate children (0 or 1 or 2), for $depth = 0 it returns all children
Can anyone help me with this function? I think the function works, however I don't know how to recursively use and add to array.
Looks like you're using a data structure within the wrong context. It's a binary tree, yet it's represented into a multilevel array which in short doesn't define its boundaries and rules of use.
When using the tree, I would use something like a Node class that has two children, left and right. Iterating through the tree would be piece of cake, inserting/deleting/editing into it is easily done depending on which set of rules you want to follow. When storing the tree, I would use some kind of Ahnentafel list which can easily be done in a relational database.
I would in no way mix both iteration and storage processes because if I change the rules of storage, I might also have to change the rules of iteration and vice versa.

PHP dynamic multidimensional array or objects

I'm trying to create a recursive function (or method) that stores a sub-tiered navigation in an array variable or object. Here is what I have:
class Navigation extends Database
{
function build($parent_id = 0)
{
$query = 'SELECT id, name, href, parent_id
FROM navigation
WHERE parent_id = '.$parent_id.'
ORDER BY name';
$results = $db->query($query);
while ($row = $results->fetch_object()) {
$nav[$row->id] = $row;
// echo $row;
$this->build($row->id);
}
return $nav;
}
}
If you comment out the echo $row everything works fine. So what I want it to do in a three tier navigation is this:
Array
(
[1] => stdClass Object
(
[id] => 1
[name] => Home
[href] => home.php
[parent_id] => 0
)
[2] => stdClass Object
(
[id] => 2
[name] => Company
[href] => company.php
[parent_id] => 0
)
[4] => stdClass Object
(
[id] => 4
[name] => Company Vision
[href] => company_vision.php
[parent_id] => 2
)
[5] => stdClass Object
(
[id] => 5
[name] => Company Goals
[href] => company_goals.php
[parent_id] => 2
)
[3] => stdClass Object
(
[id] => 3
[name] => Products
[href] => products.php
[parent_id] => 0
)
[6] => stdClass Object
(
[id] => 6
[name] => Products Shoes
[href] => products_shoes.php
[parent_id] => 3
)
[7] => stdClass Object
(
[id] => 7
[name] => Nike
[href] => products_shoes_nike.php
[parent_id] => 6
)
)
Just as an example, so the array would dynamically do this:
$nav[$row->id] = $row; // Home
$nav[$row->id] = $row; // Company
$nav[2][$row->id] = $row; // Company Vision
$nav[2][$row->id] = $row; // Company Goals
$nav[$row->id] = $row; // Products
$nav[3][$row->id] = $row; // Products Shoes
$nav[3][6][$row->id] = $row; // Products Shoes Nike
Thanks in advance.
Question: How do you make a recursive function/method and store the recursive information in a variable rather than echoing the results?
Issues:
(a) PHP overwrites the variable every time it calls itself recursively
(b) A solution would be dynamically creating an array on the fly, but I don't know if that is possible
I suspect you need the nested sets algorithm http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/

Categories