Система рейтинга

Материал из Umicms
Перейти к:навигация, поиск

Задача:

Организовать систему рейтинга для объектов системы.

Решение:

Организуем систему рейтинга с использованием jQuery и Ajax на примере объектов каталога. В начале, необходимо отредактировать тип данных "Объект каталога". Зайдите в модуль "Шаблоны данных", найдите тип данных "Объект каталога" и откройте его для редактирования. Нажмите кнопку "Добавить группу" и задайте имя группы, например - "Рейтинг". В созданной группе добавьте два поля типа "Число":

  • "Хороший" (good);
  • "Плохой" (bad).

Rate fields.png

Группа полей "Рейтинг".

Теперь необходимо написать макросы, которые будут работать с данными полями. Откройте файл "/classes/modules/vote/__custom.php" и добавьте код макросов сразу же после строки "//TODO: Write your macroses here".

Листинг 1. Код макросов установки и получения рейтинга

/*
  @title
    Установка рэйтинга объекта
 */
public function setRate() {
  $id = (int)getRequest('id');
  if(!isset($id) || !is_numeric($id))
    throw new publicException('Invalid object ID');
    
  $type = (string)getRequest('type');
  if(!isset($type))
    throw new publicException('Invalid rate type');
    
  $hierarchy = umiHierarchy::getInstance();
  $element = $hierarchy->getElement($id);
  $rate = $element->getValue($type) + 1;
  $element->setValue($type, $rate);
  $element->commit();
  
  echo $rate;
}

/*
  @title
    Получение рэйтинга объекта
  @param Integer
    $id - идентификатор объекта
  @param String
    $type - тип рэйтинга (good/bad)
 */
public function getRate($id, $type) {
  if(!isset($id) || !is_numeric($id))
    throw new publicException('Invalid object ID');
    
  if(!isset($type))
    throw new publicException('Invalid rate type');
    
  $hierarchy = umiHierarchy::getInstance();
  $element = $hierarchy->getElement($id);
  $rate = $element->getValue($type);
  
  return (int)($rate ? $rate : 0);
}

После этого, нужно добавить разрешения для макросов. Создайте файл "/classes/modules/vote/permissions.custom.php" с таким содержимым:

Листинг 2. Разрешения для макросов

<?php
  $permissions = array(
    'post' => array('setRate', 'getRate')
  );
?>

Далее необходимо повесить обработчик на событие "click" для ссылок, по клику на которые будет устанавливаться значение рейтинга. Для этого создайте файл "/js/rate.js" и напишите в него следующий код:

Листинг 3. Обработчик события "click"

jQuery(document).ready(function() {

  jQuery('.vote').click(function() {
    var cid = 'vote' + jQuery(this).attr('id');
    if(jQuery.cookie(cid)) {
      window.alert('Вы уже голосовали!');
      return false;
    }
    
    var self = jQuery(this);
    var parent = jQuery(this).parent();
    
    var id = jQuery(this).attr('id');
    var type = jQuery(this).attr('name');
    var req = 'id=' + id + '&type=' + type;
    var e = '.rate .' + type;
    
    parent.animate({'opacity': 0.3}, 200);
    jQuery.ajax({
      type: 'POST',
      url: '/udata/vote/setRate',
      data: req,
      cache: false,
    })
    .success(function(data) {
      self.html(data);
      parent.animate({'opacity': 1}, 200);
      jQuery.cookie(cid, 'true', {'expires': new Date().getTime() - 1});
    })
    .error(function() {
      window.alert('Ошибка! К сожалению, Ваш голос не будет учтён.');
      jQuery(e).animate({'opacity': 1}, 200);
    });
  });
  
  jQuery('.rate .good').hover(
    function() {
      jQuery(this).css('background-color', '#88D135');
    }, 
    function() {
      jQuery(this).css('background-color', '#4AA735');
    }
  );
  
  jQuery('.rate .bad').hover(
    function() {
      jQuery(this).css('background-color', '#FF7A32');
    }, 
    function() {
      jQuery(this).css('background-color', '#FF2926');
    }
  );
  
});

Событие "click" будет обрабатываться у ссылок с классом "vote". Также в данном коде присутствует обработчики события "hover" для кнопок установки рейтинга. Он срабатывает при наведении курсора мыши и меняет цвет кнопки. По желанию, этот функционал можно удалить.

Осталось задать стиль кнопкам установки рейтинга. Создайте файл "/css/rate.css" со следующим содержимым:

Листинг 4. Файл стилей

.rate,
.good,
.bad
{
  float: left;
}

.rate
{
  margin-left: 50px;
}

.good,
.bad
{
  padding: 4px 12px;
  text-align: center;
  margin: 0 2px;
  border-radius: 5px;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
}

.good a,
.bad a
{
  color: #000;
  font-weight: bold;
  font-size: 15px;
  text-decoration: none;
}

.good
{
  background-color: #4AA735;
}

.bad
{
  background-color: #FF2926;
}

Для примера, подключим панель рейтинга в стандартный XSLT-шаблон UMI.CMS "Интернер-магазин современный" (DemoDizzi). Откройте файл "/xsltTpls/layouts/default.xsl" и подключите созданные файлы "rate.js" и "rate.css" в секции "head" следующим образом:

Листинг 5. Подключение файлов "rate.js" и "rate.css"

<!-- rating -->
<script type="text/javascript" src="/js/rate.js"></script>
<link rel="stylesheet" type="text/css" href="/css/rate.css" />
<!-- /rating -->

После того, как файлы будут подключены, останется отредактировать шаблон вывода информации об объекте каталога. Откройте файл "/xsltTpls/modules/catalog/object-view.xsl" и разместите следующий код после блока "price", чтобы получилось примерно так:

Листинг 6. Размещение панели рейтинга в шаблоне

<!-- Блок "price" -->
<div class="price">
  <span umi:element-id="{page/@id}" umi:field-name="price">
    <xsl:apply-templates select="document(concat('udata://emarket/price/', page/@id))" />
  </span>
</div>

<div class="rate">
  <div class="good">
    <a class="vote" id="{page/@id}" name="good" title="Хороший" href="javascript: void(0);">
      <xsl:value-of select="document(concat('udata://vote/getRate/', page/@id, '/good/'))/udata" />
    </a>
  </div>
  <div class="bad">
    <a class="vote" id="{page/@id}" name="bad" title="Плохой" href="javascript: void(0);">
      <xsl:value-of select="document(concat('udata://vote/getRate/', page/@id, '/bad/'))/udata" />
    </a>
  </div>
</div>

Файл:Rate panel.png

Панель рейтинга.