Я думаю о лучшем способе разработки системы достижений для использования на моем сайте. Структуру базы данных можно найти в Лучший способ рассказать о 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
, который в основном проверяет, будет ли пользователь уже присвоен этот значок, если нет, обновит таблицу dbbbge. Класс значка также выполняет поиск всех значков для пользователя и возвращает его в массив и т.д. (Поэтому значки могут отображаться, например, в профиле пользователя).
как насчет того, когда система будет впервые реализована на уже существующем сайте?
Существует также запрос задания "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.
Если вы хотите награждать значки для пользователей за все опубликованные записи, скажем, если они были ранжированы в пятерку лучших, вы должны использовать работу 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 будет работать, даже если параметр не указан.