group after order - cakephp

In cakephp 2 I want to group table after descending order
always returned the first record of table
but I want returned last record by ordering
my data, code and result in here:
My data in table:
Code in controller:
$books = $this->Book->find('all', array(
'order' => array('age' => 'DESC'),
'group' => 'name'
));
print_r($books);
Result after the code above:
Array
(
[0] => Array
(
[Book] => Array
(
[id] => 1
[name] => ramin
[family] => zardoshti
[age] => 32
[city] => semnan
)
)
[1] => Array
(
[Book] => Array
(
[id] => 2
[name] => esmaeil
[family] => seydi
[age] => 30
[city] => semnan
)
)
)
But I want this result:
Array
(
[0] => Array
(
[Book] => Array
(
[id] => 1
[name] => ramin
[family] => zardoshti
[age] => 42
[city] => tehran
)
)
[1] => Array
(
[Book] => Array
(
[id] => 2
[name] => esmaeil
[family] => seydi
[age] => 30
[city] => semnan
)
)
)

Add a virtual field on the fly to your Book model
$this->Book->virtualFields = array(
'max_age' => sprintf('max(%s.age)', $this->Book->alias)
);
$books = $this->Book->find('all', array(
'order' => array('age' => 'DESC'),
'group' => 'name'
));
print_r($books);
The virtual field will help to get the rows with the maximum age value.
Your SQL query will look like :
SELECT
`Book`.`id`, `Book`.`name`, `Book`.`family`, `Book`.`age`,
`Book`.`city`, (max(`Book`.`age`)) AS `Book__max_age`
FROM
`test`.`books` AS `Book`
WHERE
1 = 1
GROUP BY
name
ORDER BY
`age` DESC

Related

Cakephp: Contain Behavior, conditions on array of array

