converting a related database table object into a nested array - PHP - php

i have some dummy related data in my table "you can take a look at it bellow". i want to nest the data according to their relationships into one array.
Table Data:
+-----+------+--------+
| uid | name | parent |
+-----+------+--------+
| 1 | A | 0 |
| 2 | B | 1 |
| 3 | C | 1 |
| 4 | D | 2 |
| 5 | E | 3 |
| 7 | G | 3 |
| 9 | H | 4 |
| 10 | I | 4 |
| 11 | J | 7 |
+-----+------+--------+
the array is going to be like array('A' =>array('B'=>'D','C'=>array(...)).
am currently using codeigniter and here is what i've done
CODE
public function nestDataIntoArray($id)
{
$this->db->where('uid', $id);
$query = $this->db->get('binary_tbl');
$result = [];
if ($query->num_rows() > 0) {
foreach ($query->result() as $k) {
// secondLevel deep
$secondLevel = $this->getSubLevel($k->uid);
$secondLevelRowCount = $secondLevel->num_rows();
if ($secondLevelRowCount > 0 ) {
if ($secondLevelRowCount > 1) {
foreach ($secondLevel->result() as $key) {
// create second level deep array
$result[$k->name][$key->name][] = $this->getSubLevel($key->uid)->row('name');
// thirdLevel deep
$thirdLevel = $this->getSubLevel($key->uid);
$thirdLevelRowCount = $thirdLevel->num_rows();
if ($thirdLevelRowCount > 0) {
if($thirdLevelRowCount > 1){
foreach ($thirdLevel->result() as $tKey) {
// create third level deep array
$result[$k->name][$key->name][$tKey->name] = $this->getSubLevel($tKey->uid)->row('name');
}
}else{
foreach ($thirdLevel->result() as $tKey) {
$result[$k->name][$key->name][$tKey->name] = $this->getSubLevel($tKey->uid)->row('name');
}
}
} else {
$result[$k->name][$key->name] = $this->getSubLevel($key->uid)->result_array();
} //end thirdLevel deep
}
}
} else {
$result[$k->name] = $this->getSubLevel($key->uid)->row('name');
} // end second level deep
}
} else {
$result = NULL;
}
return $result;
}
private function getSubLevel($id)
{
return $this->db->select('*')->from('binary_tbl')->where('supermember', $id)->get();
}
upon invoking the nestDataIntoArray(1) method i got the following output
OUTPUT
array (size=1)
'A' =>
array (size=2)
'B' =>
array (size=2)
0 => string 'D' (length=1)
'D' => string 'H' (length=1)
'C' =>
array (size=3)
0 => string 'E' (length=1)
'E' => null
'G' => string 'J' (length=1)
this output seems to be fine but i really dont want that Zero index and some of the data still has one or two data related to them which i still have to loop through to get and that to me just seems to be alot of unnecessary coding. So the question is: which other better way can i achieve this and how do i get rid of that zero index?

Related

Efficient Database Queries ( PHP + PDO SQL)

At the moment I have a database structure like so:
| id | name | parent_id
| 1 | Human Resources | 0
| 2 | Marketing | 0
| 3 | Operations | 0
| 4 | Design | 0
| 5 | Marketing Design| 4
| 6 | Graphic Design | 4
| 7 | Print Design | 4
| 8 | Human Personal | 1
| 9 | Food Ops | 3
As you can see these are the departments within the business and also sub departments.
A sub-departments parent_id is the id of the department
do, for example:
id: 4, name: Design, parent_id: 0
id: 7, Print Design, parent_id: 4
Print Design is a sub department of design
I have called everything from the database in one query and now I need them in this structure:
$depts = array(
"Human Resources" => array("Human Personal"),
"Marketing" => array(),
"Operations" => array("Food Ops"),
"Design" => array("Marketing Design", "Graphic Design", "Print Design"),
...
);
so far I have:
foreach ($results as $result) {
if ($result['parent_id'] == 0) {
$parentCategories_arr[array($result['id'] => $result['name'])];
} else {
$returnedResults_arr[$result['parent_id']] = array($result['name']);
}
}
However I completely think that I have missed the point. so my question:
How do I loop through all the contents of that results and add the parent categories into an array with their sub categories as an array?
Maybe there is an easier way, but it works : (hate to say that sentence) - try to make it better maybe
$mFinalArray = fixMyArray($results);
print_r($mFinalArray);
function fixMyArray($results){
// Create categories - parent_id == 0
foreach($results as $index => $result) // $index = 0|1|2|3|4|5|6|7|8|9
if($result['parent_id'] == 0) // $result['parent_id'] = current item parent_id
$mCategories[$result['name']] = $result['id']; // $mCategories['Human Resources'] = 1|2|3|4
// Insert each data to the right parent
foreach($results as $index => $result) // $index = 0|1|2|3|4|5|6|7|8
if($result['parent_id'] != 0)
foreach($mCategories as $subindex => $category) // $subindex = Human Resources | Marketing | Operations | Design
if($result['parent_id'] == $category) // $category = 0|1|2|3|4
$mFinalArray[$subindex][] = $result['name']; // ex. $mFinalArray['Human Resources'][] = Human Personal
return $mFinalArray;
}
*Last line has an extra [ ] $mFinalArray[$subindex][ ]= $result['name'] . That means append to array.
Output :
Array
(
[Design] => Array
(
[0] => Marketing Design
[1] => Graphic Design
[2] => Print Design
)
[Human Resources] => Array
(
[0] => Human Personal
)
[Operations] => Array
(
[0] => Food Ops
)
)

foreach function for more than 2 array

I need to insert data to a table.. the data come from different sources. The following are my code.
$title = array(Book A, Book B, Book C);
$number = array(2,1,4);
$lines = array(Maria, Smith, Abner);
for($i=1; $i<count($lines); $i++)
{
print '<tr>';
print '<td>'.$title[$i].'</td>';
print '<td>P'.$number[$i].'</td>';
print '<td>['.$lines[$i].']</td>';
print '<td></td>';
print '</tr>';
}
Seems not working :/ the array not display properly in my table.
I'm expecting output as follows:
------------------------------------------------
| Title | No | Lines | Remarks |
------------------------------------------------
| Book A | 2 | Maria | |
| Book B | 1 | Smith | |
| Book C | 4 | Abner | |
------------------------------------------------
at the moment.. I get the following output:
------------------------------------------------
| Title | No | Lines | Remarks |
------------------------------------------------
| Book A | 2 | Maria | |
| | | Smith | |
| | | Abner | |
------------------------------------------------
If your arrays has different keys you can 'reset' them to be zero-based. Just use $array = array_values($array). Quote from manual
array_values() returns all the values from the array and indexes the array numerically.
After this you code will work. This is how your example can be modified:
$title = array('Book A', 'Book B', 'Book C');
$number = array("a" => 2, "b" => 1, "c" => 4);
$lines = array('Maria', 'Smith', 7 => 'Abner');
/* At this point you have some arrays with unknown keys.
It can be [0 => item, 1 => item2] or ['name' => item, 'name2' => item2]
or even with skipped keys [0 => item, 7 => item2]
*/
// Reset keys for all arrays. Now all arrays will contain keys 0, 1, 2 etc.
$title = array_values($title);
$number = array_values($number);
$lines = array_values($lines);
for($i = 0; $i < count($lines); $i++) // Note, arrays now are zero-based, you must start from $i = 0
{
print '<tr>';
print '<td>'.$title[$i].'</td>';
print '<td>P'.$number[$i].'</td>';
print '<td>['.$lines[$i].']</td>';
print '<td></td>';
print '</tr>';
}
you just put i=0; because array started from 0 index and try following code may it help u.
<?php $title = array('Book A','Book B','BookC');$number = array('2','1','4');$lines = array('Maria','Smith','Abner');for($i=0;$i<count($lines); $i++){print '<tr>';print '<td>'.$title[$i].'</td>';print '<td>P'.$number[$i].'</td>';print'<td>['.$lines[$i].']</td>';print '<td></td>'; print '</tr>'; } ?>
There's a neat trick to merging separate arrays with array_map() if you pass null as the first argument, followed by the arrays you want merged.
As quoted in Example #4 in the docs:
An interesting use of this function is to construct an array of arrays, which can be easily performed by using NULL as the name of the callback function
Using your example for context:
<?php
$titles = ['Book A', 'Book B', 'Book C'];
$numbers = [2,1,4];
$lines = ['Maria', 'Smith', 'Abner'];
// create an 'array of arrays'
$rows = array_map(null, $titles, $numbers, $lines);
var_dump($rows);
Yields:
array (size=3)
0 =>
array (size=3)
0 => string 'Book A' (length=6)
1 => int 2
2 => string 'Maria' (length=5)
1 =>
array (size=3)
0 => string 'Book B' (length=6)
1 => int 1
2 => string 'Smith' (length=5)
2 =>
array (size=3)
0 => string 'Book C' (length=6)
1 => int 4
2 => string 'Abner' (length=5)
You can then iterate over it pretty easily, like so:
foreach ($rows as $row) {
list($title, $number, $line) = $row;
printf('<tr><td>%s</td><td>%s</td><td>%s</td></tr>',
$title, $number, $line);
}
This should give you something like:
<tr><td>Book A</td><td>2</td><td>Maria</td></tr>
<tr><td>Book B</td><td>1</td><td>Smith</td></tr>
<tr><td>Book C</td><td>4</td><td>Abner</td></tr>
A useful side-effect of this approach is that your arrays do not have to be the same length; null will be used where applicable to pad out any "missing" values.
Another quick example:
<?php
$letters = range('a', 'd'); // ['a', 'b', 'c', 'd']
$numbers = range(1, 3); // [1, 2, 3]
$merged = array_map(null, $letters, $numbers);
var_dump($merged);
Yields:
array (size=4)
0 =>
array (size=2)
0 => string 'a' (length=1)
1 => int 1
1 =>
array (size=2)
0 => string 'b' (length=1)
1 => int 2
2 =>
array (size=2)
0 => string 'c' (length=1)
1 => int 3
3 =>
array (size=2)
0 => string 'd' (length=1)
1 => null
Hope this helps :)
You can try modifying you code as follow:
foreach($lines as $z => $value)
{
print '<tr>';
print '<td>'.$title[$z].'</td>';
print '<td>P'.$number[$z].'</td>';
print '<td>['.$value.']</td>';
print '<td></td>';
print '</tr>';
}
I found that the array index for all my array is not in sequential.
eg: $title =
array[0] = Book A
array[5] = Book B
array[9] = Book C
So, that is probably the reason why it is not display accordingly. I cannot use function 'for'. However, I cannot re-number the index because its the key for me to continue with next module/function.
So, I tried the following code.. but seems something missing..
$i=0;
if (!empty($title)){
foreach($title as $key => $value){
$y = $number[$key];
if ($i<count($lines))
{ $z = $lines[$i];
$i+1;
}
print '<tr>';
print '<td>'.$value.'</td>';
print '<td>'.$y.'</td>';
print '<td>['.$z.']</td>';
print '<td></td>';
print '</tr>';
}
}
The following is the output that I get. Now array for $lines that didn't display properly.
------------------------------------------------
| Title | No | Lines | Remarks |
------------------------------------------------
| Book A | 2 | Maria | |
| Book B | 1 | Maria | |
| Book C | 4 | Maria | |
------------------------------------------------

