Find to mime the LeftJoin in CakePhp - mysql

I have 3 models:
User
Like
Post
Like has 2 foreign key set using CakePHP convention on user_id and post_id (that are the id column of the other 2 models).
I want to run a find that mime the LEFT JOIN in sql on Post with a condition on the foreign key.
In detail i want:
1: all the posts.
1a: if the post have a like from the user XXX I want it included in the result
1b: else the post doesn't have a ->Like attribute.
So, if i do this:
$posts = $this->Post->find('all');
in $posts i have all the posts, and for each posts all the likes.
Reading the book, I feel like i should write something like:
$options['joins'] = array(
array('table' => 'likes',
'alias' => 'Likes',
'type' => 'LEFT',
'conditions' => array(
'Post.id = Likes.post_id',
'Likes.user_id = 536f6a29-babc-4724-a74d-2ce100000000'
)
)
);
$posts = $this->Post->find('all', $options);
But this doesn't work.
Hope this is clear.

well you need put in your models
class User extends AppModel
{
public $useTable = 'users';
public $primaryKey = 'id';
public $hasMany = array(
'Post',
'Like'
);
}
class Post extends AppModel
{
public $useTable = 'posts';
public $primaryKey = 'id';
public $belongsTo = array('User');
public $hasMany = array(
'Like'
);
}
class Like extends AppModel
{
public $useTable = 'likes';
public $primaryKey = 'id';
public $belongsTo = array('Post','User');
}
and in you controller
$this->loadModel("User");
$query = $this->User->find('all', array(
'joins' => array(
array(
'table' => 'posts',
'alias' => 'Post',
'type' => 'LEFT',
'conditions' => array(
'User.id = Post.user_id'
)
),
array(
'table' => 'likes',
'alias' => 'Like',
'type' => 'LEFT',
'conditions' => array(
'User.id = Like.user_id'
)
)
),
'conditions' => array(
'Post.id = Likes.post_id',
'Likes.user_id = 536f6a29-babc-4724-a74d-2ce100000000'
),
'order' => array(
'Post.id' => 'ASC'
),
'fields' => array('Post.*','User.id'),
'recursive' => -1
));

Related

How to use conditions in self association without joins?

I have Product model [id, parent_id, x].
I want to append on each Product, single ProductParent, only when Product.x = 0, and Product.parent_id = ProductParent.id.
What i try is:
public $hasOne = array(
'ProductParent' => array(
'className' => 'Product',
'foreignKey' => false,
'conditions' => array(
'ProductParent.id = Product.parent_id',
'Product.x' => 0
)
)
);
And get output Product.parent_id is unknown.
You can try using Tree behavior. Check this: http://book.cakephp.org/2.0/en/core-libraries/behaviors/tree.html

Cakephp: How to link models if each model connected to other by some foreign key

I am new to Cakephp and I don't found any solution for my problem.
I have three tables-
medicines:
id|Name|company_id
companies:
id|Name|city_id
cities:
id|Name
I have to select medicines.name, companies.name and cities.name where ids are matched so
how I cand do this by Cakephp method.
I know the simple sql query for this:
SELECT medicines.name, companies.name and cities.name FROM medicines, companies, cities WHERE medicines.company_id=companies.id AND companies.city_id=cities.id
Thanks in Advance
Have you tried reading the book? It is well explained there: Associations: Linking Models Together
Defining relations between different objects in your application
should be a natural process. For example: in a recipe database, a
recipe may have many reviews, reviews have a single author, and
authors may have many recipes. Defining the way these relations work
allows you to access your data in an intuitive and powerful way.
Examples from the book:
class User extends AppModel {
public $hasOne = 'Profile';
public $hasMany = array(
'Recipe' => array(
'className' => 'Recipe',
'conditions' => array('Recipe.approved' => '1'),
'order' => 'Recipe.created DESC'
)
);
}
class User extends AppModel {
public $hasMany = array(
'MyRecipe' => array(
'className' => 'Recipe',
)
);
public $hasAndBelongsToMany = array(
'MemberOf' => array(
'className' => 'Group',
)
);
}
class Group extends AppModel {
public $hasMany = array(
'MyRecipe' => array(
'className' => 'Recipe',
)
);
public $hasAndBelongsToMany = array(
'Member' => array(
'className' => 'User',
)
);
}

join two model from one model in cakephp

