HI,
why not work "order" function?
$this->paginate = array(
'limit' => 5,
'order' => array(
'User.name' => 'desc'
),
'fields' => array('Post.id', 'Post.title', 'User.name AS aut_name'),
'joins' => array(
array(
'table' =>'users',
'alias' =>'User',
'type' =>'LEFT',
'conditions' => array(
'Post.user_id = User.user_id'
)
)
)
);
$posts = $this->paginate();
$this->set(compact('posts'));
DB structure:
posts:
id, title,body, created, updated, user_id
users:
user_id, name
Looking quickly your code... Does field user_id exist in User table?
'conditions' => array(
'Post.user_id = User.id'
)
Because you're specifying User.name As aut_name in your fields, you won't be able to order by User.name unless you also have User.name in your fields list. Alternatively use:
'order' => array(
'aut_name' => 'desc'
),
NOTE: This is for the initial query only, to sort by aut_name from the View you'll need to use a Virtual Field in the User model.
Also, as #Min said, are your conditions correct?
Adding a solution on the same problem:
This work for cakePHP 2.3.4
CakePHP Paginate conditions on Join Table
Related
I have some deep associations using containable and need to filter back the results. For the sake of this question, let's say we are selling cars and want to narrow the results down by features.
Car hasmany make hasmany model HABTM features
$options = array(
'order' => array('Car.price'),
'contain' => array(
'make',
'model' => array(
'order' => 'Model.name ASC'
),
'features'
)
);
$cars = $this->Car->find('all', $options);
How would I go about excluding all cars that don't have power windows (Features.name != power_windows).
Containable is only suitable for you to specify what models you wanted to include when fetching data, but not limiting the parent model from fetching data at all. One obvious symptom is that sometimes your parent data may have some null contained data.
So to achieve it, I think we should use joins here so you can specify condition:
$options = array(
'order' => array('Car.price'),
'contain' => array(
'make',
'model' => array(
'order' => 'Model.name ASC'
),
'features'
),
'joins' => array(
array(
'table' => 'features',
'alias' => 'Feature',
'type' => 'LEFT',
'conditions' => array(
'Car.id = Feature.car_id'
)
)
),
'conditions' => array(
'Features.name !=' => 'power_windows',
)
);
But one drawback of this is that you might have duplicated Car due to joining. That's a separate issue ;)
I am working on a cakephp 2.x .. I have two tables in my database both have the userid I am using bindModel.. my query is working fine ... I just have one problem .. I want to add the condition in where clause that
**where userid = $userid**
function getMessages($userid){
$this->bindModel(array(
'belongsTo' => array(
'Contact' => array(
'className' => 'Contact',
'foreignKey' => false,
'conditions' => array(
'Message.user_id = Contact.user_id',
'AND' =>
array(
array('OR' => array(
array('Message.mobileNo = Contact.mobileNo'),
array('Message.mobileNo = Contact.workNo'),
)),
)
),
'type' => 'LEFT',
)
)
), false);
return $this->find('all', array('conditions' => array(),
'fields' => array('Message.mobileNo'
),
'group' => 'Message.mobileNo',
'limit' => 6));
}
I am getting user id in parameter ... so I want to add the condition that get the following result where
message.userid and contact.userid = $userid ...
Just split the conditions in two lines like:
'conditions' => array(
'Contact.user_id' => $userid,
'Message.user_id = Contact.user_id',
[...]
)
But the approach that makes more sense is to leave the bind as is - after all the bind is generally between message users and contact users with the same id - and add the condition for the specific case in your find('all') with 'Message.user_id' => $userid.
i have a two tables namely; histories and users. i need to display data like:
id | Username | Lastest created Post | First created Post
the data of id and username is from users table and the last created and first created post data is from histories. i need to view all the users, their lastest created post and their first created post. please help me to make controller and view thanks
Try below.
<?php
$users = $this->User->find('all',array
(
'conditions' => array
(
//conditions goes here
),
'fields' => array
(
'User.id',
'User.username',
'History.Lastest created Post',
'History.First created Post'
)
));
?>
Assume that relation between 'User' and 'History' table is One-to-One and there's a 'user_id' column in History table, you may need to specify relation between them in History model, for example:
var $hasOne = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
Then, you need to perform joins to do this. For example, somewhere in your User model, try something like this:
class User extends AppModel {
....
function getAllUsersHistory{
$allHistories = $this->find('all', array(
'joins' => array(
'table' => 'history',
'alias' => 'HistoryJoin'
'type' => 'INNER',
'conditions' => array(
// your conditions, for example: 'History.user_id' => 'User.id'
)
),
'fields' => array(
'User.id',
'User.username',
'History.lastest_created_post',
'History.first_created_post'
)
));
return $allHistories;
}
.....
}
Im trying to replicate the following query in cakephp:
SELECT *
FROM uploads, proposals
WHERE proposals.id = uploads.proposal_id AND proposals.tender_id = 10
Im using the find method in the Upload model with the following conditions:
$conditions = array(
'Proposal.id' => $id,
'AND' => array(
'Upload.proposal_id' => 'Proposal.id'
)
);
return($this->find('list', array('conditions' => $conditions)));
but im getting this query instead
SELECT `Upload`.`id`, `Upload`.`title`
FROM `kumalabs_lic`.`uploads` AS `Upload`
WHERE `Proposal`.`id` = 10 AND `Upload`.`proposal_id` = 'Proposal.id'
as you can see, the proposals table is missing, can somebody explain me how can i make this query?
Thanks :)
I would recommend you use the linkable behaviour for this. It is much easier than the default way of doing joins in CakePHP. It works with the latest version of CakePHP, as well as 1.3.
CakePHP Linkable Behavior
You would then modify your find to look like this:
return($this->find('list', array(
'link' => array('Proposal'),
'conditions' => array(
'Proposal.id' => $id,
),
'fields' => array(
'Upload.*',
'Proposal.*',
),
)));
CakePHP will automatically join on your primary / foreign key, so no need to have the
'Upload.proposal_id' => 'Proposal.id'
condition.
Though you don't need that condition, I also want to point out that you are doing your AND wrong. This is how you do AND and OR in CakePHP
'conditions' => array(
'and' => array(
'field1' => 'value1', // Both of these conditions must be true
'field2' => 'value2'
),
'or' => array(
'field1' => 'value1', // One of these conditions must be true
'field2' => 'value2'
),
),
If the model have association, CakePHP automatically join the table by 'contain' keyword. Try code bellow:
public function getProposalsFromTender($id){
$data = $this->find('all', array(
'conditions' => array('Proposal.id' => $id),
'fields' => array('Upload.*', 'Proposal.*'),
'contain' => array('Proposal')
));
return($data);
}
Note:
CakePHP use explicit join instead of implicit join like ...from proposals, uploads...
I'm not familiar with that JOIN syntax but I believe it equals this:
SELECT *
FROM uploads
INNER JOIN proposals ON proposals.id = uploads.proposal_id
WHERE proposals.tender_id = 10
... so you need something similar to this:
// Untested
$conditions = array(
'Proposal.id' => $id,
'joins' => array(
array(
'alias' => 'Proposal',
'table' => 'proposals',
'type' => 'INNER',
'conditions' => 'Proposal.id = Upload.proposal_id',
),
),
);
Of course, this is a direct translation of your JOIN. If your models are properly related, it should all happen automatically.
I'm trying to return a list of events, and include the city where it's taking place. The city is only associated through the Event's Venue though.
Below is the code I'm using. It returns all the correct data, but it doesn't return ANY city data (other than the city_id field in Venue - which I'm not sure why it's returning).
Associations:
Event belongsTo Venue
Venue hasMany Event
Venue belongsTo City
City hasMany Venue
Code:
$this->Event->Behaviors->attach('Containable');
$events = $this->Event->find('all', array(
'limit' => 5,
'order' => 'Event.created DESC',
'fields' => array(
'name',
'description',
'phone',
'price_general',
'price_child',
'price_adult',
'price_child',
'tickets_url'
),
'contain' => array(
'Venue' => array(
'fields' => array(
'name',
'address',
'city_id',
),
'City' => array(
'fields' => array(
'City.name',
'state'
),
'conditions' => array(
'City.id' => 'Venue.city_id'
)
)
),
'Schedule' => array(
'fields'=>array(),
'Date' => array(
'conditions'=>array(
'Date.start >=' => $start_date,
'Date.start <=' => $end_date,
)
)
)
),
));
Bonus answer: (that I have currently asked in another StackOverflow question) - The Date conditions are supposed to filter which events show up, but instead, they're only filtering which Date data to show.
WORKING ANSWER: (thanks bancer)
$this->Event->recursive = -1;
$options['joins'] = array(
array('table' => 'schedules',
'alias' => 'Schedule',
'type' => 'LEFT',
'conditions' => array(
'Event.id = Schedule.event_id',
)
),
array('table' => 'dates',
'alias' => 'Date',
'type' => 'LEFT',
'conditions' => array(
'Date.schedule_id = Schedule.id',
)
)
);
$options['fields'] = array(
'Event.name',
'Schedule.start_date',
'Date.start',
);
$options['limit'] = 5;
$events = $this->Event->find('all', $options);
I would recommend to avoid using Containable. It generates too many queries in some cases. A better way for complex queries is to join tables "manually".
Another option I would consider at the first place is to search through 'Venue' model without using Containable like this: $this->Event->Venues->find('all', ...). As Venues directly associated with Cities and Events there should be possible to get what you want without extra complexities.
Update: take a look at the question How to change the sequence of 'joins' in CakePHP?
instead of containable, did you try including the city data in fields itself by fields=> array('','','City.name)