Attach Comments to Any Model in CakePHP
This method of linking models allows you to have a single table of data, say Comment, that is related to any one of a number of other Models (eg: Post, Event).
The Tables
CREATE TABLE IF NOT EXISTS `comments` ( `id` int(11) NOT NULL auto_increment, `class` varchar(128) NOT NULL, `foreign_id` int(11) NOT NULL, `name` varchar(255) NOT NULL, `body` text, PRIMARY KEY (`id`) ); CREATE TABLE IF NOT EXISTS `posts` ( `id` int(11) NOT NULL auto_increment, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`) ); CREATE TABLE IF NOT EXISTS `events` ( `id` int(11) NOT NULL auto_increment, `name` varchar(255) NOT NULL, PRIMARY KEY (`id`) );
The Models
Before we get started, lets setup the models.
models/comment.php
<?php
class Comment extends AppModel {
var $name = 'Comment';
}
?>
models/post.php
<?php
class Post extends AppModel {
var $name = 'Post';
var $hasMany = array(
'Comment' => array(
'className' => 'Comment',
'foreignKey' => 'foreign_id',
'conditions' => array('Comment.class'=>'Post'),
),
);
}
?>
models/event.php
<?php
class Event extends AppModel {
var $name = 'Event';
var $hasMany = array(
'Comment' => array(
'className' => 'Comment',
'foreignKey' => 'foreign_id',
'conditions' => array('Comment.class'=>'Event'),
),
);
}
?>
The View
views/posts/view.ctp
<h2><?php __('Post Details');?></h2>
<?php debug($post); ?>
<?php echo $form->create('Comment',array('url'=>array('controller'=>'posts','action'=>'view',$post['Post']['id'])));?>
<fieldset>
<legend><?php __('Add Comment');?></legend>
<?php
echo $form->input('Comment.name');
echo $form->input('Comment.body');
?>
</fieldset>
<?php echo $form->end('Submit');?>
The Controller
Now to save the data.
controllers/posts_controller.php
<?php
class PostsController extends AppController {
var $name = 'Posts';
function view($id = null) {
if (!$id) {
$this->_flash(__('Invalid Post.', true),'error');
$this->redirect(array('action'=>'index'));
}
// save the comment
if (!empty($this->data['Comment'])) {
$this->data['Comment']['class'] = 'Post';
$this->data['Comment']['foreign_id'] = $id;
$this->Post->Comment->create();
if ($this->Post->Comment->save($this->data)) {
$this->Session->setFlash(__('The Comment has been saved.', true),'success');
$this->redirect(array('action'=>'view',$id));
}
$this->Session->setFlash(__('The Comment could not be saved. Please, try again.', true),'warning');
}
// set the view variables
$post = $this->Post->read(null, $id); // contains $post['Comments']
$this->set(compact('post'));
}
}
?>
In Conclusion
That's all there is to it, now you can save comments related to any other model record!

Comments
It's good article, but why we must added 'foreign_id' handle?
We write in $hasMany property...
A Comment can be related to any other model.
For example Event 123 could have a comment which would look like this:
INSERT INTO comments ('class','foreign_id','name','body') VALUES ('Event',123,'title','comment body');
Or Post 456 may have a comment which would look like this:
INSERT INTO comments ('class','foreign_id','name','body') VALUES ('Post',456,'another title','another comment body');
When you define the foreign_id in the Post or Event model, this is used for finding data, not for saving data.
In order to save the comment to the right record you need to define a Comment.class and Comment.foreign_id.
Hope this helps to explain it.
It is very useful. But if there is some explanation in a written text. it will be more useful to know who doesn't have program knowledge.
sorry for the short description. the code is not very long, i didnt have much time when i published it but I am planning on coming back and expanding the descriptions.
Post new comment