Yii: Добавляем рейтинг статей CStarRating с возможностью оценивать статью зарегистрированным пользователям
Добавляем звёзды рейтинга для статей с помощью класса CStarRating, чтобы пользователи могли оценить понравившуюся статью. Подробнее про класс CStarRating читаем здесь в документации Yii.
В базе данных MySQL делаем:
1) В таблице статей добавляем поле 'rating' (int(11) с NULL по-умолчанию). Здесь будет общий рейтинг, суммарный от всех пользователь, но "нормированный к сотне" (то есть 5 звёзд соответствуют максимальному значению 500)
2) Создадим дополнительную таблицу 'rating', здесь каждая запись, это оценка конкретного пользователя для конкретной статьи (оценка по звёздам от 1 до 5):
-- -- Структура таблицы `rating` -- CREATE TABLE IF NOT EXISTS `rating` ( `id` int(10) NOT NULL AUTO_INCREMENT, `article_id` int(10) NOT NULL, `user_id` int(10) NOT NULL, `value` tinyint(3) NOT NULL, PRIMARY KEY (`id`), KEY `user_id` (`user_id`), KEY `article_id` (`article_id`,`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ; -- -- Ограничения внешнего ключа сохраненных таблиц -- -- -- Ограничения внешнего ключа таблицы `rating` -- ALTER TABLE `rating` ADD CONSTRAINT `rating_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `tbl_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, ADD CONSTRAINT `rating_ibfk_1` FOREIGN KEY (`article_id`) REFERENCES `tbl_article` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
3) В файл вида подробной статьи добавляем оценку + возможность оценить для зарегистрированного пользователя
<div class="b-rating__with_text">
<?php
$data->ShowRating();
echo '<span> '.$data->marksCount.' '
.CLocoHelper::GetFormatWord('оценка', $data->marksCount).'</span>'
?>
</div>
<div class="b-rating__with_text">
<?php
if (!Yii::app()->user->isGuest){
$this->widget('CStarRating', array(
'name' => 'user-input-rating',
'minRating' => '1',
'maxRating' => '5',
'value' => $data->GetUserRating(), // mark 1...5
'starWidth'=>'15',
'ratingStepSize' => '1',
//'titles'=> CHtml::listData(RatingDesc::model()->cache(3600)->findAll(),'id','desc'),
'allowEmpty'=>false,
'callback' => 'function(value) {SetRating(value, ' . $data->id . ');}',
'cssFile'=>'/css/rating/jquery.rating.css',
));
echo '<span> оцените статью</span>';}
?>
</div>
<?php
$cs = Yii::app()->getClientScript();
$cs->registerScriptFile('/js/rating.js');
?>/**
* Return rating in specific format
* @return string rating in specific format
*/
public function GetFormattedRating()
{
$rating = $this->rating / 100;
$rating = number_format(round($rating * 4) / 4, 2);
$rating = sprintf("%1.2f", $rating);
$rating = trim(rtrim($rating, "0"), '.');
return $rating;
}
/**
* Return user mark for the good
* @return string user mark for the good
*/
public function GetUserRating()
{
$value = Rating::model()->findByAttributes(array(
'article_id' => $this->id,
'user_id' => Yii::app()->user->id,
));
//echo $value;
if (isset($value))
return sprintf("%d", $value->value);
else
return '0';
}
/**
* Show good rating with css styles
*/
public function ShowRating()
{
$good_rating = $this->GetFormattedRating();
echo '<div class="x-rating x-rate-' . round($good_rating * 4) . '"></div>';
}/**
* Set mark for the good by user
* @param $article_id
* @param $rate mark (1-5)
*/
public function actionSetMark($article_id, $rate)
{
if (Yii::app()->user->isGuest) {
echo 'you are not registered user';
return;
}
$user = Yii::app()->user->id;
$rating = Rating::model()->with(array('article', 'article.marksCount'))
->findByAttributes(array(
'article_id' => $article_id,
'user_id' => $user,
));
if (empty($rating)) { // если никто не оценивал статью ещё
if ($rate == 'undefined') {
return;
}
$rating = new Rating;
$rating->article_id = $article_id;
$rating->user_id = $user;
$rating->value = $rate;
if ($rating->save()) {
$good = $rating->article;
$good->rating = round($good->rating + ($rate * 100 - $good->rating) / ($good->marksCount + 1));
$good->save();
echo 'success';
}
else
echo 'fail saving';
} else {
if ($rating->value != $rate) {
if ($rate == 'undefined') {
echo 'rate deleted';
$rating->delete();
return;
}
$old_mark = $rating->value;
$rating->value = $rate;
if ($rating->save()) {
$good = $rating->article;
$good->rating = round($good->rating + ($rate * 100 - $old_mark * 100) / $good->marksCount);
$good->save();
echo 'success';
}
else
echo 'fail saving';
} else
echo 'no need to change';
}
}6) В /js/rating.js
/*
* Send new user choice, then recieve object where define what need to change
* and change selects
*/
function SetRating(value, good) {
$.ajax({
url:"/review/setmark",
type:'GET',
data: "good_id="+good+"&rate=" + value,
success: RatingSet
});
}
function RatingSet(data){
}7) В css/main.css
.x-rating {
float:left;
height:16px;
margin-bottom:0;
margin-left:20px;
margin-right:0;
margin-top:1px;
width:75px;
}
.x-rate-0 {background:url(../css/star0.gif) -75px 0 no-repeat;}
.x-rate-1 {background:url(../css/star1.gif) -75px 0 no-repeat;}
.x-rate-2 {background:url(../css/star2.gif) -75px 0 no-repeat;}
.x-rate-3 {background:url(../css/star3.gif) -75px 0 no-repeat;}
.x-rate-4 {background:url(../css/star0.gif) -60px 0 no-repeat;}
.x-rate-5 {background:url(../css/star1.gif) -60px 0 no-repeat;}
.x-rate-6 {background:url(../css/star2.gif) -60px 0 no-repeat;}
.x-rate-7 {background:url(../css/star3.gif) -60px 0 no-repeat;}
.x-rate-8 {background:url(../css/star0.gif) -45px 0 no-repeat;}
.x-rate-9 {background:url(../css/star1.gif) -45px 0 no-repeat;}
.x-rate-10 {background:url(../css/star2.gif) -45px 0 no-repeat;}
.x-rate-11 {background:url(../css/star3.gif) -45px 0 no-repeat;}
.x-rate-12 {background:url(../css/star0.gif) -30px 0 no-repeat;}
.x-rate-13 {background:url(../css/star1.gif) -30px 0 no-repeat;}
.x-rate-14 {background:url(../css/star2.gif) -30px 0 no-repeat;}
.x-rate-15 {background:url(../css/star3.gif) -30px 0 no-repeat;}
.x-rate-16 {background:url(../css/star0.gif) -15px 0 no-repeat;}
.x-rate-17 {background:url(../css/star1.gif) -15px 0 no-repeat;}
.x-rate-18 {background:url(../css/star2.gif) -15px 0 no-repeat;}
.x-rate-19 {background:url(../css/star3.gif) -15px 0 no-repeat;}
.x-rate-20 {background:url(../css/star0.gif) 0 0 no-repeat;}
1 комментарий
Leave a Comment