cakephp sort link not working - cakephp

Can't make sort links work. (concrete or virtual fields).
Vitual fields for my sum() field on this action:
$this->Qca->virtualFields['comps'] = 'Sum(CASE WHEN Qca.qca_tipcode = 1 THEN 1 END)';
$this->Qca->virtualFields['production'] = 'Sum(qca_end - qca_start)';
$this->Qca->virtualFields['idle'] = 'Sum(Qca.qca_durend)';
My find(), works fine:
$hoursvalues = $this->Qca->find('all', array('conditions' => $conditions,
'fields' => array('Qca.dir_id', 'Qca.name', 'Sum(CASE WHEN Qca.qca_tipcode = 1 THEN 1 END) AS Qca__comps', 'Sum(qca_end - qca_start) as Qca__production', 'Sum(Qca.qca_durend) as Qca__idle'),
'group' => array('Qca.dir_id')
)
);
and then:
$this->paginate('Qca' );
$this->set('hoursvalues', $hoursvalues);
What extra settings does $this->paginate('Qca' ); needs? Please note I have all data I need via find().
What is it I'm missing that sorting does not work for either concrete or virtual fields?
Thansk a lot!
Carlos

Part of your problem is the following:
$this->paginate('Qca');
$this->set('hoursvalues', $hoursvalues);
$this->paginate() returns an array with sorted values. What you need to do is specify your extra settings in $this->paginate array and then
$this->set('hoursvalues', $this->paginate('Qca'));
For your other fields, making them virtualFields will make them easier to work with.

Related

How to put where conditions with group by in cakephp find all query

I have created sql query which is working fine.
But i want to convert this sql query in cakephp format.
I try to convert this query in cakephp but
i am not understanding how to apply where conditions with group by clause.
And i only need to select this column u_data.lane_id AS LaneId, origin_city.pcode AS origin_pcode, dest_city.pcode AS dest_pcode....
not all columns from table.
plz help me to do this.
$options['conditions'] = array(
'CustomerRoute.portfolio_id' => '".$_SESSION["portfolioid"]."'
);
$content = $this->Customer->find('all', $options);
You simply need to define "group" and "fields" within $options-
Instead of $_SESSION, you should stick to the convention and use $this->Session->read instead.
//Eg: $_SESSION["portfolioid"] can be replaced with $this->Session->read("portfolioid")
$options['conditions'] = array(
"CustomerRoute.portfolio_id" => $this->Session->read("portfolioid"),
"u_data.supplier_id" => $this->Session->read("supplierid")
);
$options['fields'] = array(
"u_data.lane_id AS LaneId",
"origin_city.pcode AS origin_pcode",
"dest_city.pcode AS dest_pcode"
); // Add this
$options['group'] = array('CustomerRoute.id'); // Add this
$content = $this->Customer->find('all', $options);
This should give you what you're looking for.
Peace! xD

Cakephp value from array

I've read many similar topics here but not one helps me with problem.
i'm trying to get sections_id value from query in controller.
$query_id = "SELECT sections_id FROM sections WHERE name='".$table_name."'";
debug($id = $this->Info->query($query_id)); die();
there is debug result
array(
(int) 0 => array(
'sections' => array(
'sections_id' => '14'
)
)
)
and i tried in controller get value of id typing $id['sections']['sections_id'], or
$id['sections_id'] and many other types, nothing works. Do you have any idea ?
use $id[0]['sections']['sections_id'] to access it
For one result use
$data[0]['sections']['sections_id']
If query returns more than one result the use below code:
foreach($id as $data){
echo $data['sections']['sections_id']
}
Look for array index's carefully! Iinjoy

cakephp combine find() queries

