Comments having sub-comments in cakePHP - php

I am creating a forum for my school. A student will be able to create many topics in a particular forum and other students are able to comment on it. The tricky part is that i have a feature where a student can have sub comment to a comment. Lemme tell you my simple table structure which i am using Mysql and developing in cakephp. Below is not the full structure.
User (id,name)
Forums(id,desc,date)
Topics(id,user_id,forum_id,title,content,date)
comments(id,user_id,topics_id,content,date,parent_id) *=> the parent_id referers where the subcomment belongs to.*
I used the cakePHP containable to get all toics and comments of a particular forum in my forum_controller:
$this->find('all',array(
'contain'=>array(
'User'=>array(
'fields' => array ('id','displayName','gender','email','profileImgBig')
),'Post'=>array(
'User'=>array(
'fields' => array('id','displayName','gender','email','profileImgBig')
),
'order' => array('Post.created'=>'DESC'),
)
),
'conditions'=>array('Topic.forum_id'=>$id),
'order' => array('Topic.datePosted'=>'DESC')
));
The above retrieves all forum->Topics->User & Topics->Comments->User.
How can i implement in a way that its retrieves all Comments and sub comments? Please help and advice me. Thank you! I am looking at tree behaviour but i am not sure how am i suppose to incorporate with my above find statement.

You can indeed use the TreeBehaviour in CakePHP for this. You'll need to add two more fields to your database (lft, rght) besides parent_id for this and activate it in the model for comments.
See the CakePHP manual for details, but after activating the behaviour you can use functions like Model::children() and Model::find('threaded') to find all comments that reside below a certain comment (e.g, that are subcomments).
I would usually first query the database for all topics, and then queue the Comment model for comments and subcomments using the Model::children() function. I wonder though, why would you want to load all topics and all comments within those topics, and not just 1 topic with comments?

Related

Cakephp, order find by related model field

I have a News model that has many Comments. What I need is to find ten News that has new Comments.
At first this task is seems to be eazy, I just need to find last ten Comments ($this->Comment->find('all');) and just display related News, but in case I have 2 comments for the same news I will recieve a duplicated news entry.
So, can I order News by Comments date or something?
*And here is solution. Thanks Dave
$this->Comment->find('all', array(
'order' => array(
'Comment.created' => 'DESC'
),
'group' => 'News.id',
));
Use MySQL's "GROUP BY" ('group' option in CakePHP). More details:
http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#complex-find-conditions

How to use a relationship in the where parameter when finding records using the pods framework?

my question has to do with the pods framework plugin for wordpress sites. I am using pods version 2.2 and have been having trouble with the where parameter in the find() function.
I'd be suprised if I am the first person to encounter this problem but I have searched extensively and haven't found anyone providing an answer (or question at that).
Anyway, I'll give an example to highlight my problem.
Say I have a Bands Pod and a Records Pod and these two pods have a bi-directional multi-select relationship between them (that is, an n to n relationship). Hence a band can have numerous records and a record can have multiple bands. Further, the relationship exists between the fields BandsPod('records') and RecordsPod('bands').
Now, I can retrieve all records in the records pod like so (note the where is commented out):
$pods = pods('records');
$params = array(
'select' => 't.*',
'limit' => -1
//,'where' => '???'
);
$pods->find($params);
Then do whatever I want with them, e.g. template(), fetch(), etc.
My trouble occurs when I want to filter by band. What should my where statement be if I want to retrieve all records by band with id 1?
My view is that it should be something like this:
$params = array(
'select' => 't.*',
'limit' => -1,
'where' => '1 IN bands.id'
);
$pods->find($params);
However, this does not work (not that I especially expected it to).
It would also be desirable to know how this would work for filtering by multiple bands. E.g.
'where' => '(1, 2) IN bands.id'
As I said before, I've been trying to get this to work for some time and with little joy. I have managed to get it working but in a very ugly way. I.e.
Get bands from Bands Pod with relevant band ids,
Collect all ids of records from the bands pod records field,
Write params for Records Pod
Use the ids in the where statement to check they match with t.id,
$pods->find(); //where $pods=pods('records');
Thanks in advance for taking the time to read this and any answers you may give.
Cheers,
Joe
N.B. I know about the filters() function and it does not do what I'm after. I'd like stuff specifically for the where statement please.
You would want:
'where' => 'bands.id IN ( 1, 2 )'
If your bands are a custom post type, it would be:
'where' => 'bands.ID IN ( 1, 2 )'

Find query with condition depending on parent model

