Я думаю о том, как лучше всего разработать систему достижений для использования на моем сайте. Структуру базы данных можно найти в разделе " Лучший способ указать, что 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
который в основном проверяет, был ли пользователь уже награжден этим значком, если нет, обновит таблицу db значка. Класс бейджей также заботится о получении всех бейджей для пользователя и возвращении их в массиве и т. Д. (Так что бейджи могут, например, отображаться в профиле пользователя)
как насчет того, когда система будет реализована в самом начале на уже действующем сайте?
Также к каждому значку можно добавить запрос о работе 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
Класс award
функция действует на user_id
- они всегда будут даны награды. По умолчанию значок присуждается человеку, который ВЫЗВИЛ событие, т.е. идентификатор пользователя сеанса (это верно для default_event
функции, хотя задание CRON, очевидно, проходит через всех пользователей и награждает отдельных пользователей)
Итак, давайте возьмем пример, на веб-сайте задачи кодирования пользователи отправляют свою запись кодирования. Затем администратор оценивает записи и по завершении публикует результаты на странице задачи для всеобщего обозрения. Когда это происходит, вызывается событие POSTED_RESULTS.
Если вы хотите наградить пользователей значками за все опубликованные записи, скажем, если они попали в пятерку лучших, вам следует использовать задание 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 по-прежнему будет работать, даже если параметр не указан.