I am still new to Cakephp I have 3 find queries to the same model and I have tried to combine them to make one. Finding it hard with the cake way of accessing the data. Especial that they have different find condition. Maybe it cant be done.
Cakephp version 2.3.5
// Count Total Members
$totalMemebers = $this->Member->find('count');
$this->set('totalMemebers', $totalMemebers);
// SUM total points gained for the last 7 days (positive values)
$this->Member->Point->virtualFields['gainedTotal'] = 'SUM(Point.points)';
$gainedTotal = $this->Member->Point->find('all', array(
'recursive'=> -1,
'fields' => array('gainedTotal'),
'conditions'=>array(
'Point.points >'=>0,
'Point.date >' => date('Y-m-d', strtotime("-1 weeks")))
)
);
$this->set('gainedTotal', $gainedTotal);
// SUM total points redeemed for the last 7 days (negative values)
$this->Member->Point->virtualFields['redeemedTotal'] = 'SUM(Point.points)';
$redeemedTotal = $this->Member->Point->find('all', array(
'recursive'=> -1,
'fields' => array('redeemedTotal'),
'conditions'=>array(
'Point.points <'=>0),
'Point.date >' => date('Y-m-d', strtotime("-1 weeks"))
)
);
$this->set('redeemedTotal', $redeemedTotal);
Because all queries use different conditions, it will not be possible to combine them to a single query. This is not a limitation of CakePHP, using regular SQL will not allow you to do so either, unless you're going to use sub queries or some calculated fields (SELECT CASE WHEN points > 0 AND date > .... THEN points ELSE 0 END CASE AS gainedPoint) but this will offer no benefits (performance wise)
Optimizations
To optimise (and clean up) your code, there are some improvements possible;
First of all, to get the value of a single field, you may use Model::field(). This will return just the plain value of a field, not an array containing the value.
For example:
$this->Member->Point->virtualFields['gainedTotal'] = 'SUM(Point.points)';
$gainedTotal = $this->Member->Point->field('gainedTotal', array(
'Point.points >'=>0,
'Point.date >' => date('Y-m-d', strtotime("-1 weeks"))
));
$this->set('gainedTotal', $gainedTotal);
Move data-related code to your model
This is something you should do in general. Move those queries to your Models. This will make your code cleaner and better to maintain. Also, your queries will be easier to re-use and finally, you will be able to Unit-test the queries.
class Point extends AppModel
{
// general stuff/properties here
/**
* Returns the SUM total points gained for
* the last 7 days (positive values)
*
* #return int Gained total for all members
*/
public function gainedTotal()
{
this->virtualFields['gainedTotal'] = 'SUM(points)';
$gainedTotal = $this->field('gainedTotal', array(
'points >'=>0,
'date >' => date('Y-m-d', strtotime("-1 weeks"))
));
// remove the virtualField to prevent it being used
// in subsequent queries
unset($this->virtualFields['gainedTotal']);
return (int)$gainedTotal;
}
}
And, inside your Controller, simply do this:
$this->set('gainedTotal', $this->Member->Point->gainedTotal());
This will clearly reduce the amount of code inside your Controller ('lean controllers, fat models'), which is always good practice.
Add relevant indexes to your database
If performance is important, you can massively improve the performance of these queries by adding the right indexes to your database, especially when calculating totals for a large number of records.
Describing this in detail is beyond the scope of this question, but here are some pointers; How MySQL uses indexes and CREATE INDEX SYNTAX

List with order and virtualfield

