Я думаю о лучшем способе разработки системы достижений для использования на моем сайте. Структуру базы данных можно найти по адресу Лучший способ указать, что 3 или более последовательных записей отсутствуют , и этот поток действительно является расширением для получения идей от разработчиков.
Проблема, с которой я часто сталкиваюсь на бейджах / системах достижений на этом веб-сайте, заключается в том, что это все разговоры, а не код. Где реальные примеры реализации кода?
Я предлагаю здесь проект, который, я надеюсь, люди могли бы внести и надеяться создать хороший дизайн для кодирования расширяемых систем достижений. Я не говорю, что это лучший, далеко не так, но это возможный стартовый блок.
Пожалуйста, не стесняйтесь вносить свои идеи.
моя идея дизайна системы
Похоже, что общий консенсус заключается в том, чтобы создать "систему, основанную на событиях" - всякий раз, когда происходит известное событие, такое как сообщение, которое создается, удаляется и т. Д., Оно вызывает класс события следующим образом.
$event->trigger('POST_CREATED', array('id' => 8));
Затем класс события выясняет, какие значки «слушают» это событие, затем он requires
этот файл и создает экземпляр этого класса, например:
require '/badges/' . $file;
$badge = new $class;
Затем вызывается событие по умолчанию, передающее данные, полученные при вызове trigger
;
$badge->default_event($data);
значки
Именно тогда происходит настоящее волшебство. каждый значок имеет свой собственный запрос / логику, чтобы определить, следует ли награждать значок. Каждый значок указан, например, в этот формат:
class Badge_Name extends Badge
{
const _BADGE_500 = 'POST_500';
const _BADGE_300 = 'POST_300';
const _BADGE_100 = 'POST_100';
function get_user_post_count()
{
$escaped_user_id = mysql_real_escape_string($this->user_id);
$r = mysql_query("SELECT COUNT(*) FROM posts
WHERE userid='$escaped_user_id'");
if ($row = mysql_fetch_row($r))
{
return $row[0];
}
return 0;
}
function default_event($data)
{
$post_count = $this->get_user_post_count();
$this->try_award($post_count);
}
function try_award($post_count)
{
if ($post_count > 500)
{
$this->award(self::_BADGE_500);
}
else if ($post_count > 300)
{
$this->award(self::_BADGE_300);
}
else if ($post_count > 100)
{
$this->award(self::_BADGE_100);
}
}
}
Функция
award
происходит из расширенного класса Badge
, который в основном проверяет, получит ли пользователь этот значок, если нет, обновит ли его таблицу базы данных. Класс значков также заботится о получении всех значков для пользователя и их возврате в массив и т. Д. (Таким образом, значки могут быть, например, отображены в профиле пользователя)
как насчет того, когда система будет впервые внедрена на уже работающем сайте?
Существует также запрос задания cron, который можно добавить к каждому значку. Причина этого заключается в том, что когда система бейджей впервые внедряется и инициализируется, бейджи, которые должны были быть уже заработаны, еще не присуждаются, потому что это система, основанная на событиях. Таким образом, задание CRON запускается по требованию для каждого значка, чтобы награждать все, что должно быть. Например, задание CRON для вышеупомянутого будет выглядеть так:
class Badge_Name_Cron extends Badge_Name
{
function cron_job()
{
$r = mysql_query('SELECT COUNT(*) as post_count, user_id FROM posts');
while ($obj = mysql_fetch_object($r))
{
$this->user_id = $obj->user_id; //make sure we're operating on the right user
$this->try_award($obj->post_count);
}
}
}
Поскольку вышеуказанный класс cron расширяет основной класс значков, он может повторно использовать логическую функцию try_award
Причина, по которой я создаю специализированный запрос для этого, заключается в том, что мы могли «имитировать» предыдущие события, то есть проходить через каждую запись пользователя и запускать класс событий, такой как $event->trigger()
, это было бы очень медленно, особенно для многих значков. Поэтому мы вместо этого создаем оптимизированный запрос.
Какой пользователь получает награду? все о награждении других пользователей на основе события
Функция Badge
class award
действует на user_id
- они всегда будут получать награду. По умолчанию значок вручается тому, кто ПРИЧИНА событие произошло, т.е. идентификатор пользователя сеанса (это верно для функции default_event
, хотя задание CRON, очевидно, проходит через всех пользователей и награждает отдельных пользователей)
Итак, давайте возьмем пример, на веб-сайте задачи кодирования пользователи отправляют свои записи кодирования. Затем администратор оценивает записи и по завершении публикует результаты на странице испытаний для всеобщего обозрения. Когда это происходит, вызывается событие POSTED_RESULTS.
Если вы хотите наградить пользователей значками за все опубликованные записи, скажем, если они были ранжированы в топ-5, вам следует использовать задание cron (хотя само по себе это будет обновляться для всех пользователей, а не только которые оспаривали результаты были опубликованы для)
Если вы хотите указать более конкретную область для обновления с помощью задания cron, давайте посмотрим, есть ли способ добавить параметры фильтрации в объект задания cron и получить функцию cron_job для их использования. Например:
class Badge_Top5 extends Badge
{
const _BADGE_NAME = 'top5';
function try_award($position)
{
if ($position <= 5)
{
$this->award(self::_BADGE_NAME);
}
}
}
class Badge_Top5_Cron extends Badge_Top5
{
function cron_job($challenge_id = 0)
{
$where = '';
if ($challenge_id)
{
$escaped_challenge_id = mysql_real_escape_string($challenge_id);
$where = "WHERE challenge_id = '$escaped_challenge_id'";
}
$r = mysql_query("SELECT position, user_id
FROM challenge_entries
$where");
while ($obj = mysql_fetch_object($r))
{
$this->user_id = $obj->user_id; //award the correct user!
$this->try_award($obj->position);
}
}
Функция cron будет работать, даже если параметр не указан.