Recursive PHP function not returning result - php

Just a simple function to build breadcrumbs based off a simple database table where there are columns:
id, parent, title
The "parent" column can be 0 for top-level, or the "id" of another row for sub-categories (unlimited depth). All I'm trying to do is have a function that'll help me build breadcrumbs from it, starting from the "id" of the bottom-most category I specify and working its way up to the top parent. Here's what I have:
function getCategoryParents($id=0, $out=array()) {
$id = (int)$id;
if ($id > 0) {
$query = "SELECT * FROM `" .$this->tables['categories']. "` WHERE (`id`=" .$id. ")";
$cat = sqlfetch(sqlquery($query));
array_push($out, $cat);
if ($cat['parent']) {
$this->getCategoryParents($cat['parent'], $out);
} else {
return $out;
}
} else {
return $out;
}
}
But it's not returning anything. But, if I do a print_r($out) from within the function instead of return, ex:
if ($cat['parent']) {
$this->getCategoryParents($cat['parent'], $out);
} else {
echo print_r($out);
}
It outputs the array just fine. But I need to be able to actually work with the array, so I need it returned from the function. I'm sure I'm missing something incredibly small, but I cannot figure it out for the life of me!
Also, I don't want to do a global variable, and also need the info of the category id specified in the initial function call as part of the array as well (as I was trying to do).

Following the suggestions, here's what ended up working:
function getCategoryParents($id=0) {
$out = array();
$id = (int)$id;
if ($id > 0) {
$query = "SELECT * FROM `" .$this->tables['categories']. "` WHERE (`id`=" .$id. ")";
$cat = sqlfetch(sqlquery($query));
array_push($out, $cat);
if ($cat['parent']) {
$out = array_merge($out, $this->getCategoryParents($cat['parent']));
}
}
return $out;
}

Related

How to compare associative array with result_array in PHP

Need to bind Page drop-down conditionally on base of 'Content' table. Page titles are stored in an associative array and 'Content' table have page code stored in it. Here is the code
Function which return page titles
public function getPageTitles(){
$pageTitles = array("Home"=> "Home",
"AboutUs"=> "About Us", //AboutUs will save in database as pageCode
"Features"=> "Features",
"ContactUs"=> "Contact Us");
return $pageTitles;
}
Function which checks if page have content or not:
public function getPageTitlesWithNoContent()
{
$pageTitles = $this->getPageTitles();
$this->db->distinct('pageCode');
$this->db->select('pageCode');
$this->db->from('content');
$this->db->where('status', 1);
$data = $this->db->get();
$queryResult = $data ? $data->result_array() : 0 ;
$emptyPageTitle = array();
foreach($pageTitles as $x => $x_value)
{
$hasContent = in_array($x, $queryResult);
if (!$hasContent){
$emptyPageTitle[$x] = $x_value;
}
}
return $emptyPageTitle;
}
This function is returning all page titles.. new to php no idea what is wrong
Check name fields in table is same? With Uppercase first char?
Also change your code in this loop:
foreach($pageTitles as $x => $x_value)
{
if (in_array($x, $queryResult)){
$emptyPageTitle[$x] = $x_value;
}
}
I remove ! negative in check condition
#NMathur I think you almost got it. Made some changes for you in that code, Check it.
public function getPageTitlesWithNoContent() {
$pageTitles = $this->getPageTitles();
$this->db->select('pageCode');
$this->db->from('content');
$this->db->where('status', 1);
$this->db->group_by('pageCode');
$query = $this->db->get();
$queryResult = array();
foreach ($query->result_array() as $row) { // This loop should need to form an array based on query result
$queryResult[$row['pageCode']] = $row['pageCode'];
}
$emptyPageTitle = array_diff_key($pageTitles,$queryResult); // Compares the keys from array1 against the keys from array2 and returns the difference
return $emptyPageTitle;
}
As #TamilvananN guided, I printed the queryResult and tried this workaround:
foreach($pageTitles as $x => $x_value)
{
foreach ($queryResult as $item)
{
if (!($x == $item['pageCode'])){
$emptyPageTitle[$x] = $x_value;
}
}
}
It is working, but as you can see this has loop in a loop .. that can be very costly .. can you please share any fast way to compare the results.

