First stab at underlying grouping code, and how it could work without any groups.
[project/achievements.git] / achievements.pages.inc
1 <?php
2
3 /**
4 * @file
5 * Page callbacks for the Achievements module.
6 */
7
8 /**
9 * Menu callback and block; show the site-wide leaderboard.
10 *
11 * @param $block
12 * Whether this is a block display (defaults to FALSE).
13 */
14 function achievements_leaderboard_totals($block = FALSE) {
15 $achievers = achievements_totals($block ? 5 : 50);
16 $header = array(t('#'), t('Who'), t('Points'), t('Unlocks'), t('When'));
17 $header = $block ? array_slice($header, 0, 3) : $header; // UNIQUEZORS.
18 !$block ? drupal_set_title(t('Achievement leaderboard')) : ''; // UNIQUEZORS+.
19 drupal_add_css(drupal_get_path('module', 'achievements') . '/achievements.css');
20
21 $rows = array();
22 foreach ($achievers as $achiever) {
23 $row = array( // dueling styles for wipe.
24 array(
25 'data' => $achiever->rank,
26 'class' => array('achievement-leaderboard-rank')
27 ),
28 array(
29 'data' => theme('username', array('account' => $achiever)),
30 'class' => array('achievement-leaderboard-username')
31 ),
32 array(
33 'data' => l($achiever->points, 'user/' . $achiever->uid . '/achievements'),
34 'class' => array('achievement-leaderboard-points')
35 ),
36 );
37
38 if (!$block) {
39 $row[] = array(
40 'data' => l($achiever->unlocks, 'user/' . $achiever->uid . '/achievements'),
41 'class' => array('achievement-leaderboard-unlocks')
42 );
43 $row[] = array(
44 'data' => format_date($achiever->timestamp, 'small'),
45 'class' => array('achievement-leaderboard-when')
46 );
47 }
48
49 $rows[] = $row;
50 }
51
52 $build['achievements']['leaderboard'] = array(
53 '#attributes' => array('class' => array('achievement-leaderboard')),
54 '#header' => $header, // 3 or 5 columns based on $block.
55 '#empty' => t('No one has been ranked yet.'),
56 '#rows' => $rows,
57 '#theme' => 'table',
58 );
59
60 if ($block) { // link off to more. MOOOReEeE!
61 $build['achievements']['see-more'] = array(
62 '#prefix' => '<div class="achievement-see-more">',
63 '#markup' => l(t('View the top 50 leaders ยป'), 'achievements/leaderboard'),
64 '#suffix' => '</div>',
65 );
66 }
67
68 return $build;
69 }
70
71 /**
72 * Menu callback; display a single achievement page with leaderboards.
73 */
74 function achievements_leaderboard_for($achievement) {
75 drupal_add_css(drupal_get_path('module', 'achievements') . '/achievements.css');
76 drupal_set_title(t('Achievement: @title', array('@title' => $achievement['title'])));
77
78 $build['achievements']['achievement'] = array(
79 '#theme' => 'achievement',
80 '#achievement' => $achievement,
81 '#unlock' => achievements_unlocked_already($achievement['id']),
82 );
83
84 // get stats for first and most recent unlocks.
85 $query = db_select('achievement_unlocks', 'au');
86 $query->join('achievement_totals', 'at', 'at.uid = au.uid');
87 $query->join('users', 'u', 'u.uid = au.uid'); // same basic start for both queries.
88 $query->condition('achievement_id', $achievement['id']); // ... with a slight tweak.
89 $query->fields('au', array('uid', 'rank', 'timestamp'))->fields('at', array('points', 'unlocks'))->fields('u', array('name'));
90 $query2 = clone $query; // allows us to save a few lines of duplicate query building. never used clone before. awesome.
91 $stats['first'] = $query->orderBy('rank')->range(0, 10)->execute()->fetchAllAssoc('rank'); // FI... sigh.
92 $stats['recent'] = $query2->orderBy('timestamp', 'DESC')->range(0, 10)->execute()->fetchAllAssoc('rank');
93
94 // both stat tables are displayed similarly.
95 foreach (array('first', 'recent') as $type) {
96 $rows = array(); // clear previous run.
97 foreach ($stats[$type] as $stat) {
98 $rows[] = array(
99 array(
100 'data' => $stat->rank,
101 'class' => array('achievement-leaderboard-rank')
102 ),
103 array(
104 'data' => theme('username', array('account' => $stat)),
105 'class' => array('achievement-leaderboard-username')
106 ),
107 array(
108 'data' => l($stat->points, 'user/' . $stat->uid . '/achievements'),
109 'class' => array('achievement-leaderboard-points')
110 ),
111 array(
112 'data' => format_date($stat->timestamp, 'short'),
113 'class' => array('achievement-leaderboard-when')
114 ),
115 );
116 }
117
118 $build['achievements']['stats'][$type] = array(
119 '#attributes' => array('class' => array('achievement-stats-' . $type)),
120 '#caption' => t('@type achievement unlocks', array('@type' => drupal_ucfirst($type))),
121 '#header' => array(t('#'), t('Who'), t('Points'), t('When')),
122 '#empty' => t('No one has unlocked this yet. Keep trying!'),
123 '#rows' => $rows,
124 '#theme' => 'table',
125 );
126 }
127
128 return $build;
129 }
130
131 /**
132 * Menu callback; display all achievements for the passed user.
133 *
134 * @param $account
135 * The user object this request applies against.
136 */
137 function achievements_user_page($account) {
138 drupal_add_css(drupal_get_path('module', 'achievements') . '/achievements.css');
139 drupal_set_title(t('Achievements for @name', array('@name' => $account->name)));
140
141 $achievements = achievements_load(NULL, TRUE);
142 $unlocks = db_select('achievement_unlocks', 'au')->fields('au', array('achievement_id', 'rank', 'timestamp'))
143 ->condition('uid', $account->uid)->orderBy('timestamp', 'DESC')->execute()->fetchAllAssoc('achievement_id');
144
145 $build['achievements']['stats'] = array(
146 '#prefix' => '<div class="achievement-stats">',
147 '#markup' => t('@name is ranked #@rank with @points points. @unlocks_count of @total_count achievements have been unlocked.', array(
148 '@name' => $account->name,
149 '@rank' => achievements_totals_user('rank', $account->uid),
150 '@points' => achievements_totals_user('points', $account->uid),
151 '@unlocks_count' => count($unlocks),
152 '@total_count' => count($achievements))),
153 '#suffix' => '</div>',
154 );
155
156 foreach ($achievements as $group_id => $group) {
157 foreach ($group['achievements'] as $achievement_id => $achievement) {
158 $build['achievements'][$group_id][$achievement_id]['#theme'] = 'achievement';
159 $build['achievements'][$group_id][$achievement_id]['#achievement'] = $achievement;
160
161 if (isset($unlocks[$achievement_id])) {
162 $build['achievements'][$group_id][$achievement_id]['#unlock'] = (array) $unlocks[$achievement_id];
163 $build['achievements'][$group_id][$achievement_id]['#weight'] = -$unlocks[$achievement_id]->timestamp;
164 // by setting the weight to the timestamp, the latest unlocks are always shown at the top.
165 }
166 }
167 }
168
169 return $build;
170 }
171
172 /**
173 * Menu callback; Retrieve autocomplete suggestions for achievement names.
174 */
175 function achievements_autocomplete($string = '') {
176 $achievements = achievements_load(); // MmmMMmMm, gooOoaaAaalLLlsss.
177 array_walk($achievements, 'achievements_autocomplete_search', $string);
178 drupal_json_output(array_slice(array_filter($achievements), 0, 10));
179 }
180
181 /**
182 * array_walk helper function for achievements_autocomplete().
183 */
184 function achievements_autocomplete_search(&$value, $key, $string) {
185 $value = (stripos($value['title'], $string) === FALSE) ? FALSE : $value['title'];
186 }