I'm pretty infatuated with Stack Overflow's badge system, so I decided to cook up a generic framework for adding one to my crossword site. Herein I will present my work in progress for the consumption of my dear readers.
The storage of these badge-awarding rules seemed interesting to me. It'd have to be flexible enough to take data from any part of the site related to a user, and not be a hassle to add new badges or check a user's list of acquired badges. I haven't put the caching in yet, which would form the basis for making awarded badges permanent, instead of calculated on the fly, but it's still pretty fun to work with.
I started off by creating a simple Badge interface.
Badge.php
public function getActive();
public function validFor($user);
public function toString();
public function getColor();
}
Then tossed in a little abstract class to handle some defaults:
AbstractBadge.php
public function getColor() {
return "#cccccc";
}
public function getActive() {
return true;
}
public function toString() {
return "Default";
}
}
Now I needed a way to go through these badges and find out which applied to a User object. I wanted to use a plugin style system where I'd just need to have a directory full of these Badge implementors and it would figure out which ones to apply. This bit is certainly in-progress, but works well enough to demonstrate.
Badges.php
class Badges extends ArrayObject {
public function __construct() {
$badgedir = opendir(BADGE_DIR);
while ($f = readdir($badgedir)) {
if (preg_match('/Badge\.php$/',$f)) {
try {
include BADGE_DIR.'/'.$f;
$cls = str_replace('.php','',$f);
$badge = new $cls;
if ($badge instanceof Badge) {
if ($badge->getActive())
$this->append($badge);
}
} catch (Exception $ex) {}
}
}
return $this;
}
public function getUserBadges($user) {
$result = new ArrayObject();
foreach ($this as $badge) {
if ($badge->validFor($user))
$result->append($badge);
}
return $result;
}
}
This iterates through the Badges in a directory (one defined by a path in my site config file, in this case), and returns all active badges for a certain user. Now it's fairly trivial to add new badges.
For example, we could have a badge that would reward the user for being me.
AdamBadge.php
public function validFor($user) {
return $user->username == 'adam';
}
public function toString() {
return "Your name is Adam";
}
}
And now I'll be congratulated for being myself every time I check my user profile. What a fine feeling it is.
Up next:
“class AdamBadge extends AbstractBadge {
public function validFor($user) {
return $user->username == ‘gibzon’;
}
public function toString() {
return “You are awesome!”;
}
}”
Jiminy! You’ve hacked me!