I am getting duplicate nodes on my family tree - php

My function is duplicating some nodes on the tree. When I am calling that function in a recursive way. I have a database table of all father, mother, wife, husband, child ids. I am taking all persons from their father id only. I don't know from where these extra nodes are coming and how should I handle ie it. Output image
<?php
function categoryTree($parent_id = 0,&$alreadyThereArr=array())
{
$ci =& get_instance();
//$query = $ci->db->query("SELECT * FROM tbl_user WHERE father_id = $parent_id ORDER BY id ASC");
$sql="SELECT * FROM `tbl_user` WHERE father_id = '$parent_id' ORDER BY id ASC";
$query=$ci->db->query($sql);
$result=$query->result();
if(count($result) > 0)
{
echo '<ul>';
foreach($result as $key)
{
if(!in_array($key->id,$alreadyThereArr))
{
//echo 'In';
if($key->wife_id != 0)
{
//echo 'wife';
$wife=$ci->Main_M->getSingleRow('tbl_user','id',$key->wife_id);
$start='<div>
<span class="male">'.$key->name.'</span>
<span class="spacer"></span>
<span class="female">'.$wife->name.'</span>
</div>';
}
else
{
$gender=($key->gender == 'M') ? 'male' : 'female';
$start='<div><span class="'.$gender.'">'.$key->name.'</span></div>';
}
$alreadyThereArr[]=&$key->id;
echo '<li>';
echo $start;
echo '<ul>';
categoryTree($key->id, $alreadyThereArr);
echo '</ul>';
echo '</li>';
}
}
echo '</ul>';
}
//print_r($alreadyThereArr);
}
?>

Related

How to create a list view from a database table?

I'm querying a category table id, parent_id, name to generate list view of all the categories and sub-categories. What I have so far is:
HP
Laptops
PC
Sports
Sunglasses
Food
House
The function that I use to generate the output is:
public function get_category($parent_id = NULL)
{
$query = $this->db->get_where('category', array('parent_id' => $parent_id))->result();
$result = '';
foreach ($query as $row)
{
$i = 0;
if ($i == 0)
{
$result .= '<ul>';
}
$result .= '<li><a href="'.base_url().'category/edit/'.$row->id.'">' . $row->name;
$result .= $this->get_category($row->id);
$result .= '</li>';
$i++;
if ($i > 0)
{
$result .= '</ul>';
}
}
return $result;
}
This is what I want to achieve:
HP
HP > Laptops
HP > PC
Sports
Sports > Sunglasses
Food
House
Try following
public function get_category($parent_id = NULL,$level, $prev = "")
{
$query = $this->db->get_where('category', array('parent_id' => $parent_id))->result();
$result = '';
foreach ($query as $row)
{
$temp = $prev;
if($level == 0){
$temp .= '' . $row->name.'';
}else{
$temp .= ' > ' . $row->name.'';
}
$result .= $temp;
$result .= "<br />";
$result .= $this->get_category($row->id, $level + 1, $temp);
}
return $result;
}
First run of this function should be
get_category(NULL, 0, "");
Here
NULL is parent id (you can use a loop to dynamicaly pass id)
level should be 0
prev should be empty
I've created a demo according to your needs and it worked for me. I'm sharing the code below, I've done explaining in the comments wherever necessary. See if it helps you.
Controller
public function get_category($parent_id = NULL){
// get the {category}, {sub_category} from the table, if {sub_category} stored in different table use {JOIN}
$data['category'] = $this->db->get_where('category', array('parent_id' => $parent_id))->result();
$this->load->view('your-view', $data);
}
View
<?php
if(!empty($category)){ // check if {$category} has value; if not, do nothing
$catArr = array(); // initialize array to store category id
?>
<ul> <!-- Start ul -->
<?php
foreach($category as $cat){ //loop through all the {category} array
// check if the {cat_id} already exists in array; if not, do so where {cat_id} is category id(change your value here)
if( ! in_array( $cat->cat_id, $catArr ) ){
$catArr[] = $cat->event_id;
?>
<li><?php echo $cat->cat_name; ?></li> <!-- show {cat_name} in list -- your category name here -->
<?php
}
?>
<!-- Show {cat_name} and {subcat_name} both -- (your values here). Give links or whatever here(your styling)-->
<li><?php echo $cat->cat_name; ?> > <?php echo $cat->subcat_name; ?></li>
<?php
}
?>
</ul>
<?php
}
?>
OUTPUT
Honda
Honda > Car
Honda > Bike
Philips
Philips > Electricals
Philips > Electronics