PHP Comment System using Laravel

I am developing a website using laravel PHP and trying to do a comment system using the following structure:
- Comment 1 (id = 1)
-- Reply 1 (id = 2) (parent_id = 1)
--- Reply 2.1 (id = 3) (parent_id = 2)
-- Reply 2 (id = 4) (parent_id = 1)
I am wondering how would I do a foreach to cover that? Since i don't know how many child comments a comment will have.
I wouldn’t store comments and replies in a separate table as they’re both comment entities at the end of the day. Simply have a parent_id column in your comments table, and you can fetch both comments and replies in one database query as opposed to two.
I assume you also have a foreign key linking a comment to something like a post. You can then fetch all comments for that post ID:
$comments = Comment::latest()->where('post_id', '=', $post->id)->get();
Then sort them based on their parent_id value:
$comments = $comments->keyBy('parent_id');
You can then iterate over them in your Blade template like this and every iterate, check if there are comments with that comment’s ID as its parent ID:
<!-- Kick-start the loop -->
#foreach($comments[0] as $comment)
#include('partials.comment')
#endforeach
The content of partials/comment.blade.php
<blockquote class="comment">
<p class="comment-body">{{ $comment->body }}</p>
<footer>
<span class="comment-author">{{ $comment->user->name }}</span>,
<time class="comment-date" pubdate="pubdate">{{ $comment->created_at }}</time>
</footer>
</blockquote>
#if(isset($comments[$comment['id']])
#each('partials.comment', $comments[$comment['id'], 'comment')
#endif
Table Like:
+------------+-----------+---------+
| comment_id | parent_id | comment |
+------------+-----------+---------+
| 1 | 0 | test |
| 2 | 1 | test1 |
| 3 | 0 | test2 |
| 4 | 0 | test3 |
| 5 | 1 | test4 |
| 6 | 2 | test4 |
| 7 | 4 | test5 |
| 8 | 5 | test6 |
| 9 | 6 | test7 |
| 10 | 4 | test8 |
| 11 | 3 | test9 |
+------------+-----------+---------+
Get first level parent:
$comments = Comment::where('parent_id', '0')->orderBy('comment_id', 'asc')->get();
$result = array();
foreach($comments as $comment){
$list = array();
$list = array_merge($list, [['comment_id' => $comment->comment_id, 'parent_id' => $comment->parent_id, 'comment' => $comment->comment]]);
$result = array_merge($result, $this->get_child_comment($comment->comment_id,0, $list));
}
function get_child_comment($pid,$level,$list=array()) {
$sub_comments = Comment::where('parent_id','=',$pid)->where('comment_id','!=',$pid)->orderBy('comment_id', 'asc')->get();
foreach($sub_comments as $sub_comment){
$space=" "; sigm='-';
for($j=0; $j<=$level; $j++)
{
$space .=$space;
}
for($j=0; $j<=$level; $j++)
{
$space .= $sigm;
}
$sub_comment->comment = html_entity_decode($space, ENT_QUOTES, "utf-8").' '.$sub_comment->comment;
$list = array_merge($list, array(['comment_id' => $sub_comment->comment_id, 'parent_id' => $sub_comment->parent_id, 'comment' => $sub_comment->comment]));
$list = $this->get_child_comment($sub_comment->comment_id, $level+1, $list);
}
return $list;
}
}
return get array.simple print using foreach:
foreach($result as $val) {
echo $val['comment'].'<br>';
}
Output:
test
- test1
-- test4
--- test7
- test4
-- test6
test2
- test9
test3
- test5
- test8
You can represent comments in following structure:
$comments = [
(object)[
'id' => 1,
'text' => 'Comment 1',
'children' => [
(object)[
'id' => 2,
'text' => 'Reply 1',
'children' => [
(object)[
'id' => 2,
'text' => 'Reply 1.1'
]
]
],
(object)[
'id' => 4,
'text' => 'Reply 2',
]
]
]
];
And print them using recursive function like this:
function printComments($comments, $prefix = '-') {
foreach ($comments as $comment) {
echo $prefix.$comment->text.'<br>';
isset($comment->children) && printComments($comment->children, $prefix.'-');
}
}
Or calling view recursively in case of Laravel:
#include('comments.view.path') inside of
#include('comments.view.path')
For convinient retrieving of comments in the represented structure and generally for working with tree structure I suggest using nested set model and etrepat/baum for Laravel which has toHierarchy() method.

