Je réfléchis à la meilleure façon de concevoir un système de réalisations à utiliser sur mon site. La structure de la base de données peut être trouvée à Meilleur moyen de dire 3 enregistrements consécutifs ou plus manquants et ce fil est vraiment une extension pour obtenir les idées des développeurs.
Le problème que j'ai avec beaucoup de discussions sur les badges / systèmes de réussite sur ce site Web est juste que - tout est parlé et pas de code. Où sont les exemples réels d'implémentation de code?
Je propose ici un design auquel j'espère que les gens pourront contribuer et j'espère créer un bon design pour coder des systèmes de réalisation extensibles. Je ne dis pas que c'est le meilleur, loin de là, mais c'est un point de départ possible.
N'hésitez pas à apporter vos idées.
mon idée de conception de système
Il semble que le consensus général soit de créer un "système basé sur les événements" - chaque fois qu'un événement connu se produit comme une publication est créée, supprimée, etc., il appelle la classe d'événements comme ceci.
$event->trigger('POST_CREATED', array('id' => 8));
La classe d'événements découvre alors quels badges "écoutent" cet événement, puis dans ce requires
fichier, et crée une instance de cette classe, comme ceci:
require '/badges/' . $file;
$badge = new $class;
Il appelle ensuite l'événement par défaut en transmettant les données reçues lors de l' trigger
appel;
$badge->default_event($data);
les badges
C'est alors que la vraie magie opère. chaque badge a sa propre requête / logique pour déterminer si un badge doit être attribué. Chaque badge est présenté par exemple dans ce format:
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
La fonction provient d'une classe étendue Badge
qui vérifie essentiellement si l'utilisateur a déjà reçu ce badge, sinon, mettra à jour la table de base de données des badges. La classe de badge s'occupe également de récupérer tous les badges d'un utilisateur et de les renvoyer dans un tableau, etc. (les badges peuvent donc être affichés par exemple sur le profil de l'utilisateur)
qu'en est-il lorsque le système est mis en œuvre pour la première fois sur un site déjà en ligne?
Il existe également une requête de tâche "cron" qui peut être ajoutée à chaque badge. La raison en est que lorsque le système de badges est mis en œuvre et lancé pour la première fois, les badges qui auraient déjà dû être gagnés n'ont pas encore été attribués car il s'agit d'un système basé sur des événements. Ainsi, un travail CRON est exécuté à la demande pour chaque badge afin d'attribuer tout ce qui doit l'être. Par exemple, le travail CRON pour ce qui précède ressemblerait à:
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);
}
}
}
Comme la classe cron ci-dessus étend la classe de badge principale, elle peut réutiliser la fonction logique try_award
La raison pour laquelle je crée une requête spécialisée pour cela est que nous pourrions "simuler" les événements précédents, c'est-à-dire parcourir chaque message d'utilisateur et déclencher la classe d'événements comme si $event->trigger()
elle serait très lente, en particulier pour de nombreux badges. Nous créons donc plutôt une requête optimisée.
quel utilisateur obtient le prix? tout sur l'attribution d' autres utilisateurs en fonction de l'événement
La fonction de Badge
classe award
agit sur user_id
- ils recevront toujours le prix. Par défaut, le badge est attribué à la personne qui a CAUSÉ l'événement, c'est-à-dire l'ID utilisateur de la session (cela est vrai pour la default_event
fonction, bien que le travail CRON boucle évidemment à travers tous les utilisateurs et attribue des utilisateurs séparés)
Prenons donc un exemple, sur un site Web de défi de codage, les utilisateurs soumettent leur entrée de codage. L'administrateur évalue ensuite les entrées et une fois terminé, publie les résultats sur la page de défi pour que tous les voient. Lorsque cela se produit, un événement POSTED_RESULTS est appelé.
Si vous souhaitez attribuer des badges aux utilisateurs pour toutes les entrées publiées, disons, si elles étaient classées dans le top 5, vous devez utiliser le travail cron (bien que sachez que cela sera mis à jour pour tous les utilisateurs, pas seulement pour ce défi. les résultats ont été publiés pour)
Si vous souhaitez cibler une zone plus spécifique à mettre à jour avec le travail cron, voyons s'il existe un moyen d'ajouter des paramètres de filtrage dans l'objet de travail cron et obtenez la fonction cron_job pour les utiliser. Par exemple:
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);
}
}
La fonction cron fonctionnera toujours même si le paramètre n'est pas fourni.