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

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

It's good article, but why we must added 'foreign_id' handle?
We write in $hasMany property...

brett's picture

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.

brett's picture

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.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <b> <i> <strong> <cite> <em> <code> <pre> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <css>, <diff>, <drupal5>, <html>, <javascript>, <php>. The supported tag styles are: <foo>, [foo]. PHP source code can also be enclosed in <?php ... ?> or <% ... %>.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.