Script de classificação por estrelas usando PHP e MySQL com AJAX

Como você sabe a opinião dos seus leitores ou clientes sobre o conteúdo do seu site? O recurso de classificação por estrelas ajuda a coletar as opiniões dos clientes!

A classificação por estrelas é um recurso usado em diferentes sites e de várias maneiras. Por exemplo, é um dos principais blocos de construção de um site de comércio eletrônico.

A classificação por estrelas ajuda você a saber como as pessoas classificam seu conteúdo e traz mais leitores para sua página pela classificação obtida.

Quando você constrói um website, se você tem espaço para implementar um sistema de classificação por estrelas você definitivamente deveria experimentá-lo.

Os sites usam uma variedade de maneiras para permitir que os usuários classifiquem o conteúdo. Por exemplo, classificação por estrelas, classificação de cima para baixo, classificação de emoji entre outros.

Vimos muitos exemplos de classificação por estrelas, classificação emoji… Agrupei todos aqueles neste único exemplo.

Apoiei três alternativas de UI (Interface do Usuário) para a seção de classificação. Esses são:

  • Avaliação de cinco estrelas – (star)
  • Avaliação favorita – (favourite)
  • Avaliação de emoji – (emoji)

Eu criei uma diretiva em PHP para configurar o modelo para a aparência da classificação.

Plug-ins existentes para implementar uma classificação por estrelas dinâmica

Existem vários plug-ins disponíveis no mercado para permitir a classificação por estrelas. Os plug-ins prontos possuem recursos enormes.

Por exemplo, Rateit é um plugin de classificação por estrelas baseado em jQuery. Ele permite a incorporação de uma classificação por estrelas com uma lista, selecione e mais marcações HTML. Ele suporta Font Awesome, Material icons para exibir ícones de classificação.

UpvoteJS é um pacote JavaScript para renderizar um widget de classificação do tipo StackExchange.

Se você tiver um site WordPress, existem plug-ins de classificação integrados disponíveis. kk Star Ratings é um plugin popular para implementar a classificação.

Vantagens de criar um script de classificação por estrelas personalizado

Com uma classificação por estrelas personalizada, podemos simplificar a lógica do código em vez de encher demais.

E assim, vai facilitar na hora da fase de ampliação ou manutenção.

Ele corrige sua sobrecarga com um built-in repleto de recursos. Além disso, reduz seu esforço em gerenciar mil linhas de código para esse recurso simples da UI (Interface do Usuário).

Vários tipos de opções de classificação

Os sites usam um tipo diferente de opções de classificação para obter as avaliações dos usuários. A lista a seguir mostra alguns dos tipos.

  • Avaliação com uma ou várias estrelas
  • Avaliação de emojis semelhantes ao Facebook
  • Votação simples de cima para baixo.
  • Avaliação semelhante-diferente
  • Avaliação da barra

Os tipos são verdadeiros na mentalidade do usuário durante a classificação. Por exemplo, a classificação igual-diferente e cima-baixo seta as opções binárias 0 ou 1 do usuário. Mas com a classificação de barra, pode ter uma faixa de pontos fora de algum limite.

Exemplo de classificação por estrelas com AJAX

Eu criei um código de exemplo de classificação por estrelas baseado em AJAX com PHP e jQuery.

Este código mostrará uma lista de cursos com uma opção para avaliar cada curso. Os cursos vão estar no banco de dados.

O elemento de classificação na UI (Interface do Usuário) é configurável. Eu forneci três alternativas de UI (Interface do Usuário) para a seção de classificação. Uma das opções de avaliações por estrelas, favoritos ou emojis poderão ser usadas para coletar as avaliações dos usuários.

Ao adicionar a classificação, o código a envia para o PHP via AJAX. Em seguida, ele salva as classificações no banco de dados MySQL.

Depois de avaliado, o usuário não pode alterar uma avaliação novamente para evitar avaliações duplicadas.

A figura a seguir mostra a estrutura de pastas e arquivos do script de exemplo.

