I have two tables
posts
------
post_id | user_id | post_title | post_content
And
users
--------
id | user_name | user_ . .. . . . and so on
I need to fetch all posts with the user data
to show the post writer etc..
How can I achieve this using CakePHP queries?
In your UserModel you define:
var $hasMany = 'Post';
In your PostModel you define:
var $belongsTo = 'User';
Then you can get all post of some user doing:
$this->User->findAllById($id, array('recursive' => 2));
Or you can get ALL posts associated with the respective users doing:
$this->Post->find("all", array('recursive' => 2));
EDIT:
Your Posts id column is named post_id so you must define primary key in your PostModel since CakePHP conventions is that primary key should be named id:
public $primaryKey = 'post_id';
$this->Post->find('all',array('fields'=>array('User.*'),'conditions'=>array('Post.user_id=User.id')),
joins' => array(
array(
'alias' => 'User',
'table' => 'users',
'type' => 'Inner',
'conditions' => array('User.user_id' =>$id)
)
)
));
Related
I've been trying to save two foreign keys to the same row of a join table with no success. My Client model has two HABTM association with both User and Group models, a user can have many clients and create clients under many different groups.
The UserClient join table looks like this:
+----+---------+----------+-----------+
| id | user_id | group_id | client_id |
+----+---------+----------+-----------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 2 | 2 |
| 3 | 3 | 4 | 3 |
+----+---------+---------+------------+
Client model:
public $hasAndBelongsToMany = array(
'User' => array(
'className' => 'User',
'joinTable' => 'UserClient',
'foreignKey' => 'client_id',
'associationForeignKey' => 'user_id'
),
'Group' => array(
'className' => 'Group',
'joinTable' => 'UserClient',
'foreignKey' => 'client_id',
'associationForeignKey' => 'group_id'
)
);
Client view:
<?php echo $this->Form->create('Client'); ?>
<fieldset>
<legend><?php echo __('Add Client'); ?></legend>
<?php
echo $this->Form->input('first_name');
echo $this->Form->input('last_name');
echo $this->Form->input('email');
echo $this->Form->input('phone');
echo $this->Form->input('Client', array('multiple'=> 'false', 'options' => $group_ids));
echo $this->Form->hidden('User', array('value' => $user_id));
?>
</fieldset>
<?php echo $this->Form->end(__('Submit')); ?>
This works to a point, however instead of saving user_id, group_id and client_id to the same row in UserClient table, it create two separate rows for each HABTM, user_id, client_id get saved to one row and group_id, client_id get saved to another.
Is there any way to define multiple associationForeignKey within the same HABTM association so user_id, group_id and client_id get saved to the same row when creating a new client?
When you have to store additional fields in a HABTM relation, it is sometimes easier to use a join model. In your case this would mean creating a model for your UserClient table and use hasMany relations instead of HABTM.
Then of course you'll have to manage the save manually, but you'll have much more control of what must be done. You can find a few words about this in the Cake documentation.
Lets say each book has AuthorA and AuthorB fields.
Both fields are foreign keys for authors table.
table authors with fields: id | name
table books with fields: id | name | a_author_id | b_author_id |
How should controller, model and view be set up to be able to create a book with dropdown list of "author a" and "author b" both coming from author table? How would form-input for author-a (and author-b) look like inside "Add" view for Book model?
You need to setup 2 belongsTo association in your Book model with different aliases for Author model.
public $belongsTo = array(
'AAuthor' => array(
'className' => 'Author',
'foreignKey' => 'a_author_id'
),
'BAuthor' => array(
'className' => 'Author',
'foreignKey' => 'b_author_id'
)
);
Use $this->Book->AAuthor->find('list') to get the authors list and set the array to view and specify same array using 'options' key in Form->input() options for both a_author_id and b_author_id fields.
I was having trouble with a voting system that I'm trying to make in cakePHP (found here cakephp is querying extra column and I can't figure out why) but I figured that out and now I'm having another issue.
I'm making a voting system, and the problem I'm having is that only one user can vote on a given post. For example, if user 1 votes on post 1, and then user 2 votes on post 1, user 2's vote will overwrite user 1's vote.
Here are my tables
Votes
id | user_id | vote
Posts
id | title | body | created | modified | user_id | vote_total
I'm having trouble setting up the associations
Users can vote on many posts
A post can have many votes, but only 1 per user
This is in my Users model
public $hasMany = array(
'Posts' => array( 'className' => 'Post'),
'Votes' => array('className' => 'Vote')
);
This is in my Posts model
public $hasMany = array( //there can be multiple votes of the same id (references post table)
'Votes' => array('foreignKey' => 'id')
);
I don't have a votes controller. It's done through a vote function on PostsController.php
public $hasMany = array( //there can be multiple votes of the same id (references post table)
'Votes' => array('foreignKey' => 'id')
);
is wrong. It should be:
public $hasMany = array( //there can be multiple votes of the same id (references post table)
'Votes' => array('foreignKey' => 'post_id')
);
And so you have to add post_id in the Vote model.
I'm trying to access a user's name in a view on cakephp. I'm given a userid and I need to use that to look up their username which is stored in a different table.
The table that I'm retrieving displaying is messages and is as follows
id | title | message | from_user | to_user | date
The users table which contains the username
id | username | email | password
Anyway how can I look up the username of from_user in the message? I'm still getting used to cake so I don't know how to make a "join" statement without actually writing a query.
Should I send the username from the action in the controller or is it OK to do this from the view?
edit- I got it to work
Here is my index function now
public function index() {
$options['joins'] = array(
array('table' => 'Users',
'type' => 'inner',
'fields' => array('user.username'),
'conditions' => array(
'Message.from_user = User.id',
'alias' => 'user_id')
)
);
$message = $this->Message->find('all', $options);
$this->set('messages', $message);
}
I added this to my Message controller and the username now displays, but ONLY for the first message. All of the others it's blank.
public $belongsTo = array('User');
You have to redefine your relationship in Message model :
public $belongsTo = array(
'Sender' => array(
'className' => 'User',
'foreignKey' => 'from_user'
),
'Recipient' => array(
'className' => 'User',
'foreignKey' => 'to_user'
)
);
You can use containable behavior to retrieve that record. What I do is add the behavior to AppModel and set recursive to -1 in AppModel.
Then your read() call would turn into
public function view($id) {
$message = $this->Message->find('first', array(
'conditions' => array('Message.id' => $id),
'contain' => array(
'FromUser' => array('fields' => array('FromUser.username')),
),
));
$this->set('message', $message'); // or just $this->set(compact('message'));
}
In your view:
$message['FromUser']['username'];
You may also do a debug($message); either in the view or controller to see what exactly is inside the variable and the structure of it.
Assuming you have your relations set up correctly, this should retrieve the FromUser.username field associated with the message record.
More on containable: http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html (2.x) and http://book.cakephp.org/view/1323/Containable (1.3)
I have the following three database tables:
Products
########
id
title
artist_id
Arists
######
id
profile
person_id
People
######
id
first_name
last_name
In my Product model how do I create a method to return the product title along with the artist's first_name?
I have set up the following model associations:
Product belongs to Artist
Artist belongs to Person
Containable is definitely the way to go for filtering related records. Make sure to add $actsAs = array('Containable') into your model or app_model.
Then you can do things like:
$this->Product->find('all', array(
'contain' => array(
'Artist' => array(
'Person' => array(
'id',
'first_name'
)
)
)
));
Assuming you already set the relationships in these models, you just need to set it recursive:
$this->Product->recursive = 2;
print_r($this->Product->find('all'));