Tôi đang nghĩ đến cách tốt nhất để thiết kế hệ thống thành tích để sử dụng trên trang web của mình. Cấu trúc cơ sở dữ liệu có thể được tìm thấy tại Cách tốt nhất để biết 3 hoặc nhiều bản ghi liên tiếp bị thiếu và chủ đề này thực sự là một phần mở rộng để lấy ý tưởng từ các nhà phát triển.
Vấn đề mà tôi gặp phải khi nói nhiều về huy hiệu / hệ thống thành tích trên trang web này chỉ là - tất cả chỉ là nói và không có mã. Đâu là ví dụ triển khai mã thực tế?
Tôi đề xuất ở đây một thiết kế mà tôi hy vọng mọi người có thể đóng góp và hy vọng tạo ra một thiết kế tốt để mã hóa các hệ thống thành tích có thể mở rộng. Tôi không nói đây là điều tốt nhất, xa nó, nhưng đó là một bước khởi đầu khả thi.
Xin vui lòng đóng góp ý kiến của bạn.
ý tưởng thiết kế hệ thống của tôi
Có vẻ như sự đồng thuận chung là tạo ra một "hệ thống dựa trên sự kiện" - bất cứ khi nào một sự kiện đã biết xảy ra như một bài đăng được tạo, bị xóa, v.v. nó sẽ gọi lớp sự kiện như vậy ..
$event->trigger('POST_CREATED', array('id' => 8));
Sau đó, lớp sự kiện sẽ tìm ra những huy hiệu nào đang "lắng nghe" sự kiện này, sau đó requires
là tệp đó và tạo một thể hiện của lớp đó, như sau:
require '/badges/' . $file;
$badge = new $class;
Sau đó, nó gọi sự kiện mặc định truyền dữ liệu nhận được khi trigger
được gọi;
$badge->default_event($data);
những huy hiệu
Đây là nơi điều kỳ diệu thực sự xảy ra. mỗi huy hiệu có truy vấn / logic riêng để xác định xem có nên trao huy hiệu hay không. Mỗi huy hiệu được đặt ở dạng ví dụ như sau:
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
hàm đến từ một lớp mở rộng Badge
về cơ bản sẽ kiểm tra xem liệu người dùng đã được trao huy hiệu đó chưa, nếu chưa, sẽ cập nhật bảng db huy hiệu. Lớp huy hiệu cũng đảm nhận việc truy xuất tất cả các huy hiệu cho một người dùng và trả lại nó trong một mảng, v.v. (vì vậy, các huy hiệu có thể được hiển thị trên hồ sơ người dùng)
còn khi hệ thống được triển khai lần đầu tiên trên một trang đã hoạt động thì sao?
Ngoài ra còn có một truy vấn công việc "cron" có thể được thêm vào mỗi huy hiệu. Lý do cho điều này là vì khi hệ thống huy hiệu được triển khai và bắt đầu lần đầu tiên, các huy hiệu đáng lẽ đã kiếm được vẫn chưa được trao vì đây là hệ thống dựa trên sự kiện. Vì vậy, một công việc CRON được thực hiện theo yêu cầu đối với mỗi huy hiệu để trao bất cứ thứ gì cần thiết. Ví dụ, công việc CRON ở trên sẽ giống như sau:
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);
}
}
}
Khi lớp cron ở trên mở rộng lớp huy hiệu chính, nó có thể sử dụng lại hàm logic try_award
Lý do tại sao tôi tạo một truy vấn chuyên biệt cho việc này là mặc dù chúng tôi có thể "mô phỏng" các sự kiện trước đó, tức là đi qua mọi bài đăng của người dùng và kích hoạt lớp sự kiện giống như $event->trigger()
nó sẽ rất chậm, đặc biệt là đối với nhiều huy hiệu. Vì vậy, thay vào đó chúng tôi tạo một truy vấn được tối ưu hóa.
người dùng nào nhận được giải thưởng? tất cả về giải thưởng cho người dùng khác dựa trên sự kiện
Các Badge
lớp award
chức năng hoạt động trên user_id
- họ sẽ luôn được trao giải thưởng. Theo mặc định, huy hiệu được trao cho người ĐÃ LÀM sự kiện xảy ra tức là id người dùng phiên (điều này đúng với default_event
hàm, mặc dù công việc CRON hiển nhiên lặp lại qua tất cả người dùng và giải thưởng cho người dùng riêng biệt)
Vì vậy, hãy lấy một ví dụ, trên một trang web thử thách mã hóa, người dùng gửi bài viết mã của họ. Sau đó, quản trị viên sẽ đánh giá các mục và khi hoàn thành, đăng kết quả lên trang thử thách để mọi người cùng xem. Khi điều này xảy ra, sự kiện POSTED_RESULTS được gọi.
Nếu bạn muốn trao huy hiệu cho người dùng cho tất cả các mục đã đăng, giả sử, nếu họ được xếp hạng trong top 5, bạn nên sử dụng cron job (mặc dù hãy nhớ rằng điều này sẽ cập nhật cho tất cả người dùng, không chỉ cho thử thách đó kết quả đã được đăng cho)
Nếu bạn muốn nhắm mục tiêu một khu vực cụ thể hơn để cập nhật cron job, hãy xem có cách nào để thêm các tham số lọc vào đối tượng cron job và lấy hàm cron_job để sử dụng chúng không. Ví dụ:
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);
}
}
Hàm cron sẽ vẫn hoạt động ngay cả khi tham số không được cung cấp.