
С чего начать?
Начало модуль берет из учебного примера Hello world! Найти его не составит труда, качаем и распаковываем в папку. Так как модуль будет работать с базой данных, а стандартная таблица рейтинга нам не подходит, то создадим собственную.

- id — главное поле с автоинкрементом
- nid — уникальное поле хранящее id материала
- like — список id пользователей кому понравилась новость
- dislike — список id пользователей кому не понравилась новость
- rate — общий рейтинг новости
Итак с базой данных разобрались, теперь приступим к самому модулю. Педполагаю что вы уже знаете что такое AJAX, для чего он нужен. Так как в Joomla не предусмотрена возможность использования AJAX модулями то мы восмользуемся фичей которую предлагает Тушов Леонид, а именно создадим файл через который и будут идти все запросы. В результате у нас теперь 2 файла в папке модуля: ajax.php и mod_likerating (он же Hello World!). Теперь пишем для них xml файл инсталлятор и устанавливаем.
<?xml version="1.0" encoding="utf-8"?>
<install type="module" version="1.5.0">
<name>JLikeRating</name>
<author>StyleT</author>
<version>1.0</version>
<description>Модуль голосования для Joomla созданный по принципу нравится/не нравится</description>
<files>
<filename module="mod_likerating">mod_likerating.php</filename>
<filename module="mod_likerating">ajax.php</filename>
</files>
<params>
<param name="suffix" type="text" default="" label="Суффикс класса модуля" description="Позволяет присвоить суффикс классу модуля" />
</params>
</install>
Пишем код модуля
Проверяем вывод модуля и идем дальше. Так как модуль будет выводится в полной версии новости, то выводить мы его будем must have плагином Modules Anywhere с обязательно включенными параметрами Enable parameter overriding, Ignore module state и Enable in components.
К сожалению модуль не знает id открытого в данный момент материала, поэтому мы его передадим в виде параметра используя функцию Parameter overriding плагина Modules Anywhere:
{module 65|newsid=<?php echo $this->article->id; ?>}
65 это id нашего модуля полученный после установки.
Итого код модуля у нас стал вот таким:
<?php
defined('_JEXEC') or die('Restricted access');
$db = JFactory::getDBO();//Подключили БД
$user = JFactory::getUser();//Данные пользователя
$suffix = $params->get("suffix");//Суффикс класса модуля
$newsid = $params->get("newsid");//Получили id новости
if (JRequest::getVar('voteresult')) {
//Работа с AJAX
echo 'hello from AJAX\n'.JRequest::getVar('voteresult');
}
else{
//Вывод кода модуля
?>
<script type="text/javascript">
function myAJAXSendRequest(voteres) {
new Request({
method: 'get',
url: '/modules/mod_likerating/ajax.php',
data: { 'voteresult' : voteres},
onSuccess: function(responseText) {
alert(responseText);},
onFailure: function() {
alert('failed');}
}).send();
}
window.addEvent('domready', function() {//Вешаем события на кнопки
$('likerating-like').addEvent('click', function(e) {myAJAXSendRequest('like');});
$('likerating-dislike').addEvent('click', function(e) {myAJAXSendRequest('dislike');});
});
</script>
<DIV class="likerating<?php echo $suffix; ?>">
<button class="like" type="button" id="likerating-like" >
<span class="label">Нравится</span>
</button><button class="dislike" type="button" id="likerating-dislike">
<span class="label">Не нравится</span>
</button>
</div>
<?php } ?>
Все получилось? Работает? Отлично, теперь разберем этот код по шагам:
1. Плагин Modules Anywhere вызывает модуль и передает ему id новости.
2. Модуль подключает классы и получает параметры.
3. Код «if (JRequest::getVar('voteresult'))» дает false так как ajax запроса не было.
4. Вывод модуля пользователю.
5. Пользователь жмет кнопку Нравится
6. Параметры указанные в data класса Request передаются на указанный url
7. Вызванный ajax.php вызывает модуль
8. Код «if (JRequest::getVar('voteresult'))» и выполнется только часть обработки ajax, сервер отвечает
9. Вызывается onSuccess и обрабатывается ответ сервера.
10. Все это без перезагрузки страницы
Важно отметить что сейчас мы передаем данные в текстовом формате, тогда как new Request.JSON уже работает с форматом JSON что предпочтительнее если принимаем несколько переменных.
Пишем собственно голосование
Итак ниже я привожу полный код модуля голосования для которого все и затевалось.
<?php
defined('_JEXEC') or die('Restricted access');
$db = JFactory::getDBO();//Подключили БД
$user = JFactory::getUser();//Данные пользователя
$suffix = $params->get("suffix");//Суффикс класса модуля
$newsid = $params->get("newsid");//Получили id новости
if (JRequest::getVar('voteresult')) { //Если true работаем с ajax
$voteres= JRequest::getVar('voteresult');//Как пользователь проголосовал
$voted= JRequest::getVar('voted');//Голосовал ли он ранее, и если да, то как 0-нет 1-нравилось 2-не нравилось
$newsid= JRequest::getVar('newsid');//Получили id новости так как плагин Modules Anywhere нас уже не вызывал
$query="UPDATE `#__likerating_news` SET ";
if($voteres=='like')
{
switch($voted)
{
case 1:
$query.="`like`=(SELECT REPLACE(`like`,',".$user->id."','')), `rate`=`rate`-'1'";
$answer= 0;
break;
case 2:
$query.="`like`=(SELECT CONCAT_WS(',', `like`, '".$user->id."')), `rate`=`rate`+'2', `dislike`=(SELECT REPLACE(`dislike`,',".$user->id."',''))";
$answer= 1;
break;
case 0:
$query.="`like`=(SELECT CONCAT_WS(',', `like`, '".$user->id."')), `rate`=`rate`+'1'";
$answer= 1;
break;
}
}else if($voteres=='dislike')
{
switch($voted)
{
case 1:
$query.="`dislike`=(SELECT CONCAT_WS(',', `dislike`, '".$user->id."')), `rate`=`rate`-'2', `like`=(SELECT REPLACE(`like`,',".$user->id."',''))";
$answer= 2;
break;
case 2:
$query.="`dislike`=(SELECT REPLACE(`dislike`,',".$user->id."','')), `rate`=`rate`+'1'";
$answer= 0;
break;
case 0:
$query.="`dislike`=(SELECT CONCAT_WS(',', `dislike`, '".$user->id."')), `rate`=`rate`-'1'";
$answer= 2;
break;
}
}
$query.=" WHERE `nid`='".$newsid."'";
$db->setQuery($query);
$result = $db->loadResult();
echo $answer;
}
else{//Если AJAX запроса не было
//Создаем строку в таблице для новости если она ещё не была создана
$db->setQuery("INSERT INTO #__likerating_news (`nid`, `like`, `dislike`, `rate`) VALUES ('".$newsid."', '0', '0', '0')");
$result = $db->loadResult();
//Голосовал уже или нет? Тут можно сделать более рационально
$db->setQuery("SELECT `like`, `dislike` FROM `#__likerating_news` WHERE `nid`='".$newsid."'");
$result = $db->loadRow();
if(strpos("t".$result[0], $user->id))
$voted= '1';
else if(strpos("t".$result[1], $user->id))
$voted= '2';
else
$voted= '0';
?>
<script type="text/javascript">
var voted= '<?php echo $voted; ?>';//Чтобы не пересчитывать храним переменные в JS
var newsid= '<?php echo $newsid; ?>';//Плагин будет вызываться из ajax.php и нам нужно вручную передать параметр
function myAJAXSendRequest(voteres) {
new Request({
method: 'get',
url: '/modules/mod_likerating/ajax.php',
data: { 'voteresult' : voteres , 'voted' : voted, 'newsid' : newsid},
onSuccess: function(responseText) {
voted= responseText;
if(voted==0){//Смена картинки в кнопке
$('likeratingimg-like').setStyle('background-position', '0px -38px');
$('likeratingimg-dislike').setStyle('background-position', '0px 0px');
}else if(voted==1){
$('likeratingimg-like').setStyle('background-position', '0px -58px');
$('likeratingimg-dislike').setStyle('background-position', '0px 0px');
}else{
$('likeratingimg-like').setStyle('background-position', '0px -38px');
$('likeratingimg-dislike').setStyle('background-position', '0px -19px');
}
//alert(voted);
},
onFailure: function() {//При неудаче выводим сообщение
alert('failed');
}
}).send();
}
window.addEvent('domready', function() {//Вешаем события на кнопки
$('likerating-like').addEvent('click', function(e) {myAJAXSendRequest('like');});
$('likerating-dislike').addEvent('click', function(e) {myAJAXSendRequest('dislike');});
});
</script>
<DIV class="likerating<?php echo $suffix; ?>">
<button class="like" type="button" id="likerating-like" >
<img id="likeratingimg-like" class="hand-image" style="<?php if($voted== '1'){echo 'background-position: 0px -58px;';}?>" src="/modules/mod_likerating/images/pixel.gif">
<span class="label">Нравится</span>
</button><button class="dislike" type="button" id="likerating-dislike">
<img id="likeratingimg-dislike" class="hand-image" style="<?php if($voted== '2'){echo 'background-position: 0px -19px;';}?>" src="/modules/mod_likerating/images/pixel.gif">
</button>
</div>
<?php } ?>
Предполагается что background картинки состоит из спрайта который указан в CSS стиле, а вот написать собственно CSS и будет вашим заданием.
Важно и то что ajax.php трогать не надо вообще, просто ложим его в папку модуля и кидаем на него ajax запросы.
Все наверно заметили что ячейка rated базы данных заполняется и учитывается, но вот значение из неё никуда не идет, да, это так, но никто не мешает вам её использовать.
Результат

Вот что в конечном итоге вышло у меня, функциональность полностью аналогична подобным кнопкам на YouTube, каюсь, временное оформление тоже оттуда. Если кому то потребуется, могу выслать архив с файлами, сейчас времени мало, стучать в Skype
У меня ничего не работает, что делать?
Ниже приведен список полезных ссылок по данной теме:
Временно.НЕТ
Class: Request
My SQL String Functions
Basic AJAX Requests Using MooTools 1.2
От автора
Это мой первый топик на хабре, и надеюсь не последний. Возможно тут сильно подробно всё расписано, однако подробных описаний довольно мало и возникают трудности с которыми сталкивался в свое время и я, думаю эта статья поможет новичку сэкономить пару часов жизни.