Recursive PHP function gets only first values - php

I'm having an issue with below code. I'm trying for some time now, and I believe I must be blind and I do not see something obvious. Can you point at this obvious thing?
Function ought to get all categories and it's names. Takes IDs correctly, but names only for first category and first subcategory.
function collect($id, $current = null) {
global $db_1;
$s = "SELECT category.id as id, category_i18n.name as name from category,category_i18n WHERE category.parent_id= '$id' AND category.visible = '1' AND category_i18n.culture='en' AND category.id = category_i18n.id ORDER BY category.order_asc ASC";
$r = mysql_query($s, $db_1);
$row = mysql_fetch_array($r);
$children = array();
if (mysql_num_rows($r) > 0) {
while ($row) {
$children['name'] = $row['name'];
$children[$row['id']] = collect($row['id']);
}
}
else
{
$children['name'] = $row['name'];
}
return $children;
}
EDIT:
EDIT2:
After changes I'm getting array like this:
array(3) {
["name"]=>
string(9) "Cat"
["id"]=>
string(5) "10404"
["children"]=>
array(3) {
["name"]=>
string(10) "Subcat"
["id"]=>
string(5) "10410"
["children"]=>
bool(false)
}
}
I think it is not problem with mysql query, as in phpmyadmin it works and shows all data properly...

UPDATED :
It seems that you have only 1 level of subdirectory. Your function does this :
1) First it fetches the name and id of the given category.
2) It uses the obtained id to fetch the name of the subcategory which has parent_id = the previously fetched id.
3) Here comes the problem. Due to recursion it again calls collect() with the id of this subcategory. But there is no subcategory for this, so it returns null.
That is,
1st Parent (id1) -> Subcategory(id2) -> Subcategory(id2) and so on.
You can use this to get as many levels of categories as you want :
function collect($id, $current = null) {
global $db_1;
$s = "SELECT category.id as id, category_i18n.name as name from category,category_i18n WHERE category.parent_id= '$id' AND category.visible = '1' AND category_i18n.culture='en' AND category.id = category_i18n.id ORDER BY category.order_asc ASC";
$r = mysql_query($s, $db_1);
$temp = array();
if(mysql_num_rows($r) > 0)
{
while($row = mysql_fetch_array($r))
{
$temp[$row['id']]['name'] = $row['name'];
$temp[$row['id']]['children'] = collect($row['id']); //Get further children (Recursive)
if(!$temp[$row['id']]['children']) {continue;} // If FALSE is returned, means that this category has no sub categories. Move onto next one.
}
}
else {return FALSE;} //No rows present, return FALSE
return $temp;
}
This code is not tested. You will get an array in the following format
$parent[parent_id] -> [name]
-> [children] -> FALSE (if subdirectories are not present)
-> [children_id] #1 -> [name]
-> [children]
-> [children_id] #2 and so on.
UPDATE : you were getting only the last result, because I forgot one thing. The $temp[] array was getting overwritten every time in the loop.

Related

in php Foreach loop moves to the wrong key