I have a problem with contain behavior conditions and empty array.
There is part of code:
$menusTopUser = $this->Menu->find('all', array(
'contain' => array('TemplateRegion', 'Language', 'Item', 'MenusUserGroup' => array('conditions' => array('MenusUserGroup.user_group_id ' => $this->Auth->user('UserGroup.id')))
),
'conditions' => array(
'TemplateRegion.alias' => 'menu_top_user',
'Menu.active' => 1,
'Language.ISO-639-2' => $this->Session->read('Config.frontendLanguage'),
),
'fields' => array('Menu.title', 'Item.slug', 'Menu.url', 'Menu.target', 'Language.ISO-639-2'),
'order' => array('Menu.lft'),
'recursive' => 0));
$this->set(compact('menusTopUser'));
My associations look like:
Menu
hasMany: MenusUserGroup
MenusUserGroup
belongsTo: Menu, UserGroup
After executing the find, I have the next array where there are many MenusUserGroup empty. How make to filter only the record with 'MenusUserGroup.user_group_id ' => $this->Auth->user('UserGroup.id')?
Array(
[0] => Array
(
[Menu] => Array
(
[title] => Offerte e modulistica promoter
[url] =>
[target] => _self
[id] => 11
)
[Item] => Array
(
[slug] => offerte-e-modulistica-promoter
[id] => 36
)
[Language] => Array
(
[ISO-639-2] => ita
[id] => 1
)
[TemplateRegion] => Array
(
[id] => 10
)
[MenusUserGroup] => Array
(
)
)
[1] => Array
(
[Menu] => Array
(
[title] => Offerte e modulistica agenti
[url] =>
[target] => _self
[id] => 10
)
[Item] => Array
(
[slug] => offerte-modulistica
[id] => 29
)
[Language] => Array
(
[ISO-639-2] => ita
[id] => 1
)
[TemplateRegion] => Array
(
[id] => 10
)
[MenusUserGroup] => Array
(
[0] => Array
(
[id] => 7
[menu_id] => 10
[user_group_id] => 5
)
)
)
[2] => Array
(
[Menu] => Array
(
[title] => Gestione contratti
[url] =>
[target] => _self
[id] => 13
)
[Item] => Array
(
[slug] =>
[id] =>
)
[Language] => Array
(
[ISO-639-2] => ita
[id] => 1
)
[TemplateRegion] => Array
(
[id] => 10
)
[MenusUserGroup] => Array
(
[0] => Array
(
[id] => 10
[menu_id] => 13
[user_group_id] => 5
)
)
)
Use a join.
$menusTopUser = $this->Menu->find('all', array(
// join statement
'joins' => array(
array(
'table' => 'menus_user_groups',
'alias' => 'MenuUserGroupJoin',
'type' => 'INNER',
'conditions' => array(
'MenuUserGroupJoin.menu_id = Menu.id',
// condition
'MenuUserGroupJoin.user_group_id = ' . $this->Auth->user('UserGroup.id'),
),
),
),
'contain' => array('TemplateRegion', 'Language', 'Item', 'MenusUserGroup'),
'conditions' => array(
'TemplateRegion.alias' => 'menu_top_user',
'Menu.active' => 1,
'Language.ISO-639-2' => $this->Session->read('Config.frontendLanguage'),
),
'fields' => array('Menu.title', 'Item.slug', 'Menu.url', 'Menu.target', 'Language.ISO-639-2'),
'order' => array('Menu.lft'),
'recursive' => 0));

group is not working in CakePHP

I am running following query in CakePHP:
$options = array('conditions' => array('Patient.' . $this->Patient->primaryKey => $id),array('recursive'=>2,'group'=>array('group_id')));
$this->set('patient', $this->Patient->PatientTest->find('all', $options));
But my group is not working as needed. It gives me output as follows:
Array
(
[0] => Array
(
[PatientTest] => Array
(
[patient_id] => 2
[test_id] => 1
[date] => 2014-03-27 17:44:17
[result] => 55
[group_id] => 1
)
[Patient] => Array
(
[id] => 2
[name] => Test Patient
[age] => 44
[gender] => 0
[email] => emailid#gmail.com
[contact] => 789654123
[date] => 0000-00-00 00:00:00
)
[Test] => Array
(
[id] => 1
[name] => Hb
[group_id] => 1
[normal] => 12 - 16 gma%
)
[Group] => Array
(
[id] => 1
[name] => Haematology
)
)
[1] => Array
(
[PatientTest] => Array
(
[patient_id] => 2
[test_id] => 2
[date] => 2014-03-27 17:44:17
[result] => 55
[group_id] => 1
)
[Patient] => Array
(
[id] => 2
[name] => Test Patient
[age] => 44
[gender] => 0
[email] => emailid#gmail.com
[contact] => 789654123
[date] => 0000-00-00 00:00:00
)
[Test] => Array
(
[id] => 2
[name] => PCV
[group_id] => 1
[normal] => 35-50%
)
[Group] => Array
(
[id] => 1
[name] => Haematology
)
)
)
I need them group by either group_id or by Group.id.
I am unable to find why it is not grouping.
not
$options = array
(
'conditions' => array
(
'Patient.' . $this->Patient->primaryKey => $id
),
array(
'recursive'=>2,
'group'=>array('group_id')
)
);
but
$options = array
(
'conditions' => array
(
'Patient.' . $this->Patient->primaryKey => $id
),
'recursive'=>2,
'group'=>array('group_id')
);
recursive, conditions and group are at the same level
Simple and sweet code :
$groupBy = 'Patient.group_id';
$options = array (
'conditions' => array
(
'Patient.' . $this->Patient->primaryKey => $id
),
'group'=>array($groupBy)
);

Cakephp Model Assosiation Joins

well, in my cakephp project, i have 6 models, they are {User,Property,Category,Status,Comments,Attachable}
Property Model : $belongsTo = {User,Category,Status} . AND $hasMany = {Comment,Attachable} ..
Properties Controller Index Method ..
public function index() {
$this->Property->recursive = 0;
$this->set('properties', $this->paginate());
$properties= $this->paginate();
//pr($properties);
//exit;
}
which outputs :
Array
(
[0] => Array
(
[Property] => Array
(
[id] => 1
[user_id] => 1
[category_id] => 1
)
[User] => Array
(
[id] => 1
[name] => zals
[username] => admin
[userLevel] => 1
)
[Category] => Array
(
[id] => 1
[name] => villa
[property_count] => 0
)
[Status] => Array
(
[id] => 1
[name] => New
[property_count] => 0
)
)
[1] => Array
(
[Property] => Array
(
[id] => 2
[user_id] => 1
[phone] => 78666
)
[User] => Array
(
[id] => 1
[name] => zals
[username] => admin
)
[Category] => Array
(
[id] => 1
[name] => villa
[description] => villas are iby a wealthy person.
[property_count] => 0
)
[Status] => Array
(
[id] => 1
[name] => New
[description] => New Property
[property_count] => 0
)
)
[2] => Array
(
[Property] => Array
(
[id] => 3
[user_id] => 1
[category_id] => 1
)
[User] => Array
(
[id] => 1
[name] => zals
[username] => admin
[email] => admin#realty.com
[userLevel] => 1
)
[Category] => Array
(
[id] => 1
[name] => villa
[property_count] => 0
)
[Status] => Array
(
[id] => 1
[name] => New
[property_count] => 0
)
)
)
Well the above method retrieves data only from the models in $belongsTo variable. What I want is to combine the related Comments and Attachable Models with the same
query. This can be manually queried with LEFT JOIN to comments and attachable MODEL.
this is what the query looks like
function index() {
$properties = $this->Property->query("SELECT `Property`.`id`, `Property`.`user_id`, `Property`.`category_id`, `Property`.`status_id`, `Property`.`state_id`, `User`.`id`, `User`.`name`, `User`.`username`,`Category`.`id`, `Category`.`name`, `Category`.`description`, `Status`.`name`, `Status`.`description``Comment`.`id`,`Comment`.`name`,`Comment`.`comment`,`Attachment`.`id`,`Attachment`.`AttachmentName` FROM `properties` AS `Property`
LEFT JOIN `users` AS `User` ON (`Property`.`user_id` = `User`.`id`)
LEFT JOIN `categories` AS `Category` ON (`Property`.`category_id` = `Category`.`id`)
LEFT JOIN `statuses` AS `Status` ON (`Property`.`status_id` = `Status`.`id`)
LEFT JOIN `cities` AS `City` ON (`Property`.`city_id` = `City`.`id`)
LEFT JOIN `comments` AS `Comment` ON (`Property`.`id` = `Comment`.`id`)
LEFT JOIN `attachments` AS `Attachment` ON (`Property`.`id` = `Attachment`.`id`) WHERE 1 = 1 LIMIT 20");
//pr($properties);
//exit;
$this->set('properties',$properties);
}
which outputs :
Array
(
[0] => Array
(
[Property] => Array
(
[id] => 1
[user_id] => 1
[category_id] => 1
[status_id] => 1
)
[User] => Array
(
[id] => 1
[name] => za
[username] => admin
)
[Category] => Array
(
[id] => 1
[name] => villa
[description] => villa by a wealthy person.
)
[Status] => Array
(
[name] => New
)
[Comment] => Array
(
[id] => 1
[name] => A
[comment] => hello
)
[Attachment] => Array
(
[id] => 1
[AttachmentName] => 1342009083_4c2380.jpg
)
)
[1] => Array
(
[Property] => Array
(
[id] => 2
[user_id] => 1
[category_id] => 1
[status_id] => 1
)
[User] => Array
(
[id] => 1
[name] => zals
[username] => admin
)
[Category] => Array
(
[id] => 1
[name] => villa
[description] => villas a
)
[Status] => Array
(
[name] => New
)
[Comment] => Array
(
[id] => 2
[name] => asdasd
[comment] => asdasdas
)
[Attachment] => Array
(
[id] => 2
[AttachmentName] => 92f2e3c067d731a3823762.jpg
)
)
)
I am sure the latter way is not the right way to do it. Or
Suppose I used the cakephp's default index method in controller, And in VIEW i can do nested foreach loops inside the main foreach loop .. i .e
<?php foreach ($properties as $property) { ?>
$id = $property['Property']['id'];
$comments = ..... //here to query for the associated comments passing the id value ..
?>
can this be sorted out this way ? or how ? please guide .. thanks ..
Two things:
You can probably solve your problem by using the Containable behaviour. It's very flexible and can be used with pagination.
Doing an inner join on one-to-many relation is probably not a good idea.

Deep association relating to top-level model?

I have the following models:
Kin, which you can think of as an animal--a pet.
Species hasAndBelongsToMany Kin
GrowthStage hasAndBelongsToMany Species
Kin hasAndBelongsToMany GrowthStage
and KinGrowthStage, which defines the relationship between a kin and its growth stages (it contains its related images and such for the kin at that growth stage).
So in my controller I'm trying to get the following array to come out the other end. In this scenario the Species => GrowthStage => KinGrowthStages are related to the Kin id:
Array
(
[Kin] => Array
(
[id] => 4
[name] => Hobbes
[generation] => 1
[current_growth_stage_id] => 4
[species_id] => 1
)
[Species] => Array
(
[id] => 1
[name] => Tiger
[GrowthStage] => Array
(
[0] => Array
(
[id] => 5
[name] => cub
[order] => 1
[KinGrowthStage] => Array
(
[0] => Array
(
[id] => 1
[growth_stage_id] => 1
[kin_id] => 4
[image] => /img/hobbes/cub.png
)
)
)
[1] => Array
(
[id] => 2
[name] => juvenile
[order] => 2
[KinGrowthStage] => Array
(
[0] => Array
(
[id] => 1
[growth_stage_id] => 1
[kin_id] => 4
[image] => /img/hobbes/juvenile.png
)
)
)
[2] => Array
(
[id] => 9
[name] => adult
[order] => 3
[KinGrowthStage] => Array
(
// Nothing here because Hobbes hasn't reached this growth stage yet
)
)
)
)
)
What I'm getting is this. The Species => GrowthStage => KinGrowthStages is joining on the GrowthStage id rather than the Kin id:
Array
(
[Kin] => Array
(
[id] => 4
[name] => Hobbes
[generation] => 1
[current_growth_stage_id] => 4
[species_id] => 1
)
[Species] => Array
(
[id] => 1
[name] => Tiger
[GrowthStage] => Array
(
[0] => Array
(
[id] => 5
[name] => cub
[order] => 1
[KinGrowthStage] => Array
(
[0] => Array
(
[id] => 1
[growth_stage_id] => 1
[kin_id] => 1
[image] => /img/tony/cub.png
)
)
)
[1] => Array
(
[id] => 2
[name] => juvenile
[order] => 2
[KinGrowthStage] => Array
(
[0] => Array
(
[id] => 1
[growth_stage_id] => 2
[kin_id] => 1
[image] => /img/tony/juvenile.png
)
)
)
[2] => Array
(
[id] => 9
[name] => adult
[order] => 3
[KinGrowthStage] => Array
(
[0] => Array
(
[id] => 1
[growth_stage_id] => 3
[kin_id] => 1
[image] => /img/tony/adult.png
)
)
)
)
)
)
I understand why this happening, I just want to know if there's any way to modify the relationship 'on the fly' and join it on the kin id. I've tried adding the following conditions array to my contain array:
$this->Kin->contain(
array(
'Species' => array(
'GrowthStage' => array(
'KinGrowthStage' => array(
'conditions' => array('Kin.id = KinGrowthStage.kin_id'),
),
'order' => 'GrowthStage.order ASC'
)
)
)
);
But I get an error about 'unknown table Kin'.
Use the Linkable Behavior https://github.com/Terr/linkable
$this->Kin->find('all', array(
'link' => array(
'Species' => array(
'GrowthStage' => array(
'KinGrowthStage' => array(
'conditions' => 'Kin.id = KinGrowthStage.kin_id',
)
)
)
),
'order' => 'GrowthStage.order ASC'
));

How do I format the output array in CakePHP

Let's say I have an index action where I want to get a list of projects:
$this->Project->find('all', array('order' => 'Project.modified DESC', 'conditions' => array('Project.user_id' => 1)));
It works well and returns the following array:
Array ( [0] => Array ( [Project] => Array ( [id] => 2 [title] => test project ) ) [1] => Array ( [Project] => Array ( [id] => 1 [title] => first project ) ) )
How do I modify the find function, so it returns the array in the following format:
Array ( [projects] => Array ( [0] => Array ( [id] => 2 [title] => test project ) [1] => Array ( [id] => 1 [title] => first project ) ) )
Thank you!
You could use the Set::combine() utility method to do this. I've used it for similar means as so:
public function groupByMenu() {
return Set::combine (
$this->find (
'all',
array (
'conditions' => array ( 'NavItem.active' => 1 ),
'order' => 'NavMenuItem.display_order'
)
),
'{n}.NavItem.title',
'{n}',
'{n}.NavMenu.id'
);
}
The code above takes a set of navigation items and reorganizes them so that they're grouped by the menu(s) they are displayed within.
It's not really clear if it's the fact that the result is under 'Project' rather than 'projects', but if you don't like that it's under [0] I believe you could use PHPs array_shift:
$result = $this->Project->find('all', array('order' => 'Project.modified DESC', 'conditions' => array('Project.user_id' => 1)));
$result = array_shift($result);
The result will be:
Array ( [Project] => Array ( [id] => 2 [title] => test project ) ) [1] => Array ( [Project] => Array ( [id] => 1 [title] => first project ) )

Resources