showing columns from joined tables in CGridView - php

I joined some tables in model by CDbCriteria my code is something like this :
$crt = new CDbCriteria();
$crt->alias = 'so';
$crt->select = 'u.id, u.first_name, u.last_name';
$crt->join = " inner join " . Flow::model()->tableName() . " as fl on fl.id = so.flow_id";
$crt->join .= " inner join " . RoleUser::model()->tableName() . " as ru on ru.id = fl.receiver_role_user_id";
$crt->join .= " inner join " . User::model()->tableName() . " as u on ru.user_id= u.id";
$crt->compare('sms_outbox_group_id', $smsOutboxGroupId);
$crt->compare('fl.kind', Flow::KIND_SMS);
$crt->group = 'u.id';
$smsOutBox = new SmsOutbox();
return new CActiveDataProvider($smsOutBox, array(
'criteria' => $crt,
'sort' => array(
'defaultOrder' => 'so.id DESC',
)
));
how can I show my selected column in CGridView? is there any possible way to show first_name and last_name without defining relation in model?

I've found the solution using Sudhanshu Saxena answer. beside using aliases for first_name and last_name I've added two property to model with same names as aliases : receiverFirstName and receiverLastName. in this way my problem was solved and besides that it provide search functionality on this two property.
my final code is like this :
Model :
public $receiverFirstName;
public $receiverLastName;
creating criteria :
$crt = new CDbCriteria();
$crt->alias = 'so';
$crt->select = 'so.id,u.id as userId, u.first_name as receiverFirstName, u.last_name as receiverLastName, so.status';
$crt->join = " inner join " . Flow::model()->tableName() . " as fl on fl.id = so.flow_id";
$crt->join .= " inner join " . RoleUser::model()->tableName() . " as ru on ru.id = fl.receiver_role_user_id";
$crt->join .= " inner join " . User::model()->tableName() . " as u on ru.user_id= u.id";
$crt->compare('sms_outbox_group_id', $smsOutboxGroupId);
$crt->compare('u.first_name', $this->receiverFirstName, true);
$crt->compare('u.last_name', $this->receiverLastName, true);
$crt->compare('so.status', $this->status);
$crt->compare('fl.kind', Flow::KIND_SMS);
$crt->group = 'userId';
$crt->order = 'so.id';
return new CActiveDataProvider($this, array(
'criteria' => $crt,
));
and finally in CgridView I did this :
'columns' => array(
array(
'header' => Yii::t('app', 'Row'),
'value' => '$this->grid->dataProvider->pagination->currentPage * $this->grid->dataProvider->pagination->pageSize + ($row+1)',
),
array(
'name' => 'receiverFirstName',
'value' => '$data->receiverFirstName',
),
array(
'name' => 'receiverLastName',
'value' => '$data->receiverLastName',
),
array(
'name' => 'status',
'value' => 'SmsOutbox::getStatusTitle($data->status)',
'filter' => CHtml::listData(SmsOutbox::getStatusList(), 'id', 'title')
),
),

Use the alias and call it in CgridView like this
$crt->select = 'u.id, u.first_name as fname, u.last_name as lastname';
In your Grid call it.
array('name'=>'name' or 'header'=>'some header','value'=>'$data->fname')

Related

Cakephp AND constraint for array in query operation

I have a Table schedules that needs to be joined in my Query.
$joins[] = array(
'table' => 'schedules',
'alias' => 'Schedule',
'conditions' => array(
'Schedule.provider_id = Provider.id',
'Schedule.endtime > "' . date('Y-m-d H:i:s') . '"',
'Schedule.starttime' => $startTimes,
),
'type' => 'INNER'
);
$starttimesis an array consisting of DateTime Objects.
Providers can have multiple schedules and I want to get all providers, which match at least all starttimes from the $starttimesarray.
Thanks to ndm I got the solution. What I was missing was the group stetement:
$group = 'Provider.id HAVING COUNT(DISTINCT Schedule.id) = ' . count($startTimes);

How to give alias name to table in bonfire..?

I am using Ci-bonfire and I want to give alias name of table when I have join multiple table at that time it will give column ambiguous so how to give alias name of table
Here is my code example..
$select = array(
$this->table_name . '.*',
'bf_countries.name'
);
$join = array(
'bf_countries' => array(
'condition' => 'bf_countries.country_id = ' . $this->table_name . '.country_id',
'type' => 'left'
)
);
$order = array(
"sortby"=>$this->table_name.".".$this->key,
"order"=>"DESC"
);
$config = array(
"req_data" => $req_data,
"select"=>$select,
"join"=>$join,
"order"=>$order
);
$this->grid->initialize($config);
return $this->grid->get_result();
Suppose I want to give alias name of bf_countries table so what to do for that..?

How to Implement this Mysql query into Zend framework 1 using dbSelect

