Yii: Добавляем рейтинг статей CStarRating с возможностью оценивать статью зарегистрированным пользователям

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>&nbsp;&nbsp; '.$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>&nbsp;&nbsp;оцените статью</span>';}
					?>
		</div>
		<?php
					$cs = Yii::app()->getClientScript();
					$cs->registerScriptFile('/js/rating.js');
		?>
Вызывается в 'callback' функция SetRating(value, article), которая находится в js/rating.js (см. ниже) и ей передаются id статьи и оценка пользователя ( от 1 до 5)

4) В модель Article добавляем

/**
     * 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>';
    }
5) В контроллер ArticleController.php
/**
     * 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;}



Источник: loco.ru

Комментарии (1)  

1 комментарий

#414
Виктор говорит:
April 4, 2012 at 12:54 pm
Супер!! Работает!

Leave a Comment

Fields with * are required.

Картинка с кодом валидации
Пожалуйста введите символы с картинки. Регистр букв неважен.