Database array only returns one row

I am sorry for my lazy title. I hope that a moderator could improve it so the database won't get infected.
I got the following code (forum.php);
<?php
$res = $db->query('
SELECT *
FROM forums_categories
ORDER BY category_id
');
while ($row = $db->fetch_array($res)) {
$categories = array(
'ID' => $row['category_id'],
'NAME' => $row['category_name']
);
echo '<pre>';
print_r($categories);
echo '</pre>';
}
And I got the following database structure;
|---------------|-------------------|
| category_id | category_name |
|---------------|-------------------|
| 1 | Example 1 |
| 2 | Example 2 |
| 3 | Example 3 |
| 4 | Example 4 |
| 5 | Example 5 |
| 6 | Example 6 |
|---------------|-------------------|
But my array only returns 1 value:
Array
(
[ID] => 1
[NAME] => Example 1
)
Oh and if somebody likes to know how my $db->fetch_array looks like:
<?php
function fetch_array($result)
{
return mysql_fetch_assoc($result);
}
How can I return all rows in my array? Thank you for reading and thank you for replying!
You're overwriting the previous value of $categories on each iteration
$categories[] = array(
'ID' => $row['category_id'],
'NAME' => $row['category_name']
);
You might also want to initialize an empty array
$categories = array();
before your loop to avoid warnings.

php Multidimensional array question

So I have an array like the following:
Array
(
[0] => Array
(
[user_id] => 684
[sec_id] => 2
[rank_id] => 1
[rank] => usr
)
[1] => Array
(
[user_id] => 693
[sec_id] => 3
[rank_id] => 5
[rank] => usr
)
)
And I have another array like this
Array
(
[0] => 2
[1] => 7
[2] => 27
)
I want the value of the second array to be added at the end of each arrays of the 1st array, and it should be multiplied. I mean, if I have 100 arrays in the first array, and 3 elements in the second array, I should have 300 in the resulting array.
Taking example of the above, I would like to have something as follows:
user_id | sec_id | rank_id | rank | menu_id
684 | 2 | 1 | usr | 2
684 | 2 | 1 | usr | 7
684 | 2 | 1 | usr | 27
693 | 3 | 5 | usr | 2
693 | 3 | 5 | usr | 7
693 | 3 | 5 | usr | 27
I tried with the following function, but it's not working.
function getR($arr_one,$arr_two) {
foreach ($arr_one as $k=>&$v) {
foreach ($arr_two as $x=>&$y) { $v['menu_id'] = $y; }
}
return $arr_one;
}
This is just making an array like this:
user_id | sec_id | rank_id | rank | menu_id
684 | 2 | 1 | usr | 27
693 | 3 | 5 | usr | 27
Means, it's just adding menu_id at the end of each element of the first array, but not multiplying. Any idea, I'm surely missing something.
Thanks guys.
function getR($arr_one,$arr_two) {
$new_arr = array();
foreach ($arr_one as $k=>$v) {
foreach ($arr_two as $x=>$y) {
$this_item = $v;
$this_item['menu_id'] = $y;
$new_arr[] = $this_item;
}
}
return $new_arr;
}
I'm not going to ask... but try this:
<?php
function crazy ($arr1,$arr2) {
foreach ($arr1 as $key=>$value) {
foreach ($arr2 as $value2) {
$nvalue=$value;
$nvalue[]=$value2;
$new[]=$nvalue;
}
}
return $new;
}
$arr1=array(array('user'=>1,'dude'=>2),array('user'=>2,'dude'=>3));
$arr2=array(2,7,27);
print_r(crazy($arr1,$arr2));
this is tested too, http://www.ideone.com/Of126
Without testing (eek!) I imagine something like this:
function getR( $arr_one, $arr_two )
{
$second_key = 0;
foreach ( $arr_one as $k => &$v )
{
$v['menu_id'] = $second_key++;
if ( 3 == $second_key ) $second_key = 0;
}
return $arr;
}
Presumably, you're passing the first array by reference? Not sure what $arr is that you're returning though...

Categories