i want to fetch record form 2 model (Booking and Message), both model don't have any relation.
i try a lot but its not working
i used that code ( http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#joining-tables )
$options['joins'] = array(
array('table' => 'books_tags',
'alias' => 'BooksTag',
'type' => 'inner',
'conditions' => array(
'Book.id = BooksTag.book_id'
)
),
array('table' => 'tags',
'alias' => 'Tag',
'type' => 'inner',
'conditions' => array(
'BooksTag.tag_id = Tag.id'
)
)
);
$options['conditions'] = array(
'Tag.tag' => 'Novel'
);
$books = $Book->find('all', $options);
Try this:
BookModel:
public $hasMany = array(
'BooksTag' => array(
'foreignKey' => 'book_id'
)
);
TagModel:
public $hasMany = array(
'BooksTag' => array(
'foreignKey' => 'tag_id'
)
);
BooksController:
$this->Book->Behaviors->load('Containable');
$this->Book->find('all', array(
'contain' => array(
'BooksTag' => array(
'Tag',
),
),
));
I prefer to do this on many queries. First find the required tag:
$this->loadModel('Tag');
$tag = $this->Tag->find('first', array('conditions' => array('Tag.tag' => 'Novel')));
$tag_id = $tag['Tag']['id'];
Then find book_ids:
$this->loadModel('BookTag');
$book_ids = $this->BookTag->find('list', array('conditions' => 'BookTag.tag_id' => $tag_id, 'fields' => 'book_id, book_id'));
Then find books:
$this->Book->find('all', array('conditions' => array('Book.id' => $book_ids)));
It is a long code but runs fast and is easy to understand. Another way is to use sub-queries but they are ugly and may slow down your application

How to retrive From which user is message in Cake?

I am making a message system in CakePHP and I have table messages
id
from_id
to_id
subject
message
to_id is set as FK for user so user can haveMany messages but how can I echo the name of sender if I get only id?
User Model:
class User extends AppModel {
public $name = 'User';
public $hasOne = array (
'UserProfile'=>array(
'className'=>'UserProfile',
'foreignKey'=>'id'
)
);
public $hasMany = array(
'Message'=>array(
'className'=>'Message',
'foreignKey'=>'to_id'
)
);
}
Message Model:
class Message extends AppModel {
public $name = 'Message';
public $belongsTo = array (
'User'=>array(
'className'=>'User',
'foreignKey'=>'to_id'
),
);
}
Message Controller:
public function messages(){
$user = $this->User->find( 'first', array('conditions' => array(
'User.id' => $this->Session->read('Auth.User.id'))));
$this->set('user', $user);
if($this->request->is('post')) {
$this->requert->data['Message']['from_id'] = $this->Auth->user('id');
debug($this->request->data);
}
}
This needs to store all information about user in array including array Message but in this case I get the arrat Message with:
id => 1
from_id => 10
to_id => 7
subject => 'subject'
message => 'body'
So how can I extract the name of sender from this id?
Please help?
In this case you will need to use aliases for the classNames.
class Message extends AppModel {
public $belongsTo = array(
'Sender' => array(
'className' => 'User',
'foreignKey' => 'from_id'
),
'Receiver' => array(
'className' => 'User',
'foreignKey' => 'to_id'
)
);
}
class User extends AppModel {
public $hasMany = array(
'SentMessages' => array(
'className' => 'Message',
'foreignKey' => 'from_id'
),
'Messages' => array(
'className' => 'Message',
'foreignKey' => 'to_id'
)
);
}

Model association is off for joining users table on comments table for a submission

My associations in CakePHP are a bit off. Here is the problem. I have a users table
and a comments table. When retrieving a submission I want to join the users table
on the comments table with Comment.user_id == User.id.
Comment Model:
class Comment extends AppModel {
var $name = 'Comment';
var $belongsTo = array('User');
var $hasMany = array(
'CommentsLike' => array(
'className' => 'CommentsLike'
),
'Comment' => array(
'className' => 'Comment'
)
);
var $hasAndBelongsToMany = array(
'User' => array(
'className' => 'User',
'joinTable' => 'comments',
'foreignKey' => 'Comment.user_id',
'associationForeignKey' => 'user_id'
),
'Submission' => array(
'className' => 'Submission'
)
);
User Model:
class User extends AppModel {
var $name = 'User';
var $hasMany = array('Comment');
var $hasAndBelongsToMany = array(
'Comment' => array(
'className' => 'Comment',
'joinTable' => 'comments',
'foreignKey' => 'Comment.user_id',
'associationForeignKey' => 'user_id',
),
'Submission' => array(
'className' => 'Submission',
'order' => 'Submission.created DESC'
)
);
When I grab a submission, it grabs all comments for it, but it doesn't join on
the users table which is what I want
Submission Model:
class Submission extends AppModel {
var $name = 'Submission';
var $belongsTo = array(
'User' => array(
'className' => 'User'
)
);
var $hasMany = array(
'Comment' => array(
'className' => 'Comment',
'order' => 'Comment.created DESC',
'conditions' => array(
'Comment.deleted' => 0
)
),
'SubmissionsVote' => array(
'className' => 'SubmissionsVote'
),
'SubmissionThumbnails' => array(
'className' => 'SubmissionThumbnails'
)
);
A find on a submission will return this:
[Submission] => Array
(
// removed for sake of stackoverflow length
)
[User] => Array
(
[id] => 2
[username] => bob_cobb
)
[Comment] => Array
(
[0] => Array
(
[id] => 1
[submission_id] => 112
[comment] => this is a test comment
[user_id] => 2
[created] => 5 minutes ago
[deleted] =>
[parent_id] =>
)
)
As you can see [Comment][0] should also have [Comment][0][User] or something similar.
Why would I want this? Simple: I want to grab the username of the person who
commented by the foreign key of user_id from the comments table. I've read the docs and tutorials and pretty sure I'm close on this but not sure what's holding me back.
Here is a screenshot of the comments table:
Here is a screenshot of the users table structure:
You can a couple of options:
Either set the recursive property in the Submission model to the level you need to fetch back your associated data ( see http://book.cakephp.org/2.0/en/models/model-attributes.html#recursive )
or (more preferable) use the Containable behaviour ( see http://book.cakephp.org/2.0/en/core-libraries/behaviors/containable.html ) to specify what related data to return:
class Submission extends AppModel
public $actsAs = array('Containable');
}
Use it like this in your find:
$data = $this->Submission->find('all', array(
'conditions'=>array(your conditions here),
'contain'=>array(
'User,
'Comment'=>array(
'User'
)
)
));
Most people use containable in every model so add it to AppModel and set AppModel::recursive to -1