Codeigniter multi-dimensional array return only the first row

One day I'm on this problem and I cant find the solution.
My goal is to return a list of links from an ID (the father). So I want all his childs.
But in the view, I only have on result (the 1st one...).
I have in my controller :
$data['list_link'] = $this->menuManager->list_link();
In my Model :
function list_link($fatherid=0){
$r = array();
$sSQL = 'SELECT * FROM categories WHERE fatherid = ' . $fatherid . ' AND siteid = ' . MY_SITEID_DEFAULT . ' ORDER BY name';
$query = $this->db->query($sSQL);
// stock results in array
$r[] = $query->result_array();
foreach ($query->result() as $row) {
// let's find the childs
$this->list_link($row->id,$loop);
}
return $r;
}
If I "for each" the $r here, all looks good.
So, $data['list_link'] shoud now have all the rows.
In my view :
foreach ($list_link as $link){
foreach ($link as $row){
echo $row['name'];
}
}
But, I only have the first links (first childs), not the other one. Any help would be greatly appreciated as I'm on that problem for days...
You're not storing any values in the recursive calls (though I'm still not sure you'd get what you expect). You'd need to populate $r with each function call:
$r[] = $this->list_link($row->id,$loop);
However, either I missed something or you're overcomplicating things, but I think you could simply return the result array and use it:
function list_link($fatherid=0,$loop=0){
$sSQL = 'SELECT * FROM categories WHERE fatherid = ' . $fatherid . ' AND siteid = ' . MY_SITEID_DEFAULT . ' ORDER BY name';
$query = $this->db->query($sSQL);
return $query->result_array();
}
UPDATE
Your latest version still doesn't collect the data from recursive calls, here is the full function, see if it works:
function list_link($fatherid=0){
$r = array();
$sSQL = 'SELECT * FROM categories WHERE fatherid = ' . $fatherid . ' AND siteid = ' . MY_SITEID_DEFAULT . ' ORDER BY name';
$query = $this->db->query($sSQL);
$result = $query->result_array();
// stock results in array
$r[$fatherid] = $result;
foreach ($result as $row) {
// let's find the children
$r[$fatherid][$row['id']] = $this->list_link($row['id']);
}
return $r;
}
Note that I've added $r[$fatherid][$row['id']] so the end result should be an array with a branching structure. If you don't want that, just do $r[] instead.

How to make a function for autoset

I'm not sure if it is possible or not but what I am looking for a way making auto "set" for mysql results.
function test(){
$pDatabase = Database::getInstance();
$site = new Template("sites.tpl");
$query = 'SELECT * FROM sites';
$result = $pDatabase->query($query) or die('Query failed: ' . mysql_error());
while ($row = mysql_fetch_array($result)) {
$site->set("id",$row['id']);
$site->set("category",$row['category']);
$site->set("name",$row['name']);
$site->set("html",$row['html']);
$site->set("css",$row['css']);
$site->set("js",$row['js']);
$site->set("php",$row['php']);
$site->set("details",$row['details']);
$site->set("link",$row['link']);
}
mysql_free_result($result);
}
Maybe there is a better way doing all that $site->set ? I mean my code looks way too big and pointless. Any other ways ?
If you want to call $site->set on all key/value pairs in $row
while ($row = mysql_fetch_array($result)) {
foreach($row as $key => $value) {
$site->set($key,$value);
}
}
Change to this...
Assuming your site->set function will always take the exact table column names.
while ($row = mysql_fetch_array($result)) {
foreach($row as $k=>$v){
$site->set($k,$v);
}
}
You could also alter teh $site->set function and do the loop there. And then just do this...
while ($row = mysql_fetch_array($result)) {
$site->set($row);
}
And the function. Just an outline. Not really sure what you have going on in the actual function. But this is just an idea
function set($arrorkey, $value=null){
// If passed value is an array, do this...
if(is_array($arrorkey)){
foreach($arrorkey as $k=>$v){
$_SESSION[$k] = $v;
//Or database binding or whatever you're actually doing inside here
}
} else {
// If passed value, is a column, and value pair...do this.
$_SESSION[$arrorkey]=$value;
//Or database binding or whatever you're actually doing inside here
// This is just an example
}
return;
}

