I have used join query which joins three tables employee, places and employee_places.The join query gives me all the results as I have used find('all').But in the view page I just want to show employee name from employee table - place name from place table in a dropdown.
e.g:- emp1-place1,emp2-place2 and so on. Where should I give the fields name in find.
Look at the following code :
$options['joins'] = array(
array('table' => 'employees',
'alias' => 'emp',
'type' => 'inner',
'conditions' => array(
'emp.id = EmployeePlace.employee_id '
)
),
array('table' => 'places',
'alias' => 'pl',
'type' => 'inner',
'conditions' => array(
'pl.id = EmployeePlace.place_id'
)
)
);
$empTables = $this->Bill->EmployeePlace->find('all', $options);
$this->set(compact('empTables'));
The above query results the following array:-
Array
(
[0] => Array
(
[EmployeePlace] => Array
(
[id] => 1
[employee_id] => 1
[place_id] => 1
[Date] => 2011-02-02
)
[Employee] => Array
(
[id] => 1
[image] =>
[firstName] => Andy
[lastName] => Murray
[date_of_joining] => 2010-09-02
[date_of_leaving] => 2011-02-02
[date_of_birth] => 1991-08-10
[gender] => Male
[supervisor] => 0
[designation] => Manager
[user_id] => 0
)
[Place] => Array
(
[id] => 1
[placeName] => table-1
[section_id] => 1
[position] => Left
[seating_capacity] => 4
)
)
)
I just want firstName from employee - placeName from place table in the dropdown. How do I do this using condition in find.
Use containable: http://book.cakephp.org/view/1323/Containable
You will then only be dealing with data that you require.
Loop over the results and build the strings you want. Add the strings to an array indexed against the value you want the selection to return. Pass the array out to the view.
How are you going to handle the values? What do you want to do when a user has made a selection?
OR:
You could create a db view, which is a table that combines data from other tables on the fly. CakePHP can access this as a normal table.
Related
I have Three tables Projects, Tasks and Tags. Projects.id is the primary key of the first table, Tasks.id is the PK of the second table and Tags.id is the PK of Third table.
Projects Model Code snippet
public $primaryKey = 'id';
public $hasMany = array(
'Tasks' => array('className' => 'Tasks','foreignKey' => 'project_id')
);
Tasks Model Code snippet
public $primaryKey = 'id';
public $hasMany = array(
'Tags' => array('className' => 'Tags','foreignKey' => 'task_id')
);
The below query return some unexpected result.
$data = $this->Projects->find('all', array(
'recursive' => 2,
'contain' => array(
'Tags' => array(
'conditions' => array('Tags.tag_name =' => "Driver")
)
)
));
The response data i am getting is
[Projects] => Array
(
[id] => 1
[project_id] => 1234
[project_name] => XYZ
)
[Tasks] => Array
(
[0] => Array
(
[id] => 1
[project_id] => 1
[task_id] => 12
[task_name] => task1
[Tags] => Array
(
[0] => Array
(
[id] => 1
[task_id] => 1
[tag_id] => 3444
[tag_name] => Driver
)
)
)
[1] => Array
(
[id] => 2
[project_id] => 1
[task_id] => 343242
[task_name] => task2
[Tags] => Array
(
)
)
See i am even getting tasks without tag as Driver. How i can exclude tasks without tag Driver?
In another word task1 do have Tag as Driver, so that should be there. But task2 don't have any tag, even then the return data contain task2. How to fix it?
You cannot limit the results of the main or parent model based on conditions on child models because "contain" actually creates separate queries for each contain model.
To get the proper result you must use join.
I'm using CakePHP 2.3.8 and I'm trying to more efficiently join two tables. buildings and building_rental_rates
buildings
id | name | description | property_owner | building_type
1 Big Big Building 1 1
building_rental_rates
id | building_type | rate_name | rate
1 1 daily 150.00
2 1 hourly 15.00
I want to look up a building and select the different rental rates. The tables are joined on building_type. Here's the find statement I have
$buildings = $this->Building ->find('all',array(
'Building.property_owner' => '1',
'fields' => array('Building.*','BuildingRentalRate.*'),
'joins' => array(
array(
'table' => 'building_rental_rates',
'alias' => 'BuildingRentalRate',
'type' => 'inner',
'conditions' => array(
'Building.building_type = BuildingRentalRate.building_type'
)
)
)
));
Here is the result
Array
(
[0] => Array
(
[Building] => Array
(
[id] => 1
[name] => Big
[description] => Big Building
[property_owner] => 1
[building_type] => 1
)
[BuildingRentalRate] => Array
(
[id] => 1
[building_type] => 1
[rate_name] => daily
[rate] => 150.00
)
)
[1] => Array
(
[Building] => Array
(
[id] => 1
[name] => Big
[description] => Big Building
[property_owner] => 1
[building_type] => 1
)
[BuildingRentalRate] => Array
(
[id] => 2
[building_type] => 1
[rate_name] => hourly
[rate] => 15.00
)
)
)
While the data is found properly, it's a pain to traverse through it. Can I use a join statement to result in this output? Notice how the BuildingRentalRate is an array containing all entries of that table that share the same building_type
Array
(
[0] => Array
(
[Building] => Array
(
[id] => 1
[name] => Big
[description] => Big Building
[property_owner] => 1
[building_type] => 1
)
[BuildingRentalRate] => Array
(
[0] => Array
(
[id] => 1
[building_type] => 1
[rate_name] => daily
[rate] => 150.00
)
[1] => Array
(
[id] => 2
[building_type] => 1
[rate_name] => hourly
[rate] => 15.00
)
)
)
)
I know Cake can output results like this when using model associations, but I wasn't able to get my associations correct apparently because it kept on joining Building.id on BuildingRentalRate.building_type (it should be Building.building_type = BuildingRentalRate.building_type)
Even with my association like this...
//Building.php
public $hasMany = array('BuildingRentalRate' => array('foreignKey' => 'building_type'));
//BuildingRentalRate.php
public $belongsTo = array('Building' => array('foreignKey' => 'building_type'));
It would join Building.id on BuildingRentalRate.building_type despite specificying building_type in both models as the foreign key.
Can I do some kind of nested SQL query in the conditions or is there an easier way of doing this?
you should be able to avoid using joins if in BuildingRentalRate.php you set your relationship this way
$public belongsTo = array(
'Building' => array(
'foreignKey' => false,
'conditions' => array
(
'Building.building_type' => 'BuildingRentalRate.building_type'
)
)
);
I want to display all comments along with all posts in a single page.For eg : I have 3 comments for POST A,2 comments for post B and so on.
It should look like this :
POST A - 3 Comments
POST B - 2 Comments and so on
So for this I have coded this :
$result = $this->Comment->find('all',array('fields'=>array('Comment.post_id','Comment.comments'),'group'=>'Comment.post_id'));
pr($a);exit;
$this->set('a',$a);
The array I got is this
Array
(
[0] => Array
(
[Comment] => Array
(
[post_id] => 1
[comments] => Nice Post...Nice Post...Nice Post...
)
)
[1] => Array
(
[Comment] => Array
(
[post_id] => 3
[comments] => wow..nice !!! Lorem Ipsum is simply dummy text of the printing and typesetting
)
)
)
I have total 3 comments for post_id = 1
I want all the three comments come together.
Remove ,'group'=>'Comment.post_id' from your find()
Depending on exactly what you mean, there are a number of ways to do that.
Find on Post
The question description is:
want to display all comments along with all posts
For that you'd only need to perform a find on Post, including Comment in the scope of the results. If your associations have been defined correctly that means:
$result = $Post->find('all', array(
'recursive' => 1
));
In this case, $result will be of the form:
[0] => Array
(
[Post] => Array
(
[id] => 1
[title] => First article
[content] => aaa
[created] => 2008-05-18 00:00:00
)
[Comment] => Array
(
[0] => Array
(
[id] => 1
[post_id] => 1
[author] => Daniel
[email] => dan#example.com
[website] => http://example.com
[comment] => First comment
[created] => 2008-05-18 00:00:00
)
[1] => Array
(
[id] => 2
[post_id] => 1
[author] => Sam
[email] => sam#example.net
[website] => http://example.net
[comment] => Second comment
[created] => 2008-05-18 00:00:00
)
)
)
[1] => Array
(
[Post] => Array
(...
Instead of using recursive, you can use the containable behavior to fine-tune the amount of information returned.
Find on Post - counting comments
To get a list of posts and their comment counts - you need first to understand the sort of query required - e.g.:
SELECT
Post.id,
COUNT(Comment.id)
FROM
posts as Post
LEFT JOIN
comments as Comment ON (Post.id = Comment.post_id)
GROUP BY
Post.id
Without the join, any post with no comments will not be listed.
There are many ways to execute a query of that kind - here's one:
$result = $Post->find('all', array(
'fields' => array(
'Post.id',
'COUNT(Comment.id)'
),
'group' => array('Post.id'),
'joins' => array(
array(
'table' => 'comments',
'alias' => 'Comment',
'conditions' => array(
'Post.id = Comment.post_id'
)
)
)
));
Use find list
The group query in the question isn't the right structure unless there's an aggregate function used (count, sum, etc.). To get all comments grouped by post id - you can however use find list:
$result = $Comment->find('list', array(
'fields' => array(
'id',
'comments',
'post_id'
)
));
Used in this way the response format will be:
$result['post_id']['id']['comment']
i.e.:
array(
1 => array(
aa => 'Nice Post...Nice Post...Nice Post...',
bb => 'Another comment for post id 1'
),
3 => array(
cc => 'wow..nice !!! Lorem Ipsum is simply dummy text of the printing and typesetting ',
dd => 'Another comment for post id 3',
...
)
)
Array
(
[Site] => Array
(
[id] => 1
[parent_id] => 0
[title] => test
[url] => http://www.test.com
[slug] => www_test_com
[keywords] => cpc,seo
[language_id] => 1
)
[SiteMeta] => Array
(
[0] => Array
(
[id] => 1
[site_id] => 1
[key] => pagerank
[value] => 5
[created] => 2010-08-03 00:00:00
)
)
)
By using cakephp, I debug my find('all') and returned me above array. I can sort Site field values by order value inside find function how I am able to order also with SiteMeta values
Any ideas?
Thanks
I'd do this in the Model as part of the association.
$hasMany = array('SiteMeta'=>array('order'=>array('SiteMeta.value'=>'asc')))
You won't have to repeat yourself anywhere then.
you can use a default query with a order condition like this:
$result = $this->Site->find('all', array(
'order'=>array('SiteMeta.value DESC' , 'Site.value DESC'),
'recursive'=>1));
Obviously you can put a condition inside the array to retrieve your right result
I would do it this way (as shown in the Docs)
$result = $this->Site
->find()
->contain([
'SiteMeta' => [
'sort' => ['SiteMeta.pagerank' => 'ASC']
]
]);
I have two tables in my database Members and Memberitems. I created two models for it. one is, Member and another is Memberitem
Member model has hasMany relation to Memberitem, and Memberitem model has belongsTo relations with my Member model.
Memberitem entries has specific categorization based on color, like, Red, Pink, Green, etc.
Now I want to select all the members who has atleast one Pink color memberitem using pagination.
Currently I am using:
$this->paginate = array(
'limit' => 5,
'contain' => array(
'Memberitem' => array(
'conditions' => array('Memberitem.color' => 'Pink')
)
)
);
But its showing all the Members.
output is this:
Array
(
[0] => Array
(
[Member] => Array
(
[id] => 1
[first_name] => fh
[last_name] => g
)
[Memberitem] => Array
(
[0] => Array
(
[id] => 1
[name] => item2
[color]=> Pink
)
)
)
[1] => Array
(
[Member] => Array
(
[id] => 2
[first_name] => ad
[last_name] => vd
)
[Memberitem] => Array
(
)
)
[2] => Array
(
[Member] => Array
(
[id] => 3
[first_name] => ae
[last_name] => sdi
)
[Memberitem] => Array
(
[0] => Array
(
[id] => 3
[name] => item1
[color]=> Pink
)
)
)
)
Its showing this result. Member of empty memberitem is still there. I want only 1st and 3 record in result.
This is a classic :-) It takes a while to get it though.
The Cake manual has an excellent peace on this. You should read: http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html#containing-deeper-associations
So if you want only Members with certain MemberItems, you should query on the MemberItems and contain the Member Model. You can actually do this from Member Model:
$this->Member->Memberitem->find('all', array(
'conditions' => 'Memberitem.color = "Pink"',
'contain' => 'Member',
));
or maybe a bit more catered to you app:
$this->paginate['Memberitem'] = array(
'contain' => array('Member'),
'conditions' => array(
'Memberitem.color' => 'Pink',
),
);
$items = $this->paginate('Memberitem');
Hope that helps!