SELECT
CONCAT(us.user_id,' ', us.name),
UPPER(sc.so_number) Order_no ,
sh.upc UPC,re.label Error,
(SELECT count(*) FROM order_checker_scan scan WHERE scan.so_number =sh.so_number and scan.upc=sh.upc and scan.user_id!=0
and DATE_FORMAT(scan_time,'%Y-%m-%d') >= '2015-11-01' ) AS
prev_data,
(select CONCAT(u.user_id,' ', u.name) from users u,picklist_history p where u.user_id=p.user_id and
p.so_number=sh.so_number limit 1) as picker,
sh.item_key Times,
DATE_FORMAT(sc.date_started,'%b%d %Y %h:%i%p') datetime,sh.qty_required QTY
FROM
order_checker_short sh,
order_checker_header
sc,order_checker_short_reason re,
users us
WHERE sh.so_number=sc.so_number AND
sh.reason_id=re.reason_id AND
sc.created_by=us.user_id And
sc.created_by!=0 AND
DATE_FORMAT(date_started,'%Y-%m-%d') between '2015-11-16' and '2015-11-17' AND
sh.reason_id !=0 AND
sh.upc !=1
GROUP BY sc.so_number,sh.upc
ORDER BY sc.date_started DESC, sc.so_number DESC , sh.upc ASC
Please test the following:
// 1st subselect
$prevDataSelect = $db->select()
->from(array('scan' => 'order_checker_scan'), array('count(*)'))
->where('scan.so_number = sh.so_number')
->where('scan.upc = sh.upc')
->where('scan.user_id != 0')
->where("DATE_FORMAT(scan_time,'%Y-%m-%d') >= '2015-11-01'");
// 2nd subselect
$pickerSelect = $db->select()
->from(array('u' => 'users', 'p' => 'picklist_history'), array("CONCAT(u.user_id,' ', u.name)"))
->where('u.user_id = p.user_id')
->where('p.so_number = sh.so_number')
->limit(1);
// Main selection
$mainSelect = $db->select()
->from(
// tables
array(
'sh' => 'order_checker_short',
'sc' => 'order_checker_header',
're' => 'order_checker_short_reason',
'us' => 'users',
),
// columns
array(
'SomeName' => "CONCAT(us.user_id, ' ', us.name)",
'Order_no' => 'UPPER(sc.so_number)',
'UPC' => 'sh.upc',
'Error' => 're.label',
'prev_data' => new Zend_Db_Expr('(' . $prevDataSelect . ')'),
'picker' => new Zend_Db_Expr('(' . $pickerSelect . ')'),
'Times' => 'sh.item_key',
'datetime' => "DATE_FORMAT(sc.date_started,'%b%d %Y %h:%i%p')",
'QTY' => 'sh.qty_required',
)
)
// AND WHERE clauses
->where('sh.so_number = sc.so_number')
->where('sh.reason_id = re.reason_id')
->where('sc.created_by = us.user_id')
->where('sc.created_by != 0')
->where("DATE_FORMAT(date_started, '%Y-%m-%d') between '2015-11-16' and '2015-11-17'")
->where('sh.reason_id != 0')
->where('sh.upc != 1')
// GROUP BY clause
->group(array('sc.so_number', 'sh.upc'))
->order(array('sc.date_started DESC', 'sc.so_number DESC', 'sh.upc ASC'));
If doesn't work please tell me what's the output of $mainSelect->assemble()

How to run subqueries in cakephp

Cakephp 2.6
I have a Model, Temps, which has many tickets. In the index view of Temps I want to return for each record, the ticket with the date closest to the current date.
In mySQL it can be done as
'SELECT expiry_date FROM uploads WHERE expiry_date > CURDATE() ORDER BY expiry_date ASC LIMIT 1'
But I don't know how to run this as a sub query. My Current query to generate my results is as follows: (bearing in mind this has been configured for datatables) Tickets is an alias for the Upload Model
public function getAjaxIndexData($data) {
$tokens = explode(" ", $data['searchString']);
$conditions = array(
$this->alias . '.deleted' => false,
'OR' => array(
'CONCAT(' . $this->alias . '.first_name," ",' . $this->alias . '.last_name) LIKE' => '%' . implode(' ', $tokens) . '%',
),
$data['columnsFilter']
);
$fields = array(
'id',
'full_name',
'pps_number',
'mobile',
'email',
'start_date',
'time_served'
);
$order = array(
$data['orderField'] => $data['order']
);
$contain = array(
'LocalOffice.name',
);
$options = array(
'conditions' => $conditions,
'fields' => $fields,
'order' => $order,
'contain' => $contain,
'limit' => $data['limit'],
'offset' => $data['start']
);
$optionsNoFields = array(
'conditions' => $conditions,
'contain' => $contain,
);
$result['draw'] = $data['draw'];
$result['recordsTotal'] = $recordTotal = $this->find('count');
$result['recordsFiltered'] = $this->find('count', $optionsNoFields);
$result['data'] = $this->find('all', $options); //standard search
$result['data'] = $this->formatTable($result['data']);
return json_encode($result);
}
Within this query I would like to add a field that shows the nearest expiry date for each Temp.
How would I construct this?
Dynamically create a virtual field:
$this->virtualFields['nearest'] = '(SELECT expiry_date FROM uploads WHERE expiry_date > CURDATE() AND uploads.owner_id = '.$this->alias.'.ticket_id ORDER BY expiry_date ASC LIMIT 1')';
Then adjust your fields array
$fields = array(
'id',
'full_name',
'pps_number',
'mobile',
'email',
'start_date',
'time_served',
'nearest'
);
Also, the query could be rewritten as ("temp" needs to be replaced with the model alias)
SELECT MIN(expiry_date)
FROM uploads
WHERE expiry_date > CURDATE()
AND uploads.owner_id = temp.ticket_id;
Which means that a potentially better performing query would be to move that subquery out of the columns of the SELECT statement to a JOIN. For example:
SELECT *
FROM temp
LEFT JOIN (SELECT MIN(expiry_date) AS expiry,owner_id
FROM uploads
WHERE expiry_date > CURDATE())
GROUP BY owner_id) AS next_dates
ON next_dates.owner_id = temp.ticket_id;

