PHP dynamic multidimensional array or objects - php

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/

Related

Codeigniter :Parsing array in view

I have 2 array indexes in my data array users and books
this is how i am creating this array in my controller
public function getuserhistory($id){
$query= $this->db->get_where('book_assign', array(
'user_id' => $id,
));
return $query->result();
}
public function booksrecord($id){
$books= $this->db->get_where('books',array('id' => $id));
return $books->result();
}
public function history($id){
$results['user']= $this->usermodel->getuserhistory($id);
foreach ($results as $value) {
foreach ($value as $subvalue) {
$results[]['books']= $this->usermodel->booksrecord($subvalue->id);
}
}
$data['data'] = $results;
$this->load->view('history', $data);
}
following is the array that i get
Array
(
[user] => Array
(
[0] => stdClass Object
(
[id] => 1
[user_id] => 5
[book_id] => 1
[date_issue] => 2016-07-24 00:00:00
[date_return] => 2016-07-25 00:00:00
)
[1] => stdClass Object
(
[id] => 2
[user_id] => 5
[book_id] => 2
[date_issue] => 2016-07-24 00:00:00
[date_return] => 2016-07-25 00:00:00
)
)
[0] => Array
(
[books] => Array
(
[0] => stdClass Object
(
[id] => 1
[title] => PHP Made Easy
[author] => Dietel & Dietel
[serial_no] => 232323
[qty] => 9
[row_no] => 1
[col_no] => 2
[status] => 1
[category_id] => 1
[description] => This is a book about php
)
)
)
[1] => Array
(
[books] => Array
(
[0] => stdClass Object
(
[id] => 2
[title] => C++
[author] => Dietel & Dietel
[serial_no] => 232323
[qty] => 9
[row_no] => 1
[col_no] => 2
[status] => 1
[category_id] => 1
[description] => This is a book about c++
)
)
)
)
This array has one specific user in user index and books assigned to that user in book index, I've to parse this array in a way that can generate one row in a table where i can show each book assigned to a user in a separrate row . Please helpe me to parse this array
this is the format i've to print
<tr>
<th>User id </th>
<th>Book Title </th>
<th>Date Issued</th>
<th> Date Return</th>
<th> Action</th>
</tr>
Your parent level array is inconsistent with it's elements since first element is an interloper - only that one is user data while other elements are each book data. We can assume that sometimes there could be much more books returned. To keep consistency in that manner I would separate those arrays in two arrays which first holds user data and second one holds books array.
$user = array_shift($parent);
$books = $parent;// convinient naming for later use
Now, you can loop users and dedicate appropriate book using book id
if (count($user))
{
foreach($user as $obj)
{
$rows = "<tr><td>$obj->user->id</td>";
foreach($books as $book)
{
if($book->id == $obj->book_id)
{
$rows .= "<td>$book->title</td>";
}
break;
}
$rows .= "<td>$obj->date_issued</td>";
$rows .= "<td>$obj->date_returned</td>";
$rows .= "<td>Action</td></tr>";
}
echo $rows;
}
Check this if works.
Although this (sh|c)ould work, see to return less data from DB and always try to use DRY methodology. Here you have many objects returned (user key from your array) just for different book id needed. It is pretty much expensive approach and you can check how to use concat in DB for book id or similar function.

fastest way to get array block based on value contained within the block (not working)

https://gist.github.com/jcranny/9465715
I have this array (example)...
Array
(
[0] => Array
(
[series] => stdClass Object
(
[term_id] => 5
[name] => Moto2 2013
[slug] => moto2-2013
[term_group] => 0
[term_taxonomy_id] => 3
)
[race_number] => 77
[team] => Technomah carXpert
[constructor] => Suter
[machine] => Honda CBR600RR
)
[1] => Array
(
[series] => stdClass Object
(
[term_id] => 6
[name] => Moto2 2014
[slug] => moto2-2014
[term_group] => 0
[term_taxonomy_id] => 3
)
[race_number] => 15
[team] => La Fonte Tascaracing
[constructor] => Suter
[machine] => Honda CBR600RR
)
[2] => Array
(
[series] => stdClass Object
(
[term_id] => 7
[name] => Moto2 2015
[slug] => moto2-2015
[term_group] => 0
[term_taxonomy_id] => 3
)
[race_number] => 15
[team] => Mapfre Aspar Team Moto2
[constructor] => Suter
[machine] => Honda CBR600RR
)
)
Now I would like to be able to get information from each block.
For example I would like to echo this data:
[race_number]
[team]
[constructor]
[machine]
But I want only to echo this data that is relevant to a specific [series]
I have the [series] term_id so this is my key to get the relevant data, but i'm struggling to get my node function work.
This is the function to do this:
function node_modify_riders_array($rider_id)
{
$fields = get_field("rider_series_data", $rider_id);
foreach($fields as $field_key => $field_val)
{
$new_fields[$field_val["series"]] = $field_val;
}
return $new_fields;
}
Then this is how I am get the series specific data based on the series term id.
$rider_series_data = node_modify_riders_array($rider_id);
$series_id = $series[0]->term_id;
$team = $rider_series_data[$series_id]["team"];
$contstructor = $rider_series_data[$series_id]["constructor"];
$machine = $rider_series_data[$series_id]["machine"];
$race_number = $rider_series_data[$series_id]["race_number"];
But some thing is wrong and I can work it out. Can anyone see where I'm going wrong or help me fix it.
Massive thanks in advance, would really appreciate some help.
What the problem is:
My function node_modify_riders_array is returning null, which is causing my $team, $contstructor, $machine, and $race_number too not output anything.
If I echo $series_id on my example, I get 6
Which should pass though my node_modify_riders_array function and display the relevant array values. But it's not outputting anything and I got no errors.
This is my full code so you can see what I am trying to do...
https://gist.github.com/jcranny/9465715
You are using an object as your array key and not the term_id of your series object.
function node_modify_riders_array($rider_id)
{
$fields = get_field("rider_series_data", $rider_id);
foreach($fields as $field_key => $field_val)
{
$new_fields[$field_val["series"]->term_id] = $field_val;
//^^^^^^^^^ <--- add this
}
return $new_fields;
}

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

PHP Array parent/child display/inherit

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.

Categories