Codeigniter $query->result() loop to associative array - php

I'm having trouble getting this loop to return all of the rows that I know mysql is generating in this query. The objects in my javascript console are returning as I would like them to; however, I'm only getting the last row from each unique $row->student_id. I can tell that each unique row->student_id is being overwritten by the previous, but I'm not sure how else to do this logic.
This is part of a Codeigniter model. My controller is performing a json_encode function on this function, then I'm pulling this data into my view with jQuery $.ajax wired to a handlebars.js template. I'm aware that I could use ember for data bindings, but that is beyond my expertise at this time.
$query = $this->db->get();
if ($query->num_rows() > 0) {
$prev = null;
foreach ($query->result() as $row) {
if ($prev != $row->student_id) {
$data[$row->student_id] = array(
'first' => $row->last_name,
'last' => $row->first_name);
$data[$row->student_id]['dorc'] = array($row->debit_or_credit);
$prev = $row->student_id;
} else {
$data[$row->student_id]['dorc'][] += $row->debit_or_credit;
}
}
return $data;
} else {
return array();
}`

Your second if condition is not correct. You should replace it by this :
foreach ($query->result() as $row) {
if (!isset($data[$row->student_id])) { // Creates the row if not exists
$data[$row->student_id] = array(
'first' => $row->last_name,
'last' => $row->first_name);
}
if (!isset($data[$row->student_id]['dorc'])) { // Create the dorc key if not exists
$data[$row->student_id]['dorc'] = array($row->debit_or_credit);
} else { // if it exists, push the debit_or_credit row value
$data[$row->student_id]['dorc'][] = $row->debit_or_credit;
}
}

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.

Mongo db cursor count not working properly?

I have written following code in php and am using mongo db as database
$projection = array("broadcast_id" => 1,"studentList" => 1);
$query = array('broadcast_id'=> $broadcast_id);
$count = $this->collection->find($query)->count();
$cursor = $this->collection->find($query,$projection);
$result = array();
foreach($cursor as $row)
{
$idstring = trim($row["studentList"]);
$idstring = preg_replace('/\.$/', '', $idstring);
$idarray = explode('|', $idstring);
foreach($idarray as $studentId)
{
$this->StudentCollection = $this->db->studentTbl;
$StudentCursor= $this->StudentCollection->find(array("student_id" => $studentId));
if($StudentCursor->count() > 0)
{
foreach ($StudentCursor as $k => $srow) {
array_push($result, $srow);
}
}
else
{
array_push($result, array("datanotfound"=>1));
}
}
}
return json_encode($result);
After fetching "studentList" from broadcastTbl table and $idstring has "5042|5043|5044" values which are student ids of studentTbl. Now I am trying to fetch corresponding students details by splitting them one by one on the basis of "|". After that I am trying to push them in array $result.
It always displays $StudentCursor->count() as "1" and never enter in else block even if find() query fails to find record and then it displays output as [] i.e it always stay in if statement !!!
Please help me in tracking out what is wrong in the code and writting it efficiently!!!

set href link for each row in codeigniter table

Let's think that we have a db and a model function that retrieve a query result like this:
public function lista_ordini ($idcliente)
{
$this->db->select('ordini.num_fattura, misure.cosplay, ordini.data_richiesta,
ordini.anticipo, ordini.data_consegna,
ordini.saldo_totale, ordini.stato');
$this->db->join('misure', "ordini.id_cliente = $idcliente");
$query = $this->db->get('ordini');
if ($query && $query->num_rows() > 0){
return $query;
}else{
echo "errore generazione query ordini";
}
}
}//This is missing in your original, I'm not sure if it's a typo
Using codeigniter's table helper to generate a table:
<?php echo $this->table->generate($query); ?>
I can generate the table...and this is ok and works...
but, What if I want that every rows has a specific field (or the entire row if it's simpler) with href link? (this link will pass thorough GET method a variable for generate another query, but I don't figure out yet how that will work, this is just an hobby project)
I try this:
public function lista_ordini ($idcliente)
{
$this->db->select('ordini.num_fattura, misure.cosplay, ordini.data_richiesta,
ordini.anticipo, ordini.data_consegna, ordini.saldo_totale,
ordini.stato');
$this->db->join('misure', "ordini.id_cliente = $idcliente");
$query = $this->db->get('ordini');
if ($query && $query->num_rows() > 0) {
$rows = $query->row();
foreach ($rows as &$row) {
$row['num_fattura'] = ''.$row['num_fattura'].'';
}
return $rows;
}else{
echo "errore generazione query ordini";
}
}
I'm pretty sure that foreach loop is the way, but I can't understand how, cause I have so much errors that I cannot understand...to make this simply, my code doesn't work, and I think that I need some semantic advice.
thank you in advace
There is a logical problem in the foreach loop here:
foreach ($rows as &$row) {
$row['num_fattura'] = ''.$row['num_fattura'].'';
}
return $rows;
Each time the loop runs you are changing the value of $row, but when it completes you are returning $rows, which is unchanged.
Instead, you could edit the original array, using $k => $v to access the key and value inside the foreach loop:
foreach ($rows as $k => $v) {
$rows[$k]['num_fattura'] = ''.$rows[$k]['num_fattura'].'';
}
return $rows;
I know what you're trying to do, but I dont understand how you are trying to do it. Here's How I would do it:
//controller method
public function show_data()
{
$this->load->library('table');
$data['table_data'] = $this->some_model->get_the_data();
$this->load->view('some_view_that_will_contain_my_table', $data);
}
Now in my view, I'd generate the table:
<!doctype html>
...
<?if(!empty($table_data)):?>
<? $this->table->set_heading('column_1', 'column_2');?>
<?foreach($able_data as $table_row):
$this->table->add_row(
array('data'=>''.$table_row['column_1'].'.'),
array('data'=>''.$table_row['column_2'].'.'),
);
endforeach;?>
<?= $this->table->generate();?>
<?endif;?> //or display an empty table

PHP MySQL hierarchy data optimization

I have a table employees, which contains columns : employee_id, name, employee_manager_id.
employee_manager_id references to employee_id. It's a hierarchal data.
I have this output using PHP but couldn't achieve it using only one mySQL query. As of now, I need to process the data in PHP using recursive function so i can achieve this kind output.
Sample Array Output
0 => (
employee_id => 2,
name => Jerald,
employee_manager_id => 1,
depth => 1
),
1 => (
employee_id => 3,
name => Mark,
employee_manager_id => 2,
depth => 2
),
2 => (
employee_id => 6,
name => Cyrus,
employee_manager_id => 3,
depth => 3
),
3 => (
employee_id => 4,
name => Gerby,
employee_manager_id => 2,
depth => 2
)
As of now, this is my recursive function in PHP to achieve the output above.
function get_employees_by_hierarchy( $_employee_id = 0, $_depth = 0, $_org_array = array() ) {
if ( $this->org_depth < $_depth ) {
$this->org_depth = $_depth;
}
$_depth++;
$_query = "SELECT * FROM employees WHERE ";
if ( !$_employee_id ) {
$_query .= "employee_manager_id IS NULL OR employee_manager_id = 0";
}
else {
$_query .= "employee_manager_id = " . $this->dbh->quoteSmart( $_employee_id );
}
$_result = $this->query( $_query );
while ( $_row = $_result->fetchRow() ) {
$_row['depth'] = $_depth;
array_push( $_org_array, $_row );
$_org_array = $this->get_employees_by_hierarchy(
$_row['employee_id'],
$_depth,
$_org_array
);
}
return $_org_array;
}
My question is, is there anyway so I can achieve the array output i want using just one mysql query?
If not possible in mysql query, is there anymore to optimize in my current code?
Any help would greatly be appreciated.
Thanks
You can try a nested set a.k.a. celko tree but insert and delete is very expensive. There is also closures and path enumeration (materialized path) but I'm not an expert. MySql doesn't support recursive queries.
I don't think you can get the depth with your current model without doing any processing on the results, but you don't need to make multiple queries.
Assuming $employees is the list of employees indexed by employee_id, you could do something like this:
function set_employee_depth(&$employees, $id) {
if (!isset($employees[$id]['depth'])) {
$employee_manager_id = (int) $employees[$id]['employee_manager_id'];
if (!$employee_manager_id) {
$employees[$id]['depth'] = 0;
} elseif ($employee_manager_id !== $id) {
$employees[$id]['depth'] = 1 + set_employee_depth($employees, $employee_manager_id);
} else {
throw new \Exception('Employee cannot be its own manager!');
}
}
return $employees[$id]['depth'];
}
foreach ($employees as $id => $employee) {
set_employee_depth($employees, $id);
}
So, your table is composed of 3 columns (employee_id, name, employee_manager_id). employee_manager_id is a self reference to employee_id. You want to construct an array with all records, adding an extra field called depth which represents the distance of said employee to the "big boss", with only one query to the database. Is that correct? I'm also assuming that the database structure can't be changed.
If these assumptions are correct, this is a basic HIERARCHICAL/TREE data structure and thus, you have a couple of ways you can tackle this problem.
First Script
The first script runs the results array sequentially, finding the main node / trunk (the big boss) first and then adding it's children, then it's grandchildren and so on. Each time a node is "sorted", it will be removed from the cycle until no nodes are left. It assumes that:
There are no Orphan records (employees with invalid managers_ids)
There are no Circular References, either simple (A is manager of B and B is manager of A) or complex (*A manager of B, B manager of C and C manager of A)
Each path (from the main node to last node) can have an infinite number of nodes
$results are produced by running a simple query SELECT * FROM employees ORDER BY employee_manager_id
Code:
$finalArray = array();
$limit = count($results);
while (count($results) > 0) {
$results[0]['cnt'] = isset($results[0]['cnt']) ? $results[0]['cnt']++ : 0; // set num of times each element was already visited
if ($results[0]['cnt'] === $limit) { //prevent an infinite cycle
break;
}
$manId = $results[0]['manager_id'];
if ($manId === null) {
$results[0]['depth'] = 0;
} else if ( ($key = searchForId($manId, $finalArray)) !== null ) {
$results[0]['depth'] = $finalArray[$key]['depth'] + 1; //use the depth of parent to calculate its own
} else {
$results[] = $results[0]; //parent was not visited yet so we add it to the end of array
array_shift($results);
continue;
}
unset($results[0]['cnt']);
$finalArray[] = array_shift($results);
}
function searchForId($id, $array) {
foreach ($array as $key => $val) {
if ($val['id'] === $id) {
return $key;
}
}
return null;
}
This script is pretty straightforward. It only runs one query to the DB. In best case scenario, it will only traverse the array once. In worse case scenario, it will visit each element count(array) - 1, which can be slow with big arrays. However, since the results are pre-sorted, best case scenario will probably be more common.
Second Script
The second script builds an actual tree of elements. It's a bit more complex but achieves similar results. Also, the Depth is calculated dynamically.
class Employee {
public $id;
public $name;
public $manager;
public function __construct($id, $name, Employee $manager = null) {
$this->id = $id;
$this->name = $name;
$this->manager = $manager;
}
public function setManager(Employee $manager) {
$this->manager = $manager;
}
public function getDepth() {
if ($this->manager === null) {
return 0;
} else {
return $this->manager->getDepth() + 1;
}
}
}
$finalArray = array();
$paths = array();
foreach ($results as $r) {
$finalArray[(int) $r['id']] = new Employee((int)$r['id'], $r['name']);
if ($r['manager_id'] !== null) {
$paths[(int) $r['id']] = (int) $r['manager_id'];
}
}
foreach ($paths as $k => $v) {
if (isset($finalArray[$k]) && isset($finalArray[$v])) {
$finalArray[$k]->setManager($finalArray[$v]);
}
}
Here is a link for answer
Here is full code for making tree structure for hierarchy management using php and mysql.

What is wrong with this PHP code?

I have two database tables, one for allowances and one for deductions. I want to calculate net salaries.
I'm using CodeIgniter. Here's my current code:
function get_allowances($eid)
{
$this->db->from('allowances');
$this->db->where('eid',$eid);
$query = $this->db->get();
if($query->num_rows()==1)
{
return $query->row();
}
else
{
//Get empty base parent object, as $item_id is NOT an item
$salary_obj=new stdClass();
//Get all the fields from items table
$fields = $this->db->list_fields('allowances');
foreach ($fields as $field)
{
$salary_obj->$field='';
}
return $salary_obj;
}
}
function get_deductions($eid)
{
$this->db->from('deductions');
$this->db->where('eid',$eid);
$query = $this->db->get();
if($query->num_rows()==1)
{
return $query->row();
}
else
{
//Get empty base parent object, as $item_id is NOT an item
$salary_obj=new stdClass();
//Get all the fields from items table
$fields = $this->db->list_fields('deductions');
foreach ($fields as $field)
{
$salary_obj->$field='';
}
return $salary_obj;
}
}
and in controller,
function net_salary($eid)
{
$allownces[] = $this->Salary->get_allowances($eid);
$deductions[] = $this->Salary->get_deductions($eid);
return $net_salary = array_sum($allownces) - array_sum($deductions);
}
My net_salary() function gives me a result of 0. What am I doing wrong, and how can I fix it?
Your models with plural names are only going to return a single object.
so what you are ending up with is...
Array
(
[0] => allowance_object
)
and
Array
(
[0] => deduction_object
)
While we really need the schema of your database try this (and make same edits for deductions)...
function get_allowances($eid)
{
$this->db->from('allowances');
$this->db->where('eid',$eid);
$query = $this->db->get();
if($query->num_rows()==1)
{
return $query->row_array(); //<--- return an Array
}
else
{
// make an array instead of object
$salary_obj = array();
//Get all the fields from items table
$fields = $this->db->list_fields('allowances');
foreach ($fields as $field)
{
$salary_array[$field] = 0; //<---- add array keys and set to integer 0 instead of empty string.
}
return $salary_array;
}
}
then in your net_salary function
function net_salary($eid)
{
$allownce = $this->Salary->get_allowances($eid);
$deduction = $this->Salary->get_deductions($eid);
return array_sum($allownce) - array_sum($deduction);
}
Try something like this:
function get_values($eid, $table_name)
{
$this->db->where('eid',$eid);
$query = $this->db->get($table_name);
$salary_obj = $query->result();
$values = array();
foreach($salary_obj as $row){
$values[] = $row->value_column_name;
}
return $values;
}
where value_column_name is the name of the table column (filedname) where the desired value stands.
call in controller:
function net_salary($eid)
{
$allownces = $this->Salary->get_values($eid, 'allowances');
$deductions = $this->Salary->get_values($eid, 'deductions');
return $net_salary = array_sum($allownces) - array_sum($deductions);
}

Categories