Dropdown list for reporting hierarchy data

I have two tables reporting,employee_details
reporting contains suprvisor_id,subordinate_id fields which are emp_id in employee_details table .And reporting table contains three levels (supervisors->subordinates->subordinates->employees) and i want to show this data as dropdown by fetching name from employee_details table, as hierarchy .so please help me is there any way to do it?
You defititly need to get the hole tree in an array if you want to display it. And this is a little bit tricky.
I think you arent't really shure how many levels you have in tree.
So the simplest way is the following but in big trees it have a bad performance. When the tree grows really big you need to check other technics.
The following is fast written, not tested an could have some bugs. But I post it to show you a possible solution:
<?php
class tree {
private $level = 0;
public function getChildsRecoursive($parentid=0,$recoursive=false) {
// you would have your own db object... please replace this...
$db->select("select * from reporting r JOIN employee_details d ON(r.subordinate_id=d.emp_id) where supervisor_id='$parentid' ORDER BY d.name");
$r = array();
while($data = $db->fetchArray()) {
$sid = $data['supervisor_id'];
$cid = $data['subordinate_id'];
if($recoursive) {
$this->level++;
$data['level'] = $this->level;
$data['childs'] = $this->getChildsRecoursive($cid, true);
$this->level--;
}
$r[] = $data;
}
return $r;
}
public function getDropdown() {
// I suspect the top Level have a supervisor_id = 0
$data = $this->getChildsRecoursive(0,true);
// you can do a print_r($data) here to see if the results are correct
$r = "<select>";
foreach($data as $d) {
$r .= $this->getOptionsRecoursive($d);
}
$r .= "</select>";
return $r;
}
public function getOptionsRecoursive($data) {
$r = "<option>";
for($i=0;$i<$data['level'];$i++) {
$r .= " ";
}
$r .= $data['name'];
$r .= "</option>\n";
if(isset($data['childs'])) {
foreach($data['childs'] as $c) {
$r .= $this->getOptionsRecoursive($c);
}
}
return $r;
}
}
?>
Hope it helps to understand. (Please recognize that this will cause many queries depending on how big your tree is).
To Start you need to do
$tree = new tree();
echo $tree->getDropdown();

Recursive function to generate breadcrumbs

function createPath($id, $category_tbl, $path) {
$s = "SELECT * FROM ".$category_tbl." WHERE ID = $id";
$r = mysql_query($s);
$row = mysql_fetch_array($r);
if($row['PARENT_ID'] == 0) {
$path .=$row['TITLE'].'-';
}
else {
$path .='-'.$row['TITLE'];
createPath($row['PARENT_ID'],$category_tbl, $path);
}
return $path;
}
It is a recursive function that must generate breadcrumbs. I cannot get it to work properly, it only returns the last TITLE.
the sql table is something like ID, TITLE, PARENT_ID
a PARENT_ID = 0 means the category has no parent,
for any other PARENT_ID, go to that ID, get it's title and add it to the $path variable
I need help to make this work. Alternatives are also welcomed.
Try something like this:
function createPath($id, $category_tbl) {
$s = "SELECT * FROM ".$category_tbl." WHERE ID = $id";
$r = mysql_query($s);
$row = mysql_fetch_array($r);
if($row['PARENT_ID'] == 0) {
return $row['TITLE'];
} else {
return createPath($row['PARENT_ID'],$category_tbl).'-'.$row['TITLE'];
}
}
Looks like you either need to use the value returned by createPath or have $path passed by reference, &$path. One or the other, but not part of each.

Categories