I have the following array structure
jobs = {70811 ={....invoices = { A="A",...},...},...}
Then I have two nested loops. The outer nested loop seeks each job # in this case 70811. The inner loop then seeks each invoice listed for the job.
in each loop I query one of the tables
foreach ($this->p['jobs'] as $job => $value) {
$sql = 'select concat(sum(i.`AMOUNT`))as `amount`, ...
from `invoice` i
where i.`JOBID` = '.$job.'
group by i.`tracknum` = "'.$this->cTrackKey.'"';
$cmeJobEdits = 0;
if ($result = $db->query($sql))
{
if ($result->num_rows > 0)
{
$this->budget = mysqli_fetch_all( $result, $resulttype = MYSQLI_ASSOC );
$subTot = 0;
for ($i=0; $i<count($this->budget);$i++)
{
$subTot += $this->budget[$i]['amount'];
}
...
unset($i);
$xsql = 'update `cmejob` set `balance` = '.$this->budget[0]['balance'].',... where `jobid` = '.$job;
if (!$result = $db->query($xsql))
{
throw new Exception("Query to update budget failed!");
}else{
$cmeJobEdits++;
}
unset($xsql);
}
}else{
throw new Exception("Query to get billed amounts for this job failed! "`enter code here`);
}
unset($sql);
unset($value);
}//end loop updating cme jobs
My problem is this the outer query where the $job variable is not the next job # but the nested array key "invoices" as shown below.
As shown in the code I tried unsetting the query and key variables in the loops with no success.
select concat(sum(i.`AMOUNT`))as `amount`, ...
from `invoice` i
where i.`JOBID` = invoices //this is the value of the variable $job
group by i.`tracknum` = "'.$this->cTrackKey.'"';
Here is the var_dump($this->p['jobs'] of the values as you requested. Is this how you prefer seeing it
array(1) { [84528]=> array(6) { ["thisBudget"]=> string(4) "0.00" ["thisBilled"]=> string(9) "44,633.80" ["thisSum"]=> string(9) "28,003.00" ["thisBalance"]=> string(10) "-72,636.80" ["invoices"]=> array(1) { ["A"]=> string(1) "A" } ["DORMANT"]=> string(0) "" } }
The problem has been resolved.
As usual the error occurred in code not shown. The code above added an 'invoices' element to the $this->p['jobs'] array when it should have been added somewhere else.
now the loop works as described.

How do you clear Static variables in PHP?

I have created a function which is using recursion to find out childs of Given User. as shown below :
function recursionFunc($param) {
$q = "select cust_id,amount,position from testtab where parent_id = $param";
$res = mysql_query($q);
static $i = 0;
while ($row = mysql_fetch_assoc($res)) {
$i++;
recursionFunc($row['cust_id']);
}
return array('totalChild'=>$i);
}
There are two cases:
I want to call recursionFunc() for each user i am having
Recursion will be done in order to find childs of a user.
Now i want to call this function in while loop in order to fetch childs of all user i am having.
Since i am using static variable $i to store the value of childs.
Now when function will be called for the first user it returns correct value of childs but return wrong value in all other cases.
AS show Below
$cutData = "select cust_id from testtab";
$ress = mysql_query($cutData);
while ($raw = mysql_fetch_assoc($ress)) {
$response = recursionFunc($raw['cust_id']);
echo '<pre>'.$raw['cust_id'];
print_r($response);
echo '<br>';
}
Outputs
1Array ( [totalChild] => 7 ) 2Array ( [totalChild] => 10 ) 3Array ( [totalChild] => 12 )
It will be great if you can help me .
Thanks in advance.

Retrieve only one row of comment

I have a site developed in codeigniter where I want to retrieve comment of a specific tee.
I have a table tee like that:
- id
- user_id
- name
- created
- modified
And the table tee_comments like that:
- id
- user_id
- tee_id
- created
- modified
I have done this query:
$this->db->select('*,tee.id as id,tee.created as created, tee_comments.id as tee_comments_id, tee_comments.created as tee_comments_created, tee_comments.modified as tee_comments_modified');
$this->db->from('tee');
$this->db->join('tee_comments', 'tee_comments.tee_id = tee.id','left outer');
$this->db->order_by("tee.created", "desc");
$query = $this->db->get();
With this query I retrieve two rows of tee because I have two comments in that tee.
My goal is to retrieve only one row where inside there is an array of comment like:
tee{
id,
name,
created,
modified
comment{
[0]
id,
tee_id,
comment,
created,
modified
[1]
id,
tee_id,
comment,
created,
modified
}
}
I have tried into the join:
- left
- right
- left outer
- right outer
But doesn't solve the problem, is there a way to do that?
Thanks
I love CodeIgniter! I use it constantly! You have 2 really simple options here:
One way would be to use limit.
$this->db->select('*,tee.id as id,tee.created as created, tee_comments.id as tee_comments_id, tee_comments.created as tee_comments_created, tee_comments.modified as tee_comments_modified');
$this->db->join('tee_comments', 'tee_comments.tee_id = tee.id','left outer');
$this->db->order_by("tee.created", "desc");
$query = $this->db->limit(1)->get('tee');
Another way is to get first item in results Array
$query = $this->db->get();
$results = $query->result(); // gets return as an array
$row = $results[0]; // will be first row in results array
Keep in mind tho, $row will return as a object(stdClass) meaning you'll have to retrieve things from it like $row->column_name.
A handy little snippet I like to use after a call is below. It makes the row Object's Array's instead.
$results = $db->get('tee')->result(); // snippet comes after you have result array
// snippet here
foreach ($r as $k => $v) { $results[$k] = array(); foreach ($v as $kk => $vv) { $results[$k][$kk] = $vv != "NULL" ? trim($vv) : ""; } }
Use $this->db->limit(1) to retrieve a single record.
According to the accepted answer on this question, you may need to put the limit statement before the select:
$this->db->limit(1);
$this->db->select('*,tee.id as id,tee.created as created, tee_comments.id as tee_comments_id, tee_comments.created as tee_comments_created, tee_comments.modified as tee_comments_modified');
$this->db->from('tee');
Option one:
for ($i = 0; $i < count($records); $i++)
{
$data = $records[$i];
// work with date.
if($i == 1)
break;
}
Option two:
just assign the first row to var.
$row = $records['tee']['comment'][0];

Return value in foreach loop in CodeIgniter

I am having some trouble in returning values from model to controller Using CodeIgniter. I am passing two arrays from controller to model. I am checking whether both the arrays are not empty and looping them using foreach loop to fetch some values from database and returning the query to controller. Here's my current code
if (!empty($search_for_area) && !empty($search_for_requirement))
{ foreach($search_for_requirement as $search_value_1)
{
foreach($search_for_area as $search_value_2)
{
if($search_value_2 != null && $search_value_1 != null)
{
$nearbytution = $this->db->query('select name,area,contactno from tut_listing where area = "'.$search_value_2.'" and categoryfilter like "%'.$search_value_1.'%" and partner > "" group by name');
print_r($nearbytution->result());
}
}
}
//Line 1
}
print_r($nearbytution->result()); works fine and i am able to view the results. Where should i put return $nearbytution; so that i can get all the fetched values? I tried it in Line 1 but i was getting only values of last array value.
function returnStuff($search_for_area,$search_for_requirement) {
$arr_area = array();
$arr_filter = array();
if ( ! empty($search_for_area) and ! empty($search_for_requirement)) {
foreach($search_for_requirement as $search_value_1) {
foreach($search_for_area as $search_value_2) {
if($search_value_2 != null && $search_value_1 != null) {
$arr_area[] = $this->db->escape($search_value_2);
$arr_filter[] = $this->db->escape_like_str($search_value_1);
}
}
}
}
$str_area = 'NULL';
if ($arr_area)
$str_area = implode(', ', $arr_area);
$str_filter = "'^-$'";
if ($arr_filter)
$str_filter = "'(".implode('|', $arr_filter).")'";
$query = $this->db->query("
SELECT name, area, contactno
FROM tut_listing
WHERE area IN ({$str_area}) AND categoryfilter REGEXP {$str_filter} and partner > '' group by name
");
return $query->result();
}
Seriously, do consider this approach. You only need to bother the poor Mysql server with one call and you get all the data you want at the same time.
Apart from that, practice consistent style in your code. It will save both your time and your hair in the long run.
CodeIgniter escape()
MySQL REGEXP
Try this in the loop:
$nearbytution[] = $this->db->query('select name,area,contactno from tut_listing where area = "'.$search_value_2.'" and categoryfilter like "%'.$search_value_1.'%" and partner > "" group by name')->result();
return $nearbytution;may then be placed at your "Line 1". It will contain an array of query results.
Unless I misunderstand your question why don't you just store all the results in a big array and then return that array?
function returnStuff($search_for_area,$search_for_requirement) {
$data = array();
if (!empty($search_for_area) && !empty($search_for_requirement)) {
foreach($search_for_requirement as $search_value_1) {
foreach($search_for_area as $search_value_2) {
if($search_value_2 != null && $search_value_1 != null) {
$nearbytution = $this->db->query('select name,area,contactno from tut_listing where area = "'.$search_value_2.'" and categoryfilter like "%'.$search_value_1.'%" and partner > "" group by name');
$data[] =$nearbytution->result());
}
}
}
}
return $data;
}
Now $data will be an array of results, each containing the query results. If your result set has to be cleaned up (to remove duplicates for instance) you can just loop through it and do that cleanup.
What you could also maybe do is build a large SQL query in your foreach loops and then just do that one big query and return the results.

Retrieve database information and check results for certain conditions

I am looking for the most efficient method to do the following...
I have a table with three fields: id, eventid and movetype - and I have the following code to query the database for all entries with a matching eventid :
$get_results = mysql_query("SELECT * FROM table WHERE eventid='$eventid'");
while($row = mysql_fetch_array($get_results)){
// store results in array
$move_type_array = explode(" ", $row['movetype']);
}
Please note: movetype can only be three values: Internal, Outgoing, Incoming
Using a set of dummy data, var_dump($move_type_array) could output:
array(1) { [0]=> string(8) "Internal" } array(1) { [0]=> string(8) "Internal" }
Another example of an output would be:
array(1) { [0]=> string(8) "Internal" } array(1) { [0]=> string(8) "Incoming" } array(1) { [0]=> string(8) "Outgoing" }
I then need to check the output to see if the following conditions are met:
Does the array contain Internal twice?
If the array only contains Internal once, then does the array also contain Incoming and Outgoing?
If either of the conditions are met then a message should be displayed telling them which condition has been met, otherwise a message should tell them that the conditions have not been met.
I have tried using a number of PHP functions such as in_array(), and also tried storing the data in a string and using preg_match() however I was unsuccessful in both methods.
Try this:
$result = mysql_query("
SELECT SUM(IF(movetype = 'Internal', 1, 0)) AS internal,
SUM(IF(movetype = 'Outgoing', 1, 0)) AS outgoing,
SUM(IF(movetype = 'Incoming', 1, 0)) AS incoming
FROM table
WHERE eventid = $eventid
GROUP BY eventid
");
$count = mysql_fetch_array($result);
if ($count['internal'] >= 2 || ($count['internal'] == 1
&& $count['outgoing'] >= 1
&& $count['incoming'] >= 1)) {
echo 'Yes';
} else {
echo 'No';
}
// 1. Don't use '*' - fetch only required fields!
// 2. Don't use mysql_* functions - they are obsolete! Use PDO or MySQLi instead.
$get_results = mysql_query("SELECT `movetype` FROM table WHERE eventid='$eventid'");
while($row = mysql_fetch_array($get_results)){
// Count the values
$arr = array_count_values(explode(" ", $row['movetype']));
// Check them here
if(isset($arr['Internal'])) {
if($arr['Internal'] === 2)
echo ' Internal: 2'.PHP_EOL;
else if($arr['Internal'] === 1
&& isset($arr['Incoming'])
&& isset($arr['Outgoing']))
echo ' Internal: 1, Incoming and Outgoing'.PHP_EOL;
}
}

Categories