Ticket-рейтинг пользователей
Добрый день уважаемые дамы и господа. Несколько постов назад поднималась тема Ticket рейтингов, где ребята решили проспонсировать добавление в Tickets такого функционала как сортировка пользователей по количеству опубликованных постов, по количеству написанных комментариев и по количеству просмотров.
Некоторое время назад я тоже интересовался присвоению каждому пользователю рейтинга и очень удивился когда обнаружил что на modx.pro этого нет, несмотря на то, что есть возможность ставить лайки и дизлайки к тикетам и комментариям. Погуглив я нашел причину отсутствия такого рейтинга. Василий отписывал что появится куча недовольных дизлайками и отрицательными рейтингами, будут выяснения кто кому и за что поставил минус и.т.п. Его можно понять, ведь недовольные будут обращаться за разъяснениями и к нему. Я же решил попробовать реализовать подобный функционал на одном тестовом сайте.
Идея заключалась в следующем:
Рейтинг пользователя = (сумма рейтингов тикетов пользователя) + (сумма ретингов комментариев пользователя)/10
Я посчитал, что лайк к посту должен цениться больше чем лайк к комментарию, поэтому лайк к комментарию оценивается как +0.1 к рейтингу пользователя, аналогично с дизлайком.
Так как с разработкой под modx у меня всё очень плохо и рейтинги я не планировал применять на боевых сайтах, принял решение реализовать по принципу «лишь бы работало». Посмотрев структуру базы данных мы обнаруживаем что каждый лайк и дизлайк к тикету и комментарию это соответствющая запись в таблице «tickets_votes» в которой нас интересуют следующие поля:
owner — id пользователя, которому ставится лайк/дизлайк.
class — (TicketComment/Ticket) к чему относится голос — комментарий или тикет.
value — (0,1,-1) нейтральный голос, лайк, дизлайк.
Нам остаётся имея id пользователя вытащить сумму его рейтингов к Тикетам и комметариям, а затем обработать его в зависимости от коэффициента. Не могу сказать, насколько правильно я это сделал, но результат вылился в следующее:
Здесь мы выводим список пользователей из группы «Users», сортируя их по нашему рейтингу. Прежде чем вывести результат мы его подготавливаем при помощи сниппета «prepareUserRating». Ведь нам нужно сложить рейтинг к тикетам и рейтинг к комментариям не забыв про коэффициент:
Чтобы вывести рейтинг конкретного пользователя достаточно совсем немного переработать предыдущий вызов сниппета:
Здесь мы вызываем тот же сниппет pdoUsers, но выводим не всех пользователей, а конкретного — по id (&users=[[!getUserId]]). getUserId — это мой самописный небольшой сниппет, который возвращает id нужного пользователя, его текст приводить не буду, у каждого свои нужды и реализация, принцип должен быть понятен.
Данный способ нельзя назвать корректным. Каждый раз при выводе рейтинга нам придётся его подсчитывать заново, выполняя leftJoin. Пока таблица «tickets_votes» имеет мало записей это может работать нормально, но со временем «tickets_votes» может разрастись до десятков и сотен тысяч записей и каждый раз производить выборку среди них не очень разумно. Поэтому, прежде чем исползовать эти примеры на боевых сайтах, подумайте)
В идеале, для реализации подобных рейтингов необходимо заводить доп. таблицу со связью User-id — TicketRating, где TicketRating у соответствующего пользователя должен обновляться сразу же при лайке/дизлайке. Немного поковыряв js файлы Tickets я нашёл места куда можно впихнуть нужные SQL запросы, но это всё же костыли, которые будут слетать при обновлении компонента, поэтому реализовывать такой вариант я не стал.
Всем добра!
Некоторое время назад я тоже интересовался присвоению каждому пользователю рейтинга и очень удивился когда обнаружил что на modx.pro этого нет, несмотря на то, что есть возможность ставить лайки и дизлайки к тикетам и комментариям. Погуглив я нашел причину отсутствия такого рейтинга. Василий отписывал что появится куча недовольных дизлайками и отрицательными рейтингами, будут выяснения кто кому и за что поставил минус и.т.п. Его можно понять, ведь недовольные будут обращаться за разъяснениями и к нему. Я же решил попробовать реализовать подобный функционал на одном тестовом сайте.
Идея заключалась в следующем:
Рейтинг пользователя = (сумма рейтингов тикетов пользователя) + (сумма ретингов комментариев пользователя)/10
Я посчитал, что лайк к посту должен цениться больше чем лайк к комментарию, поэтому лайк к комментарию оценивается как +0.1 к рейтингу пользователя, аналогично с дизлайком.
Так как с разработкой под modx у меня всё очень плохо и рейтинги я не планировал применять на боевых сайтах, принял решение реализовать по принципу «лишь бы работало». Посмотрев структуру базы данных мы обнаруживаем что каждый лайк и дизлайк к тикету и комментарию это соответствющая запись в таблице «tickets_votes» в которой нас интересуют следующие поля:
owner — id пользователя, которому ставится лайк/дизлайк.
class — (TicketComment/Ticket) к чему относится голос — комментарий или тикет.
value — (0,1,-1) нейтральный голос, лайк, дизлайк.
Нам остаётся имея id пользователя вытащить сумму его рейтингов к Тикетам и комметариям, а затем обработать его в зависимости от коэффициента. Не могу сказать, насколько правильно я это сделал, но результат вылился в следующее:
[[!pdoPage?
&element=`pdoUsers`
&groups=`Users`
&tpl=`tpl.User.info`
&showLog=`1`
&leftJoin=`{"TicketVote":{
"class": "TicketVote",
"on": "modUser.id = TicketVote.owner AND TicketVote.class = 'Ticket'"
},
"TicketVoteComment":{
"class": "TicketVote",
"on": "modUser.id = TicketVoteComment.owner AND TicketVoteComment.class = 'TicketComment'"
}
}`
&select=`{
"modUser": "*",
"TicketVote":"IFNULL(SUM(TicketVote.value),0) as TicketVote",
"TicketVoteComment":"IFNULL(SUM(TicketVoteComment.value),0) as TicketVoteComment"
}`
&groupby=`modUser.id`
&sortby=`{"TicketVote":"desc",
"TicketVoteComment":"desc"
}`
&sortdir=`desc`
&prepareSnippet=`prepareUserRating`
]]
[[!+page.nav]]
Здесь мы выводим список пользователей из группы «Users», сортируя их по нашему рейтингу. Прежде чем вывести результат мы его подготавливаем при помощи сниппета «prepareUserRating». Ведь нам нужно сложить рейтинг к тикетам и рейтинг к комментариям не забыв про коэффициент:
$userRating = $row['TicketVote'] + $row['TicketVoteComment']/10;
if ($userRating>0) { $userRating = '+'.$userRating; $raitingClass = 'UserRatingPositive'; }
elseif ($userRating<0) $raitingClass = 'UserRatingNegative';
else { $userRating='0'; $raitingClass = 'UserRatingNeutral'; }
$row['TicketVote'] = '<span class="'.$raitingClass.'">'.$userRating.'</span>';
return serialize($row);
В зависимости от положительного, отрицательного или нейтрального конечного рейтинга мы его оборачиваем в соответствующий класс. В дальнейшем через CSS сможем положительный рейтинг окрашивать зелёным цветом, а отрицательный — красным. Получаем что-то вроде этого:Вывод рейтинга конкретного пользователя
Чтобы вывести рейтинг конкретного пользователя достаточно совсем немного переработать предыдущий вызов сниппета:
[[!pdoUsers?
&users=`[[!getUserId]]`
&tpl=`tpl.User.info`
&leftJoin=`{"TicketVote":{
"class": "TicketVote",
"on": "modUser.id = TicketVote.owner AND TicketVote.class = 'Ticket'"
},
"TicketVoteComment":{
"class": "TicketVote",
"on": "modUser.id = TicketVoteComment.owner AND TicketVoteComment.class = 'TicketComment'"
}
}`
&select=`{
"modUser": "*",
"TicketVote":"IFNULL(SUM(TicketVote.value),0) as TicketVote",
"TicketVoteComment":"IFNULL(SUM(TicketVoteComment.value),0) as TicketVoteComment"
}`
&groupby=`modUser.id`
&sortby=`{"TicketVote":"desc",
"TicketVoteComment":"desc"
}`
&sortdir=`desc`
&prepareSnippet=`prepareUserRating`
]]
Здесь мы вызываем тот же сниппет pdoUsers, но выводим не всех пользователей, а конкретного — по id (&users=[[!getUserId]]). getUserId — это мой самописный небольшой сниппет, который возвращает id нужного пользователя, его текст приводить не буду, у каждого свои нужды и реализация, принцип должен быть понятен.
Заключение
Данный способ нельзя назвать корректным. Каждый раз при выводе рейтинга нам придётся его подсчитывать заново, выполняя leftJoin. Пока таблица «tickets_votes» имеет мало записей это может работать нормально, но со временем «tickets_votes» может разрастись до десятков и сотен тысяч записей и каждый раз производить выборку среди них не очень разумно. Поэтому, прежде чем исползовать эти примеры на боевых сайтах, подумайте)
В идеале, для реализации подобных рейтингов необходимо заводить доп. таблицу со связью User-id — TicketRating, где TicketRating у соответствующего пользователя должен обновляться сразу же при лайке/дизлайке. Немного поковыряв js файлы Tickets я нашёл места куда можно впихнуть нужные SQL запросы, но это всё же костыли, которые будут слетать при обновлении компонента, поэтому реализовывать такой вариант я не стал.
Всем добра!
Комментарии: 1
Вот именно, что при джоинах всё это адово тормозит.
Настолько, что сейчас даже количество комментариев тикета подсчитывается отдельным запросом, после основного. А считать лайки, дизлайки и просмотры на паре тысяч юзеров, а потом сортировать по ним — это проще самому застрелиться.
Нужны отдельные таблицы, нужны отдельные механизмы для сохранения данных, чистка кода нужна, в конце концов.
Потому и запустили эту тему. Кстати сказать, рейтинги-то мы по-любому сделаем, а вот на уборку кода собрали пока только половину.
Настолько, что сейчас даже количество комментариев тикета подсчитывается отдельным запросом, после основного. А считать лайки, дизлайки и просмотры на паре тысяч юзеров, а потом сортировать по ним — это проще самому застрелиться.
Нужны отдельные таблицы, нужны отдельные механизмы для сохранения данных, чистка кода нужна, в конце концов.
Потому и запустили эту тему. Кстати сказать, рейтинги-то мы по-любому сделаем, а вот на уборку кода собрали пока только половину.
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.