I'm having a strange thing in cakephp. So I try to explain it first.
I'm having:
two tables (staff and staffgroups)
a groupleader per group which is a staff
a virtual field, which CONCATs first and last name
the whish to order the list by lastname
Staff/model
public $virtualFields = array(
[...] ,
'fullnameForList' => 'CONCAT(Staff.lastname, ", ", Staff.firstname)',
[...]
function in Staffgroup/controller
public function getGroupLeaderListArray(){
$this->loadModel('Staff');
$loc_list = $this->Staff->find("list",
array("fields" => array("id", 'fullnameForList')),
array("order" => array("Staff.lastname ASC" ))
);
$this->set('GroupLeaderList',$loc_list);
}
outputs of the list
When I'm having the function getGroupLeaderListArray as it is above, i get the content of the virtualfield fullnameForList, but its not in order. eg. Lastname, Firstname
When I'm putting the array order before fields, it is shown in order but the wrong field. eg. Firstname Lastname
how do I get the list with the virtual field and correct order. I don't know further and I'm gaining weight and loosing hairs because of this problem. help apreciated big time!
cheers endo
You are using invalid array structures here. you need to pay attention on how arrays are working in cake. One array with named keys (you have multiple arrays here) as second param for find(), for example.
find($type, $options);
So its:
$locList = $this->Staff->find("list",
array(
'fields' => array('id', 'fullnameForList'),
'order' => array('Staff.lastname ASC')
)
);

Using DISTINCT in a CakePHP find function

I am writing a CakePHP 1.2 app. I have a list of people that I want the user to be able to filter on different fields. For each filterable field, I have a drop down list. Choose the filter combination, click filter, and the page shows only the records that match.
In people_controller, I have this bit of code:
$first_names = $this->Person->find('list', array(
'fields'=>'first_name',
'order'=>'Person.first_name ASC',
'conditions'=> array('Person.status'=>'1')
));
$this->set('first_names', $first_names);
(Status = 1 because I am using a soft delete.)
That creates an ordered list of all first_names. But duplicates are in there.
Digging around in the Cookbook, I found an example using the DISTINCT keyword and modified my code to use it.
$first_names = $this->Person->find('list', array(
'fields'=>'DISTINCT first_name',
'order'=>'Person.first_name ASC',
'conditions'=> array('Person.status'=>'1')
));
This gives me an SQL error like this:
Query: SELECT `Person`.`id`, DISTINCT `Person`.` first_name` FROM `people` AS `Person` WHERE `Person`.`status` = 1 ORDER BY `Person`.`first_name` ASC
The problem is obvious. The framework is adding Person.id to the query. I suspect this comes from using 'list'.
I will use the selected filter to create an SQL statement when the filter button is clicked. I don't need the is field, but can't get rid of it.
Thank you,
Frank Luke
Try to use 'group by', it works perfectry:
$first_names = $this->Person->find('list', array(
'fields'=>'first_name',
'order'=>'Person.first_name ASC',
'conditions'=> array('Person.status'=>'1'),
'group' => 'first_name'));
You're right, it seems that you cannot use DISTINCT with list. Since you don't need id but only the names, you can use find all like above and then $first_names = Set::extract($first_names, '/Person/first_name');. That will give you a array with distinct first names.
Here's how I did it in CakePHP 3.x:
$query = $this->MyTables->find('all');
$result = $query->distinct()->toArray();
You can try this.
Here this takes Person id as key, so there is no chance for duplicate entries.
$first_names = $this->Person->find('list', array(
'fields' => array('id','first_name'),
'conditions' => array('Person.status' => '1'),
));
$this->set('first_names', $first_names);
Using SQL grouping will also produce a distinct list. Not sure of the negative consequences if any, but it seems to work fine for me.
$first_names = $this->Person->find('list', array(
'fields' => 'first_name',
'order' => 'first_name',
'group' => 'first_name',
'conditions' => array('Person.status' => '1'),
));
$this->set('first_names', $first_names);
I know it is a question for CakePHP 1.2, but I was searching for that too with CakePHP version 3. And in this version there is a method to form the Query into a distinct one:
$first_names = $this->Persons->find(
'list',
[
'fields'=> ['name']
]
)
->distinct();
;
This will generate a sql query like this:
SELECT DISTINCT Persons.name AS `Persons__name` FROM persons Persons
But the distinct method is a bit mightier than just inserting DISTINCT in the query.
If you want to just distinct the result on one field, so just throwing away a row with a duplicated name, you can also use the distinct method with an array of the fields as parameter:
$first_names = $this->Persons->find(
'list',
[
'fields'=> ['id', 'name'] //it also works if the field isn't in the selection
]
)
->distinct(['name']); //when you use more tables in the query, use: 'Persons.name'
;
This will general a sql query like this (for sure it is a group query):
SELECT DISTINCT
Persons.id AS `Persons__id`, Persons.name AS `Persons__name`
FROM persons Persons
GROUP BY name #respectively Persons.name
Hope I will help some for CakePHP 3. :)
Yes the problem is that you are using a listing which designed for a id / value output. You probably will have to do a find('all') and then build the list yourself.
Yes I also tried to fetch unique results with 'list' but its not working. Then I fixed the problem by using 'all'.
In the example now on the book for version 2 it states the following:
public function some_function() {
// ...
$justusernames = $this->Article->User->find('list', array(
'fields' => array('User.username')
));
$usernameMap = $this->Article->User->find('list', array(
'fields' => array('User.username', 'User.first_name')
));
$usernameGroups = $this->Article->User->find('list', array(
'fields' => array('User.username', 'User.first_name', 'User.group')
));
// ...
}
With the above code example, the resultant vars would look something like this:
$justusernames = Array
(
//[id] => 'username',
[213] => 'AD7six',
[25] => '_psychic_',
[1] => 'PHPNut',
[2] => 'gwoo',
[400] => 'jperras',
)
$usernameMap = Array
(
//[username] => 'firstname',
['AD7six'] => 'Andy',
['_psychic_'] => 'John',
['PHPNut'] => 'Larry',
['gwoo'] => 'Gwoo',
['jperras'] => 'Joël',
)
$usernameGroups = Array
(
['User'] => Array
(
['PHPNut'] => 'Larry',
['gwoo'] => 'Gwoo',
)
['Admin'] => Array
(
['_psychic_'] => 'John',
['AD7six'] => 'Andy',
['jperras'] => 'Joël',
)
)
You have to plan your query in a slightly different way and plan your database to accommodate a list find.
In some cases, you wish to group by using some key, but you want unique element within the results.
For example, you have a calendar application with two types of events. One event on day 1rst and the other one on the 2nd day of month 1. And you want to show or rather count all the events, grouped by day and by type.
If you use only DISTINCT, it is quite difficult. The simplest solution is to group twice:
$this->Events->virtualFields['count'] = 'COUNT(*)';
$acts = $this->Activity->find('all',array(
'group' => array('DAY(Event.start)','EventType.id'),
));
Just group by the fields that you want to get distinct.. or use Set::extract() and then array_unique()
In 2.7-RC version, this is working
$this->Model1->find('list', array(
'fields' => array('Model1.field1', Model1.field1')
));

Resources