В прошлой статье я показывал как можно сделать лайки и дизлаки для новостей. Тема использования ajax весьма актуальна, и поэтому я решил написать еще одну статью о применении ajax.
В этой статье приведен пример создания рейтинга для новостей. Пользователь сможет оценивать запись по шкале от 1 до 5.
Для работы скрипта создадим базу данных с тремя таблицами — пользователи, новости и связь пользователя с голосом. Последняя таблица нужна для того, чтобы делать ограничение по голосования — один пользователь может проголосовать только один раз за статью. Чтобы создать таблицы и наполнить их тестовыми данными можно воспользоваться патчем:
-- Создание таблицы с новостями
CREATE TABLE IF NOT EXISTS `news` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`small_text` varchar(255) NOT NULL,
`big_text` text NOT NULL,
`date_create` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`is_active` tinyint(1) NOT NULL,
`rating` float NOT NULL,
`count_votes` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- Заполнение новостей
INSERT INTO `news` (`id`, `title`, `small_text`, `big_text`, `date_create`, `is_active`, `rating`, `count_votes`) VALUES
(1, 'Новость 1', 'короткое описание 1', 'полный текст', '2014-01-24 17:15:38', 1, 0, 0),
(2, 'Новость 2', 'короткое описание 2', 'полный текст', '2014-01-24 17:15:34', 1, 0, 0),
(3, 'Новость 3', 'короткое описание 3', 'полный текст', '2014-01-24 17:14:47', 1, 0, 0);
-- Создание таблицы для пользователей
CREATE TABLE IF NOT EXISTS `users` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`login` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
-- Создаем тестового пользователя
INSERT INTO `users` (`id`, `login`, `password`) VALUES (1, 'test', 'pass');
-- Таблица для связей пользователей с голосами
CREATE TABLE IF NOT EXISTS `votes_news2user` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`id_user` int(10) NOT NULL,
`id_news` int(10) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
Теперь создадим страницу для вывода новостей и добавим на нее кнопки для голосования
<style>
#num_vote{
display: block;
border: 1px dotted;
cursor: pointer;
float: left;
width: 20px;
height: 10px;
}
#num_vote:hover{
border: 1px solid;
background-color: #FF0000;
}
.current_vote{
background-color: #00FF00;
}
</style>
<?php
// подключение к бд
include "db_connection.php";
$userId = 1; // id пользователя
// достаем все новости
$sql = mysql_query("
SELECT * FROM `news`
") or die(mysql_error());
$news = array();
while($r = mysql_fetch_array($sql, MYSQL_ASSOC)){
$news[] = $r;
}
?>
<div>
<input type="hidden" id="id_user" value="<?=$userId;?>" />
<?php foreach($news as $oneNews){ ?>
<div class="one_news">
<h3><?=$oneNews['title'];?></h3>
<p><?=$oneNews['title'];?></p>
<div id="votes">
Rating: <b><?=($oneNews['count_votes'] == 0) ? "Нет оценок" : $oneNews['rating'] . " Голосов: " . $oneNews['count_votes']; ?></b>
<br/>
<span <?=($oneNews['rating']>=1) ? 'class="current_vote" current="1"' : 'current="0"';?> id="num_vote" num_vote="1" ></span>
<span <?=($oneNews['rating']>=2) ? 'class="current_vote" current="1"' : 'current="0"';?> id="num_vote" num_vote="2" ></span>
<span <?=($oneNews['rating']>=3) ? 'class="current_vote" current="1"' : 'current="0"';?> id="num_vote" num_vote="3" ></span>
<span <?=($oneNews['rating']>=4) ? 'class="current_vote" current="1"' : 'current="0"';?> id="num_vote" num_vote="4" ></span>
<span <?=($oneNews['rating']>=5) ? 'class="current_vote" current="1"' : 'current="0"';?> id="num_vote" num_vote="5" ></span>
<input type="hidden" id="id_news" value="<?=$oneNews['id'];?>" />
<input type="hidden" id="count_votes" value="<?=$oneNews['count_votes'];?>" />
<input type="hidden" id="rating" value="<?=$oneNews['rating'];?>" />
</div>
</div>
<hr/>
<?php } ?>
</div>
Код скрипта для подключения к базе данных храниться в файле db_connection.php. Вот его код:
define("HOST", "localhost");
define("USER", "root");
define("PASSWORD", "");
define("DB_NAME", "test_db");
$db_connect = mysql_connect(HOST, USER, PASSWORD, TRUE);
mysql_selectdb(DB_NAME,$db_connect);
mysql_set_charset('utf8');
Теперь составим скрипт, который будет обрабатывать аякс запросы и если нужно, то делать записи в базу данных или выводить сообщения об ошибках. Назовем его ajax_test.php:
// подключение к бд
include "db_connection.php";
// контейнер для ошибок
$error = false;
// получение данных
$userId = (int) $_POST['id_user'];
$newsId = (int) $_POST['id_news'];
$count = (int) $_POST['count'];
// проверяем, голосовал ранее пользователь за эту новость или нет
$sql = mysql_query("
SELECT count(*) FROM `votes_news2user` WHERE `id_user` = $userId AND `id_news` = $newsId
") or die(mysql_error());
$result = mysql_fetch_row($sql);
// если что-то пришло из запроса, значит уже голосовал
//var_dump($result);exit;
if($result[0] > 0){
$error = 'Вы уже голосовали';
}else{ // если пользователь не голосовал, проголосуем
// делаем запись о том, что пользователь проголосовал
mysql_query("
INSERT INTO `votes_news2user` (`id_user`, `id_news`) VALUES ($userId, $newsId)
") or die(mysql_error());
// делаем запись для новости - увеличиваем количесво голосов и количество проголосовавших
mysql_query("
UPDATE `news` SET `rating` = (`rating` * `count_votes` + $count) / (`count_votes` + 1), `count_votes` = `count_votes` + 1 WHERE `id` = $newsId
") or die(mysql_error());
}
// делаем ответ для клиента
if($error){
// если есть ошибки то отправляем ошибку и ее текст
echo json_encode(array('result' => 'error', 'msg' => $error));
}else{
// если нет ошибок сообщаем об успехе
echo json_encode(array('result' => 'success'));
}
И наконец напишем javascript, который будет отправлять ajax запросы к скрипту ajax_test.php, а также этот скрипт будет отвечать за некоторые эффекты при наведении на кнопки голосования:
$(document).ready(function() {
$('span#num_vote').click(function(){
var count = parseInt($(this).attr('num_vote'));
setVote(count, $(this));
});
// Визуализация выбора рейтинга
// при наведении подсвечиваем нужное количество блоков
$('span#num_vote').hover(
function () {
var countSpan = $(this).parent().find('span#num_vote').length - 1;
var num_vote = parseInt($(this).attr('num_vote'));
for(i = 0; i <= countSpan; i++){
if((num_vote-1) >= i){
$(this).parent().find('span#num_vote').eq(i).addClass('current_vote');
}else{
$(this).parent().find('span#num_vote').eq(i).removeClass('current_vote');
}
}
},
function () {
var countSpan = $(this).parent().find('span#num_vote').length - 1;
for(i = 0; i <= countSpan; i++){
var element = $(this).parent().find('span#num_vote').eq(i);
var current = parseInt(element.attr('current'));
if(current == 1){
element.addClass('current_vote');
}else{
element.removeClass('current_vote');
}
}
}
);
});
// count - тип голоса. Лайк или дизлайк
// element - кнопка, по которой кликнули
function setVote(count, element){
// получение данных из полей
var id_user = $('#id_user').val();
var id_news = element.parent().find('#id_news').val();
$.ajax({
// метод отправки
type: "POST",
// путь до скрипта-обработчика
url: "/ajax_test.php",
// какие данные будут переданы
data: {
'id_user': id_user,
'id_news': id_news,
'count': count
},
// тип передачи данных
dataType: "json",
// действие, при ответе с сервера
success: function(data){
// в случае, когда пришло success. Отработало без ошибок
if(data.result == 'success'){
// Выводим сообщение
alert('Голос засчитан');
// увеличим визуальный счетчик (текст)
var count_votes = parseInt(element.parent().find('#count_votes').val());
var rating = element.parent().find('#rating').val();
var new_rating = ((rating * count_votes) + count) / (count_votes + 1);
var new_html = new_rating.toFixed(5) + " Голосов: " + (count_votes + 1);
element.parent().find('b').html(new_html);
// увеличим визуальный счетчик (зеленые блоки)
var floor_rating = Math.floor(new_rating);
for(i = 0; i <= 4; i++){
var element_span = element.parent().find('span#num_vote').eq(i);
if((floor_rating-1) >= i){
element_span.addClass('current_vote');
element_span.attr('current', 1);
}else{
element_span.removeClass('current_vote');
element_span.attr('current', 0);
}
}
}else{
// вывод сообщения об ошибке
alert(data.msg);
}
}
});
}
Вот и все, на этом создания рейтинга закончен. Напоследок хочу обратить внимание, что для работы с ajax я использовал библиотеку jQuery, поэтому вам тоже придется ее подключать, если хотите использовать этот код.
Архив со скриптами и дампом базы данных можете скачать тут.

(45 оценок, среднее: 4,20 из 5)
Здравствуйте! Отличный сайт, много хороших скриптов. Взял Ваш скрипт и немного переделал для своего сайта, пользуюсь с удовольствием. Спасибо большое!
Всегда пожалуйста :)
Здравствуйте!
А можно как-то сделать так, чтобы на главной (например) выводились только результаты рейтинга, т.е. без возможности проголосовать? Ну а в самой статье — всё как тут сделано.
Создал базу, сделал импорт, подключил.
залил файлы из архива на сервер, но ajax и запись в базу не работает.
P.S. у вас отладке
Привет. Спасибо за скрипт. Все работает, но есть вопрос. Как на одной странице новости отобразить рейтинг только для этой конкретной страницы, не отображая рейтинг всех новостей?
Спасибо.