Yii 1.1.16项目多页面评论功能实现方案咨询
当然用Yii Widget统一实现!别写重复代码!
听我一句劝,绝对别去写5个重复的评论表单——Yii的Widget就是专门解决这种重复代码场景的神器,不仅能帮你省掉大量冗余工作,后续维护起来也省心太多!下面给你一步步拆解怎么实现:
第一步:创建评论模型与数据表
首先先搞定评论的数据存储:
创建
comment数据表,字段大概需要这些:id(主键自增)content(评论内容,文本类型)model_type(关联的模型名称,比如Article/Product,用来区分属于哪个控制器的模型)model_id(关联模型的ID,对应具体的文章/产品等实例)created_at(评论时间)user_id(评论用户ID,可选,根据你的登录逻辑来)
生成对应的
Comment模型,在模型的rules()里添加验证规则:public function rules() { return array( array('content, model_type, model_id', 'required'), array('user_id', 'numerical', 'integerOnly'=>true), array('model_type', 'length', 'max'=>50), array('created_at', 'safe'), ); }还可以在
beforeSave()里自动填充created_at和user_id:protected function beforeSave() { if(parent::beforeSave()){ if($this->isNewRecord){ $this->created_at = date('Y-m-d H:i:s'); $this->user_id = Yii::app()->user->id; // 如果用户已登录 } return true; } return false; }
第二步:创建评论Widget
在protected/components/目录下新建CommentWidget.php,这是核心的复用组件:
class CommentWidget extends CWidget { // 接收外部传入的参数:关联模型类型和ID public $modelType; // 比如"Article" public $modelId; // 比如文章ID public function init() { parent::init(); // 校验参数是否传入,避免出错 if(empty($this->modelType) || empty($this->modelId)){ throw new CException('必须传入modelType和modelId参数'); } } public function run() { // 实例化评论模型,用于表单提交 $commentModel = new Comment(); // 如果是POST提交,处理评论保存 if(isset($_POST['Comment'])){ $commentModel->attributes = $_POST['Comment']; // 手动赋值关联的模型类型和ID $commentModel->model_type = $this->modelType; $commentModel->model_id = $this->modelId; if($commentModel->save()){ // 保存成功后,清空表单或者跳转回原页面 Yii::app()->user->setFlash('commentSuccess', '评论提交成功!'); $commentModel = new Comment(); // 重置模型,清空表单 } } // 渲染视图,把模型和参数传过去 $this->render('commentWidgetView', array( 'commentModel' => $commentModel, 'modelType' => $this->modelType, 'modelId' => $this->modelId, 'comments' => $this->getComments(), // 获取该模型下的所有评论 )); } // 辅助方法:获取当前模型下的所有评论 private function getComments() { return Comment::model()->findAll(array( 'condition' => 'model_type=:type AND model_id=:id', 'params' => array(':type'=>$this->modelType, ':id'=>$this->modelId), 'order' => 'created_at DESC', )); } }
然后在protected/components/views/目录下新建commentWidgetView.php(Widget的视图文件),写评论列表和表单:
<!-- 显示评论成功提示 --> <?php if(Yii::app()->user->hasFlash('commentSuccess')): ?> <div class="alert alert-success"> <?php echo Yii::app()->user->getFlash('commentSuccess'); ?> </div> <?php endif; ?> <!-- 评论列表 --> <div class="comments-list"> <h4>评论列表</h4> <?php if(empty($comments)): ?> <p>暂无评论,快来抢沙发!</p> <?php else: ?> <?php foreach($comments as $comment): ?> <div class="comment-item"> <p><?php echo CHtml::encode($comment->content); ?></p> <small>评论于:<?php echo $comment->created_at; ?></small> <!-- 如果有用户信息,可以显示用户名 --> <?php if($comment->user): ?> <small>评论者:<?php echo CHtml::encode($comment->user->username); ?></small> <?php endif; ?> </div> <?php endforeach; ?> <?php endif; ?> </div> <!-- 评论表单 --> <div class="comment-form"> <h4>发表评论</h4> <?php if(Yii::app()->user->isGuest): ?> <p>请先<a href="<?php echo Yii::app()->createUrl('site/login'); ?>">登录</a>后发表评论</p> <?php else: ?> <?php echo CHtml::beginForm(); ?> <?php echo CHtml::activeTextArea($commentModel, 'content', array('rows'=>5, 'cols'=>50)); ?> <?php echo CHtml::error($commentModel, 'content'); ?> <br> <?php echo CHtml::submitButton('提交评论', array('class'=>'btn btn-primary')); ?> <?php echo CHtml::endForm(); ?> <?php endif; ?> </div>
第三步:在各个视图中调用Widget
现在你只需要在每个控制器对应的视图底部,加上一行代码就行,比如:
- 文章视图(
views/article/view.php):<?php $this->widget('CommentWidget', array( 'modelType' => 'Article', 'modelId' => $model->id, )); ?> - 产品视图(
views/product/view.php):<?php $this->widget('CommentWidget', array( 'modelType' => 'Product', 'modelId' => $model->id, )); ?>
以此类推,其他3个控制器的视图也这么加,完全不用重复写表单代码!
可选优化:AJAX提交评论
如果想让评论提交不用刷新页面,可以把表单改成AJAX提交,在Widget的视图里把submitButton换成ajaxSubmitButton:
<?php echo CHtml::ajaxSubmitButton('提交评论', Yii::app()->createUrl('comment/create'), array( 'type' => 'POST', 'dataType' => 'json', 'success' => 'function(data){ if(data.status === "success"){ $(".alert-success").show().text(data.msg); $("#Comment_content").val(""); // 还可以刷新评论列表,比如重新加载列表部分 $(".comments-list").load("'.$this->createUrl('comment/list', array('type'=>$modelType, 'id'=>$modelId)).'"); }else{ $(".alert-error").show().text(data.msg); } }', ), array('class'=>'btn btn-primary')); ?>
然后新增CommentController的actionCreate和actionList方法来处理AJAX请求,这样体验会更好。
为什么用Widget而不是重复写表单?
- 代码复用:只写一次表单和逻辑,5个视图直接调用,后续要改评论样式/规则,只需要改Widget的代码,不用逐个改视图
- 逻辑统一:所有评论的提交、验证、显示逻辑都在一处,避免出现不同视图的评论功能不一致
- 扩展性强:以后要加评论点赞、回复功能,直接在Widget里扩展就行,不用动多个视图
内容的提问来源于stack exchange,提问作者Shekhar Pandey
相关产品推荐
相关产品推荐

