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
)
)
Related
I am trying to load dynamic table data, my URI is;
example.coma/admin/view/form/<form_id>
My model query is;
public function getRecords($table, $form_id) {
$this->db->select('*');
$this->db->from($table);
$this->db->where('form_id', $form_id);
$query = $this->db->get();
if ($query->num_rows() > 0) {
return $query->result_array();
}
}
This returns an array of data, I need to build a HTML table based on this array.
I'll show an example of two different arrays returned by the query.
Array 1.
(select * from members where form_id = 123)
Array
(
[0] => Array
(
[id] => 104
[member_no] =>
[firstname] => Peter
[lastname] => Keys
[address] => 17 main road
[email] => P3TER#HOTMAIL.CO.UK
[postcode] => UK123
[city] => London
[telnum] => 123123123
[fk_form_submission_id] => 123
)
)
Array 2.
(select * from orders where form_id = 123)
Array
(
[0] => Array
(
[colour] => blue
[type] => shirt
[age] => 34
[size] => medium
[quantity] => 2
[discount] => Y
[posted] => N
)
)
What I want to achieve is display a vertical table to display the dataset. Obviously each table will have different row names, example below;
Table 1.
+---------------+-------+
| ID | 104 |
+---------------+-------+
| Member Number | |
+---------------+-------+
| First Name | Peter |
+---------------+-------+
| Last Name | Keys |
+---------------+-------+
| etc | etc |
+---------------+-------+
Table 2.
+--------+--------+
| Colour | blue |
+--------+--------+
| P Type | shirt |
+--------+--------+
| Age | 34 |
+--------+--------+
| Size | medium |
+--------+--------+
| etc | etc |
+--------+--------+
How can I set these table row names? Do I need to create another array of table headers and merge both arrays?
Any advice is appreciated.
I'm not sure I fully understand - but if you want to set the keys of the array dynamiclly you can do that with foreach loop as:
<table>
<tr><th>Key</th><th>Value</th></tr>
<?php foreach($res[0] as $key => $val)
echo '<tr><td>'. $key . '</td><td>' . $val . '</td></tr>'; ?>
</table>
Edit:
If you want to change the keys name to something more displayable I would recommend using another array for swap (most of the time it done for translation...).
$displayName = array("id" => "ID", "member_no" => "Member Number", "firstname" => "First Name" ..., "type" => "P type", ...);
foreach($res[0] as $key => $val)
echo '<tr><td>'. $displayName[$key] . '</td><td>' . $val . '</td></tr>';
You can also use array_combine but that will need to know which kind of keys you have...
Notice that this solution will work only if the display name are unique for all kind of keys
I have multi level categories array.
i only want to get child ID's, if parent don't have child. then return that parent id as well
id parent_id name
1 0 fashion
2 1 women
3 1 men
4 2 jeans
5 2 skirts
6 5 short skirts
7 5 long skirts
8 0 Home & entertainment
I tried this fucntion.
function buildtree($src_arr, $parent_id = 0, $tree = array()){
foreach($src_arr as $idx => $row){
if($row['parent_id'] == $parent_id){
foreach($row as $k => $v)
$tree[$row['id']][$k] = $v;
unset($src_arr[$idx]);
$tree[$row['id']]['children'] = self::buildtree($src_arr, $row['id']);
}
}
ksort($tree);
return $tree;
}
But it also gives me all parents id's.
desired outcome with id ( i am typing name for easy understanding)
array(
[0] = men
[1] = jeans
[2] = short skirts
[3] = long skirts
[4] = home & entertainment
)
Thanks for help.
A simple where clause with not in logic will help you select the children, then the parents that have no children.
select c.id, c.name
from categories c
where c.id not in (select parent_id from categories order by id desc)
Which gives a result set of
+----+----------------------+
| id | name |
+----+----------------------+
| 3 | men |
| 4 | jeans |
| 6 | long skirts |
| 7 | short skirts |
| 8 | home & entertainment |
+----+----------------------+
5 rows in set
See SQL Fiddle
Done in PHP you can use this function, which gives you a flat array with all edge childs based on a given parent_id. If you want to check a whole database table sql-only is the better option.
function getchildren($src_arr, $parent_id = 0)
{
$allchildren = array();
foreach($src_arr as $idx => $row){
if($row['parent_id'] == $parent_id){
$children = static::getchildren($src_arr, $row['id']);
if ($children) {
$allchildren = array_merge($allchildren, $children);
} else {
$allchildren[] = $row;
}
}
}
return $allchildren;
}
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.
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.
So I'm working on a permission system. It is basically a role-based system. I have a group table with a many-to-many relationship with a tasks table, and a permissions table to tie them together.
The data would look something like this (tasks table):
+-----+--------+---------+----------+
| id | task | group | parent |
|-----------------------------------|
| 1 | view | news | |
|-----------------------------------|
| 2 | edit | news | |
|-----------------------------------|
| 3 | view | forums | |
|-----------------------------------|
| 4 |a forum | forums | view |
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
What I'm trying to do is allow each group specific permissions with each page. But when needed, more specificity is available. For example on a forums page, I want to be able to control which group can view/edit posts/delete posts/etc from each individual forum.
This is all working - my problem is how to display this data so that it can be assigned. This is what I want it to look like:
News
-- View
-- Edit
Forums
-- View
---- a forum
-- Edit
---- a forum
I just can't wrap my head around how to format this array to do that
Array
(
[0] => Array
(
[task] => view
[group] => news
[parent] =>
)
[1] => Array
(
[task] => edit
[group] => news
[parent] =>
)
[2] => Array
(
[task] => view
[group] => forums
[parent] =>
)
[3] => Array
(
[task] => a forum
[group] => forums
[parent] => view
)
)
Sorry for the confusing post!
Okay totally reformatting my answer now, as it was a bit ambigious what exactly is NOT working.
First rearrange the array like this:
while($result = $query->fetch_assoc())
{
$group = $result['group'];
foreach($result as $field => $value)
{
$data[$group][$field] = $value;
}
}
Then you can iterate through it:
foreach($data as $group)
{
echo $group;
foreach($group as $task => $value)
{
if($task == 'parent' && $task != '') { $indent = '----';}
else {$indent = '--'; }
echo $indent,$task;
}
}
All just sketched out of my head, so I hope it works and it is what you want this time.