Sitemde kullanmak üzere bir başarı sistemi tasarlamanın en iyi yolunu düşünüyorum. Veritabanı yapısı, 3 veya daha fazla ardışık kaydın eksik olduğunu söylemenin en iyi yolu olarak bulunabilir ve bu iş parçacığı, geliştiricilerden fikir almak için gerçekten bir uzantıdır.
Bu web sitesinde rozetler / başarı sistemleri hakkında birçok konuşmayla ilgili sorunum sadece bu - hepsi konuşma ve kod yok. Gerçek kod uygulama örnekleri nerede?
Burada, insanların katkıda bulunabileceğini ve genişletilebilir başarı sistemlerini kodlamak için iyi bir tasarım oluşturmasını umduğum bir tasarım öneriyorum. Bunun en iyisi olduğunu söylemiyorum, ondan çok uzak, ama bu olası bir başlangıç bloğu.
Lütfen fikirlerinizle katkıda bulunmaktan çekinmeyin.
sistem tasarım fikrim
Görünüşe göre genel fikir birliği "olay tabanlı bir sistem" oluşturmaktır - bir gönderi oluşturulduğunda, silindiğinde vb. Bilinen bir olay meydana geldiğinde, olay sınıfını böyle çağırır ..
$event->trigger('POST_CREATED', array('id' => 8));
Olay sınıfı daha sonra bu olay için hangi rozetlerin "dinlediğini", sonra o requiresdosyayı bulur ve şu şekilde bu sınıfın bir örneğini oluşturur:
require '/badges/' . $file;
$badge = new $class;
Daha sonra trigger, çağrıldığında alınan verileri geçen varsayılan olayı çağırır ;
$badge->default_event($data);
rozetler
İşte o zaman gerçek sihrin gerçekleştiği yer burası. her rozetin, bir rozetin verilip verilmeyeceğini belirlemek için kendi sorgusu / mantığı vardır. Her rozet, örneğin şu biçimde düzenlenmiştir:
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);
}
}
}
awardişlev, Badgetemelde kullanıcıya rozet verilip verilmediğini kontrol eden, yoksa rozet db tablosunu güncelleyecek olan genişletilmiş bir sınıftan gelir . Rozet sınıfı aynı zamanda bir kullanıcı için tüm rozetleri geri alma ve bir dizi içinde iade etme vb. İle ilgilenir (böylece rozetler örneğin kullanıcı profilinde görüntülenebilir)
Sistem halihazırda yayında olan bir sitede ilk ne zaman uygulandığında ne olacak?
Her rozete eklenebilecek bir "cron" iş sorgusu da vardır. Bunun nedeni, rozet sistemi ilk uygulandığında ve başlatıldığında, zaten kazanılmış olması gereken rozetlerin henüz ödüllendirilmemiş olmasının nedeni, bu olay tabanlı bir sistem olmasıdır. Bu nedenle, olması gereken her şeyi ödüllendirmek için her rozet için talep üzerine bir CRON işi çalıştırılır. Örneğin, yukarıdaki CRON işi şöyle görünecektir:
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);
}
}
}
Yukarıdaki cron sınıfı, ana rozet sınıfını genişlettiğinden, mantık işlevini yeniden kullanabilir try_award
Bunun için özel bir sorgu oluşturmamın nedeni, önceki olayları "simüle edebilmemize" rağmen, yani her kullanıcı gönderisini gözden geçirip olay sınıfını $event->trigger(), özellikle birçok rozet için çok yavaş olacakmış gibi tetikleyebilmemize rağmen . Bunun yerine optimize edilmiş bir sorgu oluşturuyoruz.
ödülü hangi kullanıcı alır? her şey diğer kullanıcıları etkinliğe göre ödüllendirmekle ilgili
BadgeSınıf awardişlevi görür user_id- her zaman ödül verilecektir. Varsayılan olarak, rozet olayın gerçekleşmesine NEDEN OLAN kişiye verilir, yani oturum kullanıcı kimliği ( default_eventCRON işi açıkça tüm kullanıcılar arasında döngü yapsa da ve ayrı kullanıcıları ödüllendirse de bu işlev için doğrudur )
Öyleyse bir örnek alalım, bir kodlama sorgulaması web sitesinde kullanıcılar kodlama girişlerini gönderirler. Yönetici daha sonra girişleri değerlendirir ve tamamlandığında, herkesin görmesi için sonuçları sorgulama sayfasına gönderir. Bu olduğunda, POSTED_RESULTS olayı çağrılır.
Yayınlanan tüm girişler için kullanıcılara rozet vermek istiyorsanız, diyelim ki, ilk 5 arasında yer almışlarsa, cron işini kullanmalısınız (ancak akılda tutulması gereken bu, yalnızca bu meydan okuma için değil tüm kullanıcılar için güncellenecektir sonuçlar yayınlandı)
Cron işi ile güncellemek için daha spesifik bir alanı hedeflemek istiyorsanız, cron iş nesnesine filtreleme parametreleri eklemenin bir yolu olup olmadığını görelim ve bunları kullanmak için cron_job işlevini alın. Örneğin:
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 işlevi, parametre sağlanmasa bile çalışmaya devam edecektir.