开发者

Cakephp : Multi-Model Comment system

I'm using cakephp, I have a model "comment" with two fields : "model_type" and "model_id" in order to comment every item of my application (eg Picture, News, Article, ...) with a single Comment model.

I wonder how to make this. (A component "Comment" for controller that could be commented ?)

Finally I want to list comment in view just with a helper: $comment->show('model_name', 'item_id'); that would display correctly paginated comments and a form for a开发者_运维百科dding a new comment to the item.

Thanks.


Edit: See this too : http://bakery.cakephp.org/articles/AD7six/2008/03/13/polymorphic-behavior

The Solution

A multi model commenting system and pagination just with :

<?php echo $this->element('comments', 
    array(
        'model_type' => "model_name", 
        'model_id' => $data['model']['id'],
        'order_field' => 'created',
        'order' => 'asc')); ?>

The model

Scheme :

- id
- model_type
- model_id
- content
(optional:)
- user_id
- created
- updated
- rating
- ...

The Comment Model :


// {app}/models/comment.php
class Comment extends AppModel{
    public $name = 'Comment';
    
    // List of model that could be commented
    protected $model_list = array(
        'news' => array(
            'name' => 'News', // here it's the model's name
            'field' => 'validated'), // A field for validation ( allow comments only on validaded items)
        'articles' => array(
            'name' => 'Article',
            'field' => 'validated')
    );
    
        // This is an example
    public $belongsTo = array( 
        'User' => array(
            'conditions' => 'User.validated = true'
            )
        );
    
    public $validate = array(
        'model_type' => array(
            'rule' => 'checkModelType',
            'message' => "Something goes wrong !"
        ),
        'model_id' => array(
            'rule' => 'checkModelId',
            'message' => "Something goes wrong !"
        ),
        'content' => array(
             'rule' => 'notEmpty',        
             'message' => "Empty content !"
         )
    );
    
        // Check if the model is commentable
    public function checkModelType($data){
        $model_type = $data['model_type'];
        return in_array($model_type, array_keys($this->model_list));
    }
    
        // Check if the item exists and is validated
    public function checkModelId($data){
        $model_id = intval($data['model_id']);
        
        $model = $this->model_list[$this->data['Comment']['model_type']];
                
        $params = array(
            'fields' => array('id', $model['field']),
            'conditions' => array(
                $model['name'].'.'.$model['field'] => 1, // Validated item
                $model['name'].'.id' => $model_id
                )
        );
            
                // Binding model to Comment Model since there is no $belongsTo
        return (bool) ClassRegistry::init($model['name'])->find('first', $params);
    }
}

The Controller


// {app}/controllers/comments_controller.php
class CommentsController extends AppController
{
    public $name = 'Comments';
    
        // Pagination works fine !
    public $paginate = array(
        'limit' => 15,
        'order' => array(            
            'Comment.created' => 'asc')    
        );
    
    // The action that lists comments for a specific item (plus pagination and order !)
    public function view($model_type, $model_id, $order_field = 'created', $order = 'DESC'){
        $conditions = array(
                'Comment.model_type' => $model_type, 
                'Comment.model_id' => $model_id
                );
        
                // (optional)
        if($order_field != 'created') {
            $this->paginate['order'] = array(
                'Comment.'.$order_field => $order,
                'Comment.created' => 'asc');
        }
        
                // Paginate comments
        $comments = $this->paginate($conditions);
                
                // This allow to use paginator with requestAction
        $paginator = ClassRegistry::getObject('view')->loaded['paginator'];
        $paginator->params = $this->params;
        return compact('comments', 'paginator');
    }

    public function add(){
        // What you want !
    }
}

The views

Comments element

/* {app}/views/elements/comments.ctp
@params : $model_type
*   : $model_id
* 
* */

$result = $this->requestAction("/comments/view/$model_type/$model_id/$order_field/$order/", $this->passedArgs);
$paginator = $result['paginator'];
$comments = $result['comments'];

$paginator->options(array('url' => $this->passedArgs));
?>
<h2>Comments</h2>

<fieldset class="commentform">
<legend>Add un commentaire</legend>
<?php
    // Form
    echo $form->create('Comment', array('action' => 'add'));
    echo $form->hidden('model_type', array('value' => $model_type));
    echo $form->hidden('model_id', array('value' => $model_id));
    echo $form->input('content');
<?php
    echo $form->end('Send');
?>
</fieldset>
<div class="paginationBar">
    <?php
        echo $paginator->prev('<<  ', null, null, array('class' => 'disabled'));
        echo '<span class="pagination">',$paginator->numbers(),'</span>';
        echo $paginator->next('  >>', null, null, array('class' => 'disabled'));
    ?>
</div>
<?php
    foreach($comments as $comment){
        echo $this->element('comment', array('comment' => $comment));
    }
?>
<div class="paginationBar">
    <?php
        echo $paginator->prev('<<  ', null, null, array('class' => 'disabled'));
        echo '<span class="pagination">',$paginator->numbers(),'</span>';
        echo $paginator->next('  >>', null, null, array('class' => 'disabled'));
    ?>
    
    <p><br />
    <?php
        echo $paginator->counter(array('format' => 'Page %page% on %pages%, displayi  %current% items of %count%'));
    ?>
    </p>
</div>

Comment element

//{app}/views/elements/comment.ctp
// A single comment view
$id = $comment['Comment']['id'];
?>
<div class="comment">
<p class="com-author">
<span class="com-authorname"><?=$comment['User']['name']?>&nbsp;</span>
<span class="com-date">(<?=$comment['Comment']['created']?>)</span>
</p>
<p class="com-content"><?=$comment['Comment']['content']?></p>
</div>


hm... it would be pretty complicated if you want to display paginated comments like that. You should use lazy loading: don't actually load the comments until the user click on it or something.

You should probably make an element. you can pass model_name and model_id to it. And in the element, you can create a comment 'widget' that can directly send the comment to your comments controller, using ajax; and load the paginated comments using ajax also.


Check out this plugin (it's actually a component) developed by CakeDC.

You could either implement that or, use that to create your own solution.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