O banco de dados de exemplo de classificação

Esta seção mostra a estrutura e o SQL do banco de dados usado neste exemplo.

Eu criei duas tabelas tbl_courses e tbl_course_rating . A tabela do banco de dados tbl_cources contém cursos nos quais o usuário adicionará classificações.

A tabela tbl_cource_rating possui o mapeamento com o banco de dados tbl_cource. Possui uma classificação única sem duplicatas.

O script a seguir mostra a instrução CREATE e o dump de dados para essas duas tabelas. Ao importar este script, você pode configurar este exemplo no ambiente local.

sql/db_rating.sql

--
-- Banco de dados: `db_rating`
--

-- --------------------------------------------------------

--
-- Estrutura da tabela `tbl_course`
--

CREATE TABLE `tbl_course` (
  `id` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `description` varchar(255) NOT NULL,
  `period` varchar(255) NOT NULL,
  `availabe_seats` int(11) NOT NULL,
  `last_date_to_register` date NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

--
-- Extraindo dados da tabela `tbl_course`
--

INSERT INTO `tbl_course` (`id`, `name`, `description`, `period`, `availabe_seats`, `last_date_to_register`) VALUES
(1, 'Treinamento Profissional para Analista TI', 'Treinamento Profissional para Analista TI', '30 dias\r\n', 2, '2020-01-31'),
(2, 'Programação Empresarial em Inteligência Artificial', 'Programação Empresarial em Inteligência Artificial', '30 dias', 2, '2020-01-24');

-- --------------------------------------------------------

--
-- Estrutura da tabela `tbl_course_rating`
--

CREATE TABLE `tbl_course_rating` (
  `id` int(11) NOT NULL,
  `course_id` int(11) NOT NULL,
  `member_id` int(11) NOT NULL,
  `rating` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

--
-- Índices para tabelas despejadas
--

--
-- Índices para tabela `tbl_course`
--
ALTER TABLE `tbl_course`
  ADD PRIMARY KEY (`id`);

--
-- Índices para tabela `tbl_course_rating`
--
ALTER TABLE `tbl_course_rating`
  ADD PRIMARY KEY (`id`),
  ADD KEY `course_id` (`course_id`);

--
-- AUTO_INCREMENT de tabelas despejadas
--

--
-- AUTO_INCREMENT de tabela `tbl_course`
--
ALTER TABLE `tbl_course`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;

--
-- AUTO_INCREMENT de tabela `tbl_course_rating`
--
ALTER TABLE `tbl_course_rating`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=11;

--
-- Restrições para despejos de tabelas
--

--
-- Limitadores para a tabela `tbl_course_rating`
--
ALTER TABLE `tbl_course_rating`
  ADD CONSTRAINT `tbl_course_rating_ibfk_1` FOREIGN KEY (`course_id`) REFERENCES `tbl_course` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
COMMIT;

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

Design da UI (Interface do Usuário) para renderizar a opção de classificação por estrelas

Em uma página de entrada, mostra a lista de cursos do banco de dados. O código HTML para esta página está abaixo.

Ele carrega o elemento de classificação com base na constante PHP definida em um arquivo de configuração comum.

O elemento de avaliação mostrará 5 estrelas clicáveis, ícones favoritos ou ícones emoji.

Ao clicar no elemento de classificação, ele invoca um script jQuery para enviar solicitações AJAX para salvar classificações.

index.php

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Script de classificação por estrelas em PHP</title>
<link href="./assets/css/comodev-style.css" type="text/css"
	rel="stylesheet" />
<link href="./assets/css/star-rating-style.css" type="text/css"
	rel="stylesheet" />
<script src="./vendor/jquery/jquery-3.3.1.js" type="text/javascript"></script>
</head>

<body>
	<div class="comodev-container">
		<div class="container">
			<h2>Script de classificação por estrelas em PHP</h2>
			<div id="course_list">
			<?php require_once "getRatingData.php"; ?>
			</div>
		</div>
	</div>
	<script src="./assets/js/rating.js"></script>
</body>
</html>

Criei arquivos de modelo separados para ter diferentes tipos de UI (Interface do Usuário) de classificação. Esses são star-rating-view.php , favorite-rating-view.php e emoji_rating_view.php.

Os arquivos de modelo mostram a especificação de manipulação de eventos onClick na marcação.

star-rating-view.php

<?php
for ($count = 1; $count <= 5; $count ++) {
    $starRatingId = $row['id'] . '_' . $count;
    if ($count <= $userRating) {
        ?>
<li value="<?php echo $count; ?>" id="<?php echo $starRatingId; ?>"
    class="star"><img src="./img/<?php echo $apperance; ?>-filled.png"></li>
<?php
    } else {
        ?>
<li value="' . $count; ?>" id="<?php echo $starRatingId; ?>"
    class="star"
    onclick="addRating(this,<?php echo $row['id']; ?>,<?php echo $count; ?>, 'star');"
    onMouseOver="mouseOverRating(<?php echo $row['id']; ?>,<?php echo $count; ?>,'<?php echo $apperance; ?>');"
    onMouseLeave="mouseOutRating(<?php echo $row['id']; ?>,<?php echo $userRating; ?>,'<?php echo $apperance; ?>');"><img
    src="./img/<?php echo $apperance; ?>-open.png"></li>
<?php
    }
}
?>

favorite-rating-view.php

<?php
for ($count = 1; $count <= 5; $count ++) {
    $starRatingId = $row['id'] . '_' . $count;
    if ($count == $userRating) {
        ?>
<li value="<?php echo $count; ?>" id="<?php echo $starRatingId; ?>"
    class="star"><img src="./img/<?php echo $apperance; ?>-filled.png"></li>
<?php
    } else {
        ?>
<li value="<?php $count; ?>" id="<?php echo $starRatingId; ?>"
    class="star"
    onclick="addRating(this,<?php echo $row['id']; ?>,<?php echo $count; ?>);"
    onMouseOver="mouseOverRating(<?php echo $row['id']; ?>,<?php echo $count; ?>,'<?php echo $apperance; ?>');"
    onMouseLeave="mouseOutRating(<?php echo $row['id']; ?>,<?php echo $userRating; ?>,'<?php echo $apperance; ?>');"><img
    src="./img/<?php echo $apperance; ?>-open.png"></li>
<?php
    }
}
?>

No modelo de classificação de emoji, ele mostra uma variedade de cinco ícones de emoção, de muito triste a muito feliz .

Se você estiver fornecendo suporte nas consultas do usuário, pode usar a classificação de emoji. Incorporar a avaliação de emoji dará a sensação emocional do cliente em seu apoio.

emoji-rating-view.php

<?php
for ($count = 1; $count <= 5; $count ++) {
    $starRatingId = $row['id'] . '_' . $count;
    if ($count == $userRating) {
        ?>
                    <li value="<?php echo $count; ?>" id="<?php echo $starRatingId; ?>"
    class="star"><img src="./img/<?php echo $apperance . $count; ?>-filled.png"></li>
<?php 
                } else {
?>
                    <li value="<?php $count; ?>" id="<?php echo $starRatingId; ?>"
    class="star"
    onclick="addRating(this,<?php echo $row['id']; ?>,<?php echo $count; ?>);"
    onMouseOver="mouseOverRating(<?php echo $row['id']; ?>,<?php echo $count; ?>,'<?php echo $apperance; ?>');"
    onMouseLeave="mouseOutRating(<?php echo $row['id']; ?>,<?php echo $userRating; ?>,'<?php echo $apperance; ?>');"><img
    src="./img/<?php echo $apperance . $count; ?>-open.png"></li>
<?php 
                }
            }
?>

Estilos CSS criados para a UI (Interface do Usuário) de classificação por estrelas

assets/css/star-rating-style.css

ul {
	margin: 0px;
	padding: 10px 0px 0px 0px;
	display: inline-flex;
}

li.star {
	list-style: none;
	display: inline-block;
	margin-right: 5px;
	cursor: pointer;
	color: #9E9E9E;
}

.row-title {
	font-size: 20px;
	color: #232323;
}

.review-note {
	font-size: 12px;
	color: #999;
	font-style: italic;
}

.row-item {
	margin-bottom: 20px;
	border-bottom: #F0F0F0 1px solid;
}

p.text-address {
	font-size: 12px;
}

img {
	height: 20px;
	width: 20px;
}

.course-detail {
	font-size: 1em;
	margin-right: 20px;
}

.loader-icon {
	display: none;
}

.response {
    display: inline-block;
    vertical-align: super;
    margin-left: 10px;
    color: #FF0000;
}

Funções jQuery para lidar com a ação de classificação do usuário

Este arquivo contém funções jQuery para preparar solicitações AJAX para salvar avaliações de usuários.

Ele também controla os eventos de passagem do mouse para destacar o elemento deavaliação. A função mouseOverRating() destaca a estrela ou outros elementos de avaliação ao passar o mouse.

Da mesma forma, mouseOutRating() redefine a UI (Interface do Usuário) de classificação de volta à sua forma original ao sair do mouse.

O código AJAX em addRating() prepara a solicitação com a URL do terminal PHP e parâmetros de dados.

Ele recebe a resposta do servidor no retorno de chamada de sucesso do AJAX, no qual atualiza a UI (Interface do Usuário) de acordo.

assets/js/rating.js

function mouseOverRating(courseId, rating, appearance) {
	if (appearance == "star") {
		for (var i = 1; i <= rating; i++) {
			$('#' + courseId + "_" + i + ' img').attr('src',
					"./img/" + appearance + "-filled.png");
		}
	} else {
		ratingIconPrefix = "./img/" + appearance;
		for (var i = 1; i <= rating; i++) {
			if (appearance == "emoji") {
				ratingIconPrefix = "./img/" + appearance + "1";
			}
			if (i == rating) {
				$('#' + courseId + "_" + i + ' img').attr('src',
						ratingIconPrefix + "-filled.png");
			}
		}
	}
}

function mouseOutRating(courseId, userRating, appearance) {
	var ratingId;
	if (appearance == "star") {
		if (userRating != 0) {
			for (var i = 1; i <= userRating; i++) {
				$('#' + courseId + "_" + i + ' img').attr('src',
						"./img/" + appearance + "-filled.png");
			}
		}
		if (userRating <= 5) {
			for (var i = (userRating + 1); i <= 5; i++) {
				$('#' + courseId + "_" + i + ' img').attr('src',
						"./img/" + appearance + "-open.png");

			}
		}
		$(".selected img").attr('src', "./img/" + appearance + "-filled.png");
	} else {
		ratingIconPrefix = "./img/" + appearance;

		if (userRating <= 5) {
			for (var i = 1; i <= 5; i++) {
				if (appearance == "emoji") {
					ratingIconPrefix = "./img/" + appearance + i;
				}
				if (userRating == i) {
					$('#' + courseId + "_" + i + ' img').attr('src',
							ratingIconPrefix + "-filled.png");
				} else {
					$('#' + courseId + "_" + i + ' img').attr('src',
							ratingIconPrefix + "-open.png");
				}
			}
		}
		var selectedImageSource = $(".selected img").attr('src');
		if (selectedImageSource) {
			selectedImageSource = selectedImageSource.replace('open', "filled");
			$(".selected img").attr('src', selectedImageSource);
		}
	}

}

function addRating(currentElement, courseId, ratingValue, appearance) {
	var loaderIcon = $(currentElement).closest(".row-item");

	$.ajax({
		url : "ajax-end-point/insertRating.php",
		data : "index=" + ratingValue + "&course_id=" + courseId,
		type : "POST",
		beforeSend : function() {
			$(loaderIcon).find("#loader-icon").show();
		},
		success : function(data) {
			loaderIcon = $(currentElement).closest(".row-item");
			$(loaderIcon).find("#loader-icon").hide();
			if (data != "") {
				$('#response-' + courseId).text(data);
				return false;
			}
			if (appearance == 'star') {
				$('#list-' + courseId + ' li').each(
						function(index) {
							$(this).addClass('selected');
							if (index == $('#list-' + courseId + ' li').index(
									currentElement)) {
								return false;
							}
						});
			} else {
				$(currentElement).addClass('selected');
			}
		}
	});

}

Armazenamento de classificações de usuários no banco de dados MySQL de PHP

Quando o script AJAX é chamado, ele prepara uma solicitação para o PHP. Em PHP, ele recebe os dados de classificação escolhidos e os armazena no banco de dados de classificação.

Embora a UI (Interface do Usuário) exiba elementos diferentes, o valor da classificação varia de 1 a 5. No banco de dados, há o mapeamento entre o valor da classificação, a id do curso e a id do membro.

A configuração abaixo serve para definir a aparência do elemento de classificação. Os valores possíveis estão lá com uma declaração de comentário.

Common/Config.php

<?php
namespace Comodev;

class Config
{

    // Valores possíveis: star | favourite | emoji
    const RATING_APPEARANCE = "star";
}   

Este é um endpoint PHP chamado via AJAX . Ele insere a classificação do usuário no banco de dados.

Antes de inserir, ele verifica se o usuário já adicionou uma avaliação para aquele determinado curso. Nesse caso, o código não permitirá que o usuário avalie novamente.

ajax-end-point/insertRating.php

<?php
namespace Comodev;

use Comodev\Rating;
require_once __DIR__ . "./../Model/Rating.php";
$rating = new Rating();
// Aqui, o ID do usuário é codificado.
// Você pode integrar seu código de autenticação aqui para obter o ID do usuário conectado
$userId = 11;

if (isset($_POST["index"], $_POST["course_id"])) {
    
    $courseId = $_POST["course_id"];
    $ratingIndex = $_POST["index"];
    
    $rowCount = $rating->isUserRatingExist($userId, $courseId);
    
    if ($rowCount == 0) {
        $insertId = $rating->addRating($userId, $courseId, $ratingIndex);
        if (empty($insertId)) {
            echo "Problema ao adicionar classificações.";
        }
    } else {
        echo "Você já adicionou classificação.";
    }
}

Este código lê os cursos e as classificações correspondentes do banco de dados. Ele prepara a marcação HTML incorporada com dados dinâmicos .

Este arquivo exibe a lista de cursos com a opção de classificação em uma página inicial.

getRatingData.php

<?php
namespace Comodev;

use Comodev\Rating;
require_once "./Common/Config.php";
$config = new Config();
require_once "./Model/Rating.php";
$rating = new Rating();
// Aqui, o ID do usuário é codificado.
// Você pode integrar seu código de autenticação aqui para obter o ID de usuário conectado
$userId = 11;

$apperance = $config::RATING_APPEARANCE;

$courseResult = $rating->getCourse();
if (! empty($courseResult)) {
    foreach ($courseResult as $row) {
        $userRating = $rating->getUserRating($userId, $row['id']);
        $totalRating = $rating->getTotalRating($row['id']);
        $date = date_create($row["last_date_to_register"]);
        ?>
<div class="row-item">
    <div class="row-title"><?php echo $row['name']; ?></div>
    <ul class="list-inline" id="list-<?php echo $row['id']; ?>">
 <?php require $apperance . "-rating-view.php"; ?>

        <img src="img/loader.gif" class="loader-icon" id="loader-icon">
    </ul>
    <div class="response" id="response-<?php echo $row['id']; ?>"></div>


    <p class="review-note">Total de avaliações: <?php echo $totalRating; ?></p>
    <p class="text-address">
        <label class="course-detail">Período: <?php echo $row["period"]; ?></label><label
            class="course-detail">Assentos disponíveis: <?php echo $row["availabe_seats"]; ?></label><label
            class="course-detail">Data do Registro: <?php echo date_format($date, "d M Y"); ?></label>
    </p>
</div>
<?php
    }
}
?>

Nos dois arquivos PHP acima, codifiquei a id do usuário com uma variável PHP $userId. Você pode inserir o código de autenticação do usuário e obter o ID do usuário conectado.

Rating.php é uma classe de modelo PHP criada para realizar as ações de classificação.

Ele tem funções para ler cursos e avaliações de usuários sobre eles. As funções getUserRating()getTotalRating() retornam dados para exibir as estatísticas de classificação.

isUserRatingExist() verifica a exclusividade da classificação do usuário em um determinado curso.

Usei instruções preparadas com MySQLi para executar as consultas de banco de dados. A fonte contém uma classe DAO genérica DataSource.php para executar operações de banco de dados.

Model/Rating.php

<?php
namespace Comodev;

use Comodev\DataSource;

class Rating
{

    private $ds;

    function __construct()
    {
        require_once __DIR__ . './../lib/DataSource.php';
        $this->ds = new DataSource();
    }

    function getCourse()
    {
        $query = "SELECT * FROM tbl_course ORDER BY id DESC";
        
        $result = $this->ds->select($query);
        return $result;
    }

    function getUserRating($userId, $courseId)
    {
        $average = 0;
        $avgQuery = "SELECT rating FROM tbl_course_rating WHERE member_id = ? and course_id = ?";
        $paramType = 'ii';
        $paramValue = array(
            $userId,
            $courseId
        );
        $result = $this->ds->select($avgQuery, $paramType, $paramValue);
        if ($result > 0) {
            foreach ($result as $row) {
                $average = round($row["rating"]);
            } // endForeach
        } // endIf
        return $average;
    }

    function getTotalRating($courseId)
    {
        $totalVotesQuery = "SELECT * FROM tbl_course_rating WHERE course_id = ?";
        $paramType = 'i';
        $paramValue = array(
            $courseId
        );
        $result = $this->ds->getRecordCount($totalVotesQuery, $paramType, $paramValue);
        return $result;
    }

    function isUserRatingExist($userId, $courseId)
    {
        $checkIfExistQuery = "select * from tbl_course_rating where member_id = ? and course_id = ?";
        $userId;
        $courseId;
        $paramType = 'ii';
        $paramValue = array(
            $userId,
            $courseId
        );
        $rowCount = $this->ds->getRecordCount($checkIfExistQuery, $paramType, $paramValue);
        return $rowCount;
    }

    function addRating($userId, $courseId, $rating)
    {
        $insertQuery = "INSERT INTO tbl_course_rating(member_id,course_id, rating) VALUES (?,?,?) ";
        
        $paramType = 'iii';
        $paramValue = array(
            $userId,
            $courseId,
            $rating
        );
        $insertId = $this->ds->insert($insertQuery, $paramType, $paramValue);
        return $insertId;
    }
}

Captura de tela de saída das diferentes opções de avaliação com estrela, favorito, emoji:

star
favourite
emoji

Na captura de tela a seguir, ele exibe um texto em vermelho. É uma mensagem de erro para notificar o usuário se ele tentar adicionar a classificação novamente.

Conclusão

Vimos a importância de implementar um script de classificação em um aplicativo. Além disso, vimos os tipos de classificações geralmente usados ​​pelos aplicativos.

Ao oferecer suporte a 3 tipos de componentes de UI (Interface do Usuário) de classificação em um script de exemplo, tenho certeza que ajuda você a ter opções. Você pode escolher e consertar um deles conforme a necessidade.

Por exemplo, se você gerencia mais aplicativos, integre este em todos. A configuração de classificação permite definir com base na natureza do aplicativo.

Não há limite. Podemos aprimorar esse componente adicionando mais opções de classificação como, ao contrário, votação para cima e para baixo, classificação com um ranger e muito mais.