CakePHP Retrieving data from multiple tables with select conditions

I am building an application using CakePHP and I am stuck on a problem retrieving data using a series of joins. In the simplified example below the join with the alias Delivery could have more than record and I want to bring back the record with a max value in a particular field in that table.
$inv_conditions = array( 'Invoice.invoice_date >=' => $DateFormatter->dateForDB($dateFrom),
'Invoice.invoice_date <=' => $DateFormatter->dateForDB($dateTo),
'Invoice.id >' => 385380 );
$join = array(array(
'table' => 'jobs',
'alias' => 'Jobs',
'type' => 'LEFT',
'conditions' => array('Invoice.job_id = Jobs.JOB_ID' )
),
array(
'table' => 'functional',
'alias' => 'Delivery',
'type' => 'LEFT'
'conditions'=> array('AND ' => array('Invoice.job_id = Delivery.JOB',
'Delivery.TYPE_STAGE = 1')
)
)
);
$invoices = $this->Invoice->find("all", array(
"fields" => array(
'Invoice.id',
'Invoice.job_id',
'Invoice.invoice_no',
'Invoice.consolidated_type',
'Invoice.customer_id_tbc',
'Invoice.invoice_date',
'Invoice.invoice_reference',
'Invoice.invoice_req',
'Jobs.PAYMENT_TYPE',
'Jobs.CUSTOMER',
'Jobs.MOST_RELEVANT_LINE',
'Delivery.DEPARTURE_DATE',
'Delivery.CNOR_CNEE_NAME',
'Delivery.TOWN_NAME',
),
"conditions" => $inv_conditions,
"joins" => $join
)
);
}
I can do this with SQL no problem as follows:
SELECT
jobs.JOB_ID,
jobs.CUSTOMER,
functional.JOB_LINE_ORDER,
functional.CNOR_CNEE_NAME,
functional.TOWN_NAME
FROM jobs JOIN functional ON
jobs.JOB_ID = 'M201409180267'
AND
functional.JOB = jobs.JOB_ID
AND
functional.TYPE_STAGE = 0
AND
functional.JOB_LINE_ORDER =
(SELECT MAX(JOB_LINE_ORDER) FROM functional
WHERE functional.JOB = 'M201409180267' AND functional.TYPE_STAGE = 0)
I have tried using the following to the conditions array:
'conditions' => array('AND ' =>
array( 'Invoice.job_id = Delivery.JOB',
'Delivery.TYPE_STAGE = 1'
'Delivery.JOB_LINE_ORDER = MAXIMUM(Delivery.JOB_LINE_ORDER)' )
)
This does bring back results but not the correct ones and the resulting SQL generated by Cake does have a select in the where clause. Is there a way of doing this when retrieving data in cake where the sql statement created will have a select in the where clause.
Any suggestions would be greatly appreciated.
Thanks
Bas
You need to use subquery to generate the select in the where clause. You can create a method in your model that does this and call it from your controller.
$subQuery = $db->buildStatement(
array(
'fields' => array(''),
'table' => $db->fullTableName($this),
'alias' => 'aliasName',
'limit' => null,
'offset' => null,
'joins' => array(),
'conditions' => $conditionsArray,
'order' => null,
'group' => null
),
$this
);
$subQuery = ' <<YOUR MAIN QUERY CONDITION (' . $subQuery . ') >>';
$subQueryExpression = $db->expression($subQuery);
$conditions[] = $subQueryExpression;
return $this->Model->find('list', compact('conditions'));

Categories