How to show specific menu items for specific user login in PHP using mysql

I have a tables in MySQL one is test table columns like this
id refid name userdefined
1 0 A
2 0 B
3 0 C
4 1 A1 abc
5 1 A2 cde
6 2 B1
7 2 B2
8 3 C3
9 3 c4
10 3 c5
11 2 C7
12 2 C8 lmn
13 11 c9
14 11 c10
Using the above table I am creating the dynamic menu using a PHP function.
I have one more table, it has the login fields and data like this:
id username password field3
1 john john 1,3,4,5,6,7,8,9
What i want is if John is logged in, how do I only show the menu items in field3.
I am new to PHP. I am showing all menu items using a function in
PHP please help me, thanks in advance.
<?php
//this is php function for creating menu
$sql2 = mysqli_query($conn, 'select * from login');
$row = mysqli_fetch_array($sql2);
$menu_items = explode(',', $row['field3']);
function submenu($parentid = 0)
{
global $conn;
$sql = mysqli_query($conn, "SELECT * FROM test WHERE refid=" . $parentid . " AND id IN " . ($menu_items));
{
$rowcount = mysqli_num_rows($sql);
if ($rowcount > 0) {
echo '<ul>';
}
while ($row = mysqli_fetch_array($sql, MYSQLI_ASSOC)) {
if ($row['refid'] == 0) {
echo '<li class="limain">' . $row['name'];
submenu($row['id']);
echo '</li>';
} else {
if ($row['userdefined']) {
echo '<li class="lichild">' . $row['name'] . '';
} else {
echo '<li class="lichild">' . $row['name'];
}
submenu($row['id']);
echo '</li>';
}
}
if ($rowcount > 0) {
echo '</ul>';
}
}
}
?>
$sql2=mysqli_query($conn,'select * from login');
$row = mysqli_fetch_array($sql2);
//storing the field values in menuitems variables
$menu_items = $row['field3'];
//pass the menuitem variables to query
function submenu($parentid=0){
global $conn;
$sql=mysqli_query($conn,"SELECT * FROM test WHERE refid=".$parentid ." AND
id in ($menu_items)");
{
$rowcount=mysqli_num_rows($sql);
if($rowcount>0){
echo '<ul>';
}
while($row=mysqli_fetch_array($sql,MYSQLI_ASSOC))
{
if($row['refid']==0)
{
echo '<li class="limain">'.$row['name'];
submenu($row['id']);
echo '</li>';
}
else{
if($row['userdefined']){
echo '<li class="lichild">'.$row['name'].'';
}else{
echo '<li class="lichild">'.$row['name'];
}
submenu($row['id']);
echo '</li>';
}
}
if($rowcount>0){
echo '</ul>';
}
}
}
Your function is mostly correct in principle, I had a bit of trouble following your function so I changed a few things to improve readability, but this should work.
The only issue I found that would prevent this from working was your if($refid), which is checking for any data not == to null.
0 == null //true 0 === null //false
If I understood your table correctly, entries with a refid of 0 are parent items. In that case they're the only menu items passing into that part of the function, so I changed it from if ($refid) to if ($refid === 0)
With regards to you wanting to you only wanting to show specific menu items, you'll need to run a separate query outside of the function to get the list you made. And then add a check in you submenu() function.
I didn't have a way to test this, but it should work.
//Query to get list of menu items
$menu_items = explode(',', $row['menus']);
function submenu($parentid=0, $menu_items=null) {
global $conn;
$sql=mysqli_query($conn,"SELECT * FROM test WHERE refid=".$parentid);
$rowcount=mysqli_num_rows($sql);
if($rowcount > 0) {
echo '<ul>';
}
while($row=mysqli_fetch_array($sql,MYSQLI_ASSOC)) {
if($menu_items !== null || !in_array($id, $menu_items)) {
continue;
}
$id = $row['id'];
$refid = $row['refid'];
$userdefined = $row['userdefined'];
$name = $row['name'];
if($refid === 0) {
echo "<li class='limain'>{$name}";
submenu($id, $menu_items);
echo '</li>';
} else if ($refid > 0) {
if($userdefined) {
echo "<li class='lichild'><a href='{$userdefined}'>{$name}</a>";
} else {
echo "<li class='lichild'>{$name}";
}
submenu($id, $menu_items);
echo '</li>';
}
}
if($rowcount > 0) {
echo '</ul>';
}
}
You must protect the php files too, not only the menu items. If the user know the php filename, can access with a direct link to protected area.

Append data and display html table

I have some data set. I want to arrange data like this:
My code displays result like this:
.
How can I fix this. This is my code:
<?php
echo "<tr><th></th><th>Control</th><th>Sub 1</th><th>Sub2</th></tr>";
$i=0;
$PrevIssoff=0;
$sql="SELECT `code`, `name`,`type`
FROM `testdate`
WHERE `code`='11111'
ORDER BY `code` ASC, `type` ASC ";
$result=mysql_query($sql);
while($row=mysql_fetch_array($result)){
$frm=$row['code'];
if ($frm != $PrevIssoff && $row['type']==0)
{
$i=$i+1;
$PrevIssoff=$frm;
echo "<tr><td>$i</td><td>$row[name]</td><td></td><td></td></tr>";
}
else if($row['type']==1 )
{
echo "<tr><td></td><td></td><td>$row[name]</td><td></td></tr>";
}
else if ($row['type']==2)
{
echo "<tr><td></td><td></td><td></td><td>$row[name]</td></tr>";
}
}
echo"</table>";
?>
Database table structure - testdate
databasetable
First, your data needs to be normalized. There should be a way to write a database query to skip this step if you look hard enough.
Walkthrough each row in the while loop, building a close representation for it an array.
$dataTable = [];
while ($row = mysqli_fetch_array($result)) {
$numRows = count($dataTable);
$lastRowIndex = $numRows == 0 ? 0 : $numRows-1;
if($numRows == 0) {
$dataTable[] = [];
}
if(count($dataTable[$lastRowIndex]) == 3) {
$dataTable[] = [];
$lastRowIndex += 1;
}
$type = $row['type'];
$dataTable[$lastRowIndex][$type] = $row['name'];
}
Then make your $rowsMarkup which can be readily concatenated with the table heading.
$rowsMarkup = array_map(function($row) {
return '<tr>'.
'<td>'.$row[0] .'</td>'.
'<td>'.$row[1] .'</td>'.
'<td>'.$row[2] .'</td>'.
'</tr>';
},
$dataTable
);

restrict children count till 6th level in a tree

the php function i made gets all the children of a the parent in tree form . The problem is that it gets all the children but i want to restrict it till level 6th of the tree . The code i made is
get_childs("2");
function get_childs($parent_id){
GLOBAL $con;
if ($result = mysqli_query($con,"SELECT * FROM user_profile WHERE referred_by='$parent_id'")) {
echo '<ul>';
while ($row = $result->fetch_assoc()) {
echo '<li>'.$row['user_id'].'';
//call again for each child. if the id dosen't have childs, then prints nothing and go on!
get_childs($row['user_id']);
echo '</li>';
}// end while
echo '</ul>';
}// end if select
}
The output it generates
I want to restrict it till 17 as in above output as the level 6th reaches there .
As per my comment, I'd suggest something like this:
get_childs("2", 0);
function get_childs($parent_id, $level){
GLOBAL $con;
if ($result = mysqli_query($con,"SELECT * FROM user_profile WHERE referred_by='$parent_id'")) {
echo '<ul>';
while ($row = $result->fetch_assoc()) {
echo '<li>'.$row['user_id'].'';
//call again for each child. if the id dosen't have childs, then prints nothing and go on!
if($level < 6)
get_childs($row['user_id'], $level + 1);
echo '</li>';
}// end while
echo '</ul>';
}// end if select
}
With this tiny alteration, your tree will stop as soon as the 6th level is reached. (You might have to tweak it a tiny bit)
get_childs("2", 6);
function get_childs($parent_id, $level){
if($level < 1) return false;
GLOBAL $con;
if ($result = mysqli_query($con,"SELECT * FROM user_profile WHERE referred_by='$parent_id'")) {
echo '<ul>';
while ($row = $result->fetch_assoc()) {
echo '<li>'.$row['user_id'].'';
//call again for each child. if the id dosen't have childs, then prints nothing and go on!
get_childs($row['user_id'], $level--);
echo '</li>';
}// end while
echo '</ul>';
}// end if select
}

How to create a nested menu from MySQL with PHP?

I need to create a menu with PHP from a MySQL database.
Table called categories has id, name, parent_id, shortdesc, etc.
The output need to have parent list and children list under the partent list as follows.
If you can show me codes or website, I will appreciate it.
<ul id="catmenu">
<li class="menulist">Cars
<ul>
<li>Ford</li>
<li>Honda</li>
<li>Toyota</li>
</ul>
</li>
<li class="menulist">Food
<ul>
<li>Pasta</li>
<li>Pizza</li>
...
</ul>
</li>
...
...
</ul>
This is specifically for two levels deep. Recommended approach should it be more is to use an optimized table structure for traversal, like http://articles.sitepoint.com/article/hierarchical-data-database/2 (pointed out elsewhere) or to pull the data you need and push it into a dictionary (associative array) and query it that way.
<?php
$query = <<<EOT
SELECT
parent.name as parent_name,
child.name as child_name,
FROM
items child
INNER JOIN
items parent
ON
child.parent_id = parent.id
ORDER BY
parent.name
EOT;
$result = mysql_query($query) or die('Failure!');
echo "<ul id=\"catmenu\">";
$last_parent = '';
while($row = mysql_fetch_array($result)){
// If this is a new category, start a new one
if($last_parent != $row['parent_name']){
// Unless this is the first item, close the last category
if($last_parent != ''){
echo "</ul></li>";
}
$last_parent = $row['parent_name'];
echo "<li class=\"menulist\">{$row['parent_name']}<ul>";
}
echo "<li>{$row['child_name']}</li>";
}
// If we actually had items, close the "category"
if($last_parent != ''){
echo "</ul></li>";
}
echo "</ul>";
?>
If you have only two levels then, you could just display them :
echo '<ul id="catmenu">';
foreach($menu as $element) {
echo '<li><ul class="menulist">';
foreach($element['submenu'] as $submenu) {
echo '<li>' . $submenu['name'] . '</li>';
}
echo '</ul></li>';
}
echo '</ul>
If you have an undefined number of submenus however you should use a Recursive Function.
function menu($item) {
$ret = '<li>' . $item['name'];
if (!empty($item['submenu'])) {
foreach($item['submenu'] as $submenu) {
$ret .= menu($submenu);
}
}
return $ret;
}
echo menu($menu);
So every of your subcategories, whatever their number is will be displayed.
You make database like this.
ID NAME PARENT
0 Cars -1
1 Foods -1
2 Ford 0
3 Honda 0
4 Toyota 0
5 Pasta 1
6 Pizza 1
...
You query them all up and put it in an array.
$Menus = array();
// In a read MySQL loop
$Menus[$i]['ID']
$Menus[$i]['NAME']
$Menus[$i]['PARENT']
// Sorry, lazy to write. I think you know what I mean.
Then you loop all menu looking for PARENT == -1. Generate all UL and IL then sub it with another nested menu.
You can simply create a function like this.
var $MenuLevelClass = array("menulist");
function CreateMenu($Menus, $Tab = 0, $Parent = -1, $Level = 0) {
global $MenuLevelClass;
$CatClass = ($Level != 0) ? '' : ' class="catmenu"';
$MenuClass = $MenuLevelClass[$Level];
if ($MenuClass != '')
$MenuClass = ' class="'.$MenuClass.'"';
$TabCount = $Level + $Tab;
$TabUL = "";
for ($t = 0; $t < $TabCount; $t++)
$TabUL = $TabUL."\t";
$TabLI = $TabUL."\t";
?>
<?=$TabUL?><ul<?=$CatClass?>>
<?php
$MenuCount = count($Menus);
for ($m = 0; $m < $MenuCount; $m++) {
$Menu = $Menu[$m];
$ID = $Menu['ID'];
if ($ID != $Parent)
continue;
?>
<?=$TabLI?><li<?=$MenuClass?>><?=$Menu['Name']?><?=CreateMenu($Menus, $Tab + 1, $ID, $Level + 1)?></li>
<?php
?>
<?=$TabUL?></ul>
<?php
}
}
And to use it just run 'CreateMenu($Menus);' or 'CreateMenu($Menus, $PrefixTabCount);'.
CreateMenu will recursively create the nested menu for you.
I have not test it so you may have to adjust it.
Hope this helps.

Categories