For the purpose of this question, this is the association tree (all -> means hasMany), all database structure code adheres to CakePHP conventions.
Forum -> Section (forum_id) -> Topic (section_id) -> Reply (topic_id)
I'd like to run a $this->Reply->find query with certain conditions, and I would like the returned $data["Reply"] array to only return replies where they belong to forum_id=X.
For example, I run a $this->Reply->find with certain conditions (these don't matter), and it returns two results with different parents, and when you go up and up until you reach Forum.id (or Section.forum_id), they differ in forum_id.
What I want is to filter the results so they belong to a certain forum_id. Since forum_id is not a field in the Reply model itself, but instead in Section (which is two "layers" up), I can't use a conditions entry to filter the result.
What should I do?
Simple as this:
<?php
$this->Reply->find('all', array(
'joins' => array(
Reply::joinLeft('Topic'),
Topic::joinLeft('Section'),
Section::joinLeft('Forum'),
),
'conditions' => array('Forum.id' => $forumId),
));
https://github.com/tigrang/EasyJoin - This will determine the relationship between the models and create the join arrays for you.
If you don't want to use the plugin, you'll have to specify the joins array manually or rebind the models to be able to use Containable as it would currently create multiple queries rather than joins.

How can this association be set up?

I'm using the cakephp framework to develop an application and I'm running into some trouble understanding the associations between these models fully. Below you can see the four models along with their relative database fields.
User
id
Profile
id
user_id
Post (A blog post on the users profile)
id
profile_id
topic_id
Topic (A topic for a blog post)
id
name
Here are the associations as they currently stand:
User
hasOne: Profile
Profile
hasMany: Posts
Post
belongsTo: Topic, Profile
Now my problem. I am unsure if you have to define associations like User hasMany Posts or if it's already assumed because User hasOne Profile and Profile hasMany Posts. My other problem is defining the relationship between a post and its topic.
A profile can have unlimited posts
A post must be associated with a profile
A post can only have one topic
The topic table contains a list of all topics
A post does not NEED a topic
Given these criteria how should my associations look? All the research I've done on associations only shows simple examples.
I'm using CakePHP version 2.1.3
Thanks for any and all help and/or advice in advance
You can recursively find associations of associations, or even better, use Containable.
In the model (I recommend putting it in AppModel, since I find myself using Containable for everything):
class AppModel extends Model {
public $actsAs = array('Containable');
...
}
Then when you call read (or find, or paginate) for User, most likely in your controller, do this:
$this->User->contain(array(
'Profile' => array(
'Post'
)
));
$data = $this->User->read();
$set('user',$data);
If you set that data to your view, you can then access the id of one of the posts from $user['Profile']['Post'][0]['id'].
Now for your next question, you can have conditional associations.
public $hasMany = array(
'Topic' => array(
'className' => 'Topic',
'conditions' => 'Post.topic_id IS NOT NULL'
)
)
I think everything looks fine
Your assumption is correct you dont have to define the User / Post relationship. Users dont have many Posts, Profiles do. You could store the user_id on the Post rather than profile_id to make thing a bit more intuitive but thats up to you.
Topic hasMany Post and you are done. The topic/post conditions you describe can be controlled via the forms and before saves on the model. For example 'A post must be associated with a profile', well at the point you save the post you add in the profile_id based on session info of the logged in user.

How can I write a complex find query in CakePHP without using `$this->Model->query()`?

Hey all I'm hoping someone has enough experience with Cake PHP to make this work.
I'm working on something that at the moment could affectionately be called a twitter clone. Essentially I have a set up like this.
Users have many friends. This is a many to many relationship to the user table. It is stored in a link tabled called friends_users with columns user_id, friend_id. Users is a table with column user_id.
Then I have a table called tips which associates to a user. A user can have many tips.
I want to figure out a way to do a find on the Tip model that returns all tips owned by the userid i pass in as well as any tips owned by any friends of that user.
This SQL query works perfectly -
SELECT *
FROM `tips`
JOIN users ON users.id = tips.user_id
JOIN friends_users ON tips.user_id = friends_users.friend_id
WHERE (friends_users.user_id =2 or tips.user_id=2)
LIMIT 0 , 30
That returns user#2s Tips as well as the tips of anyone who is a friend of User 2.
Now how can I do the same thing using $this->Tip->findxxxxx(user_id)
I know I can use Tip->query if need be but I'm trying to learn the hard way.
If all you need in the results of the query is a list of tips, I'd be tempted to do this in 2 queries. The first to find a list of user ids of this user and their friends, the second to find the tips that belong to any one of these ids. So, in your Tip model:
function findTipsByUserAndFriends($userId) {
//FriendsUser is automagically created by CakePHP "with" association
$conditions = array('FriendsUser.user_id'=>$userId);
$fields = 'FriendsUser.friend_id';
//get a list friend ids for the given user
$friendIds = $this->Tip->User->FriendsUser->find('list', compact('conditions', 'fields'));
//get list of all userIds for whom you want the tips
$userIds = array($userId) + $friendIds;
$conditions = array('Tip.user_id'=>$userIds);
$tips = $this->Tip->find('all', compact('conditions'));
return $tips;
}
Note that you're calling the first find on the automagically created "FriendsUser" model that CakePHP uses to model your HABTM friends_users table, so you don't need to create it.
This is untested, so you might need to debug some of it, but you get the idea.
I would recommend that you use containable it works great.
$aCond = array(
'fields' => array(
'Discount.*'
),
'contain' => array(
'Event' => array(
'conditions' => array('Event.id' => $iEventId)
)
)
);
$aBulkDiscounts = $this->Discount->find('first', $aCond);
hope this helps.
In CakePHP speak, many to many is "Has And Belongs To Many" (HABTM). Assuming you've set up the relations properly, what you then need to do is have a two level recursive find, such that the friend you find on retrieves all of their friends, and those friends get their tips loaded. You may have to dynamically bind/unbind models in order to prevent those friends from getting their friends (although that in practice may not be too much of a problem).
The manual entry on associations is a must read.

Categories