/[drupal]/contributions/modules/versus/versus.module
ViewVC logotype

Contents of /contributions/modules/versus/versus.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.17 - (show annotations) (download) (as text)
Mon Jul 28 16:49:45 2008 UTC (16 months ago) by colan
Branch: MAIN
CVS Tags: HEAD
Changes since 1.16: +2 -2 lines
File MIME type: text/x-php
#279117: Fixed machine names displayed on Cast Votes page.
1 <?php
2 // $Id: versus.module,v 1.16 2008/06/10 02:31:17 colan Exp $
3
4 /**
5 * @file
6 * Allows users to pick a winner of two nodes of the same type.
7 *
8 * This module allows users to vote on pairs of nodes for each content type.
9 * After a user votes on a random pair by picking a winner, he or she will be
10 * directed to vote on the next random pair.
11 *
12 * Versus is a rewrite of the Smackdown module that doesn't create any nodes.
13 * Smackdown views each X vs. Y pair as a "smackdown" node. This doesn't scale
14 * well when users are required to vote on large numbers of pairs. An example
15 * is all possible combinations of nodes for a given content type. For each
16 * content type, n choose 2 nodes need to be created, and this grows very large
17 * very quickly.
18 *
19 * CRUD is handled by the Voting API module, which is required as a dependency.
20 *
21 * Copyright (C) 2008 Openject Consulting (http://www.openject.com/).
22 * Originally written by Colan Schwartz (http://drupal.org/user/58704)
23 * with theming help from William Roboly (http://drupal.org/user/48120).
24 */
25
26 /****************************************************************************
27 ** DRUPAL HOOKS ************************************************************
28 ****************************************************************************/
29
30 /**
31 * Implementation of hook_help().
32 */
33 function versus_help($section) {
34 switch ($section) {
35
36 case 'admin/help#versus':
37 // Return the brief help text.
38 return t('
39 <p>Allows users to pick a winner of two nodes of the same type.</p>
40 ');
41
42 case 'admin/settings/versus':
43 // Return a longer help text.
44 return t("
45 <p>This module allows users to vote on pairs of nodes for each content type.
46 After a user votes on a random pair by picking a winner, he or she will be
47 directed to vote on the next random pair.</p>
48
49 <p>Versus is a rewrite of the Smackdown module that doesn't create any nodes.
50 Smackdown views each X vs. Y pair as a \"smackdown\" node. This doesn't scale
51 well when users are required to vote on large numbers of pairs. An example is
52 all possible combinations of nodes for a given content type. For each content
53 type, n choose 2 nodes need to be created, and this grows very large very
54 quickly.</p>
55
56 <p>CRUD is handled by the Voting API module, which is required as a
57 dependency.</p>
58 ");
59 }
60 }
61
62 /**
63 * Implementation of hook_menu().
64 */
65 function versus_menu($may_cache) {
66
67 // Initialize the list of menu items.
68 $items = array();
69
70 if ($may_cache) {
71 // Define cacheable menu items.
72
73 // Add an item for the admin settings.
74 $items[] = array(
75 'path' => 'admin/settings/versus',
76 'title' => t('Versus settings'),
77 'description' => t('Global settings for the Versus module.'),
78 'callback' => 'drupal_get_form',
79 'callback arguments' => array('versus_settings'),
80 'access' => user_access('administer versus'),
81 );
82
83 // Add the main menu item to the navigation list.
84 $items[] = array(
85 'path' => 'versus',
86 'title' => t('Voting Options'),
87 'callback' => 'versus_voting_options',
88 'type' => MENU_NORMAL_ITEM,
89 'access' => (
90 user_access('vote with versus') || user_access('view versus results')
91 ),
92 );
93
94 // Add the "Vote" option to the Voting menu.
95 $items[] = array(
96 'path' => 'versus/vote',
97 'title' => t('Cast Votes'),
98 'callback' => 'versus_vote_request',
99 'type' => MENU_ITEM_GROUPING,
100 'access' => user_access('vote with versus'),
101 'weight' => -5,
102 );
103
104 // Add callbacks for each content type.
105 foreach (versus_types_enabled() as $type) {
106 if ($type) {
107 $items[] = array(
108 'path' => 'versus/vote/'. $type,
109 'title' => node_get_types('name', $type),
110 'access' => user_access('vote with versus'),
111 );
112 }
113 }
114 }
115
116 // Return the defined items.
117 return $items;
118 }
119
120 /**
121 * Implementation of hook_perm
122 *
123 * @todo
124 * Implement 'view versus results'. This can't be done in any good way
125 * right now as Views 1 doesn't support Drupal permissions. It only
126 * supports role-based permissions, which will differ on each site.
127 */
128 function versus_perm() {
129 return array('administer versus', 'vote with versus', 'view versus results');
130 }
131
132 /****************************************************************************
133 ** FORMS *******************************************************************
134 ****************************************************************************/
135
136 /**
137 * Define the settings form.
138 *
139 * @return array
140 * The form.
141 */
142 function versus_settings() {
143
144 $form['versus_voting_enabled'] = array(
145 '#type' => 'radios',
146 '#title' => t('Voting status'),
147 '#default_value' => variable_get('versus_voting_enabled', 0),
148 '#options' => array(t('Disabled'), t('Enabled')),
149 '#description' => t('If voting is disabled, users cannot vote. Select "Enabled" to allow it, or select "Disabled" to take it off-line. Other modules (e.g. <a href="http://drupal.org/project/competition">Competition</a>) may (un)set this.'),
150 );
151
152 $form['versus_types_enabled'] = array(
153 '#type' => 'checkboxes',
154 '#title' => t('Enabled content types'),
155 '#description' => t('Select the content types whose nodes can be voted on.'),
156 '#default_value' => versus_types_enabled(),
157 '#options' => versus_node_get_types(),
158 );
159
160 return system_settings_form($form);
161 }
162
163 /**
164 * Define the voting form on a ballot.
165 *
166 * @param $winner
167 * The node ID of the left voting option.
168 * @param $loser
169 * The node ID of the right voting option.
170 * @param $type
171 * The node type of the vote combination.
172 * @return array
173 * The form.
174 */
175 function versus_voting_form($winner, $loser, $type) {
176
177 // Create the submit button.
178 $form['op'] = array(
179 '#type' => 'submit',
180 '#value' => $winner,
181 '#theme' => 'versus_vote_button',
182 );
183
184 // Set up some information that we'll need after processing the form.
185 // This includes the winner, loser and the type.
186 $form['vote_refs'] = array(
187 '#type' => 'value',
188 '#value' => array(
189 'versus_winner' => $winner,
190 'versus_loser' => $loser,
191 'node_type' => $type,
192 ),
193 );
194
195 // Return our form.
196 return $form;
197 }
198
199 /**
200 * Process a voting form submission.
201 */
202 function versus_voting_form_submit($form_id, $form_values) {
203
204 // Figure out who won & who lost.
205 $winner = $form_values['vote_refs']['versus_winner'];
206 $loser = $form_values['vote_refs']['versus_loser'];
207
208 // Record the vote in the database.
209 $result = votingapi_add_vote('node', $loser, $winner, 'option', 'versus');
210
211 // Take the user to the next voting ballot.
212 drupal_goto('versus/vote/'. arg(2) . (arg(3) ? '/'. arg(3) : ''));
213 return;
214 }
215
216 /****************************************************************************
217 ** PRIVATE FUNCTIONS *******************************************************
218 ****************************************************************************/
219
220 /**
221 * Get a list of content types that are enabled for voting.
222 *
223 * @return
224 * The array of content types.
225 */
226 function versus_types_enabled() {
227 return variable_get('versus_types_enabled', array());
228 }
229
230 /**
231 * Helper function that caches node types.
232 *
233 * This code was originally taken from _relatedlinks_node_get_types(),
234 * in the Related Links module (http://drupal.org/project/relatedlinks).
235 *
236 * @param $keys
237 * A boolean variable that decides whether an associative array of node
238 * types is to be returned (or not).
239 *
240 * @return
241 * An associative or non-associative array of node types.
242 */
243 function versus_node_get_types($keys = FALSE) {
244 static $node_types = NULL, $key_array = NULL;
245
246 // Check if there's anything in the cache.
247 if (!isset($node_types)) {
248
249 // There's nothing in the cache so we need to get content type information.
250 $node_types = node_get_types('names');
251 foreach ($node_types as $type => $name) {
252 $node_types[$type] = check_plain($name);
253 }
254
255 // Set the list of keys.
256 $key_array = array_keys($node_types);
257 }
258
259 // Either return the key list, or key/value pairs.
260 return $keys ? $key_array : $node_types;
261 }
262
263 /**
264 * Display voting options to users.
265 *
266 * @return
267 * The themed output.
268 */
269 function versus_voting_options() {
270
271 // Declare a list of options and some header info.
272 $options = array();
273 $instructions = t('Choose the appropriate item from the list:');
274
275 // Present a voting option if the correct permissions exist.
276 if (user_access('vote with versus')) {
277 $options[] = array(
278 'title' => t('Cast Votes'),
279 'path' => 'versus/vote',
280 'description' => t('Vote on items within a particular content type.'),
281 );
282 }
283
284 // Present a link to the standings if the correct permissions exist.
285 if (user_access('view versus results')) {
286 $options[] = array(
287 'title' => t('View Standings'),
288 'path' => 'versus/standings',
289 'description' => t('Look at the current standings for a particular content type.'),
290 );
291 }
292
293 // Return the themed output.
294 return theme('versus_voting_options', $instructions, $options);
295 }
296
297 /**
298 * Receive a voting request.
299 *
300 * Either validate a voting request for a particular type, or show a list
301 * of types that can voted on.
302 *
303 * @param $type
304 * The content type to vote on.
305 * @param $competition
306 * The competition that the voting content should be part of,
307 * if the Competition module is enabled.
308 * @return
309 * The content type's voting page, or a list of content type options
310 * if no valid type is provided.
311 * @todo
312 * Set up a hook so that code for other modules doesn't have to be
313 * in here. It'll keep things cleaner & nicer.
314 */
315 function versus_vote_request($type = NULL, $competition = NULL) {
316
317 // Perform some checks for the Competition module.
318 if (module_exists('competition')) {
319
320 // Make sure that we're in a voting phase.
321 if (!variable_get('versus_voting_enabled', FALSE)) {
322 drupal_set_message(t("Sorry, but you can't vote now. We're not currently in a voting phase."), 'error');
323 drupal_goto();
324 }
325
326 // Make sure that we're getting a valid competition node ID.
327 if ($competition) {
328
329 // Check for SQL injection.
330 if (!db_result(db_query(
331 'SELECT COUNT(*) FROM {content_type_competition} WHERE (nid = %d)',
332 $competition))) {
333 watchdog('security', t('Detected possible SQL injection attempt.'),
334 WATCHDOG_WARNING);
335 drupal_goto();
336 }
337
338 // Make sure it exists & is in the current round.
339 $round = db_result(db_query("
340 SELECT field_competition_round_value FROM {content_type_competition}
341 WHERE nid = %d
342 ", $competition));
343 if ($round != competition_round_get_current()) {
344 drupal_set_message(t("You can only vote on a competition in the current round, round " . competition_round_get_current() . "."), 'error');
345 drupal_goto();
346 }
347 }
348 else /* !$competition */ {
349 return versus_voting_competitions(competition_round_get_current());
350 }
351 }
352
353 // Make sure that any provided type is valid.
354 $types = versus_types_enabled();
355 if (isset($types[$type])) {
356 $output = versus_vote_process_type($type, $competition);
357 }
358 else /* no valid content type has been provided */ {
359 $output = theme('versus_voting_types', $types);
360 }
361
362 return $output;
363 }
364
365 /**
366 * Display current competitions that can be voted on.
367 *
368 * @param $round
369 * The current round.
370 * @return
371 * HTML showing the current competitions and their content types
372 * that can be voted on.
373 */
374 function versus_voting_competitions($round) {
375
376 // Fetch the active competitions & their content types.
377 $result = db_query(db_rewrite_sql("
378 SELECT n.title, c.field_competition_round_value AS round, ct.nid,
379 ct.delta, ct.field_competition_content_types_value AS type
380 FROM {node} n
381 INNER JOIN {content_type_competition} c ON n.nid = c.nid
382 INNER JOIN {content_field_competition_content_types} ct ON c.nid = ct.nid
383 WHERE c.field_competition_round_value = %d
384 ORDER BY ct.nid, ct.vid, ct.delta
385 "), $round);
386
387 // Stick the fetched data into an array.
388 $competitions = array();
389 while ($db_object = db_fetch_object($result)) {
390 $nid = $db_object->nid;
391 $competitions[$nid]['nid'] = $db_object->nid;
392 $competitions[$nid]['title'] = $db_object->title;
393 $competitions[$nid]['types'][$db_object->delta] = $db_object->type;
394 }
395
396 // Set some instructions.
397 $instructions = t('Which competition and content type would you like to vote on?');
398
399 // Return the themed data.
400 return theme('versus_voting_competitions', $instructions, $competitions);
401 }
402
403 /**
404 * Process a voting request for a particular content type.
405 *
406 * @param $type
407 * The content type to vote on.
408 * @param $competition
409 * The competition that the voting should be restricted to.
410 * This is irrelevant when the Competition module is not enabled.
411 * @return
412 * Any output from the processing.
413 * @todo
414 * Instead of containing code for other modules, this function should gather
415 * all conditions from modules that implement hook_versus_conditions(). The
416 * hook should return an array of conditions as strings.
417 */
418 function versus_vote_process_type($type, $competition = NULL) {
419 global $user;
420
421 // Set any conditions that nodes must meet in order to become candidates.
422 // By default, there are no conditions, and all nodes of a particular
423 // type are candidates for voting.
424 $conditions = array("TRUE");
425
426 // Add conditions for the competition module.
427 if (module_exists('competition')) {
428
429 // Make sure that we're in the voting phase.
430 if (competition_phase_get_current() != COMPETITION_PHASE_VOTING) {
431 $conditions[] = "FALSE";
432 }
433
434 // Each node to be voted upon must belong to the current round.
435 // We already check for SQL injection attempts, so we don't need to here.
436 $conditions[] = "(
437 SELECT (
438 SELECT entry.field_competition_entry_comp_nid
439 FROM {content_type_competition_entry} entry
440 WHERE entry.nid = (
441 SELECT r.parent_nid FROM {relativity} r WHERE r.nid = n.nid
442 )
443 ) = $competition
444 )";
445 }
446
447 // Marshal the conditions.
448 $conditions = implode(" AND ", $conditions);
449
450 // Request the list of node IDs for the required type.
451 $result = db_query(db_rewrite_sql("
452 SELECT n.nid, n.type FROM {node} n WHERE n.type = '%s' AND $conditions
453 ORDER BY RAND()
454 "), $type);
455
456 // Fetch them.
457 $nids = array();
458 while ($db_object = db_fetch_object($result)) {
459 $nids[] = (object) array(
460 'nid' => $db_object->nid,
461 'type' => $db_object->type,
462 );
463 }
464
465 // Initialize some voting options.
466 $left = NULL;
467 $right = NULL;
468 $done = FALSE;
469
470 // If there's only one result, assign it to the left option.
471 if (count($nids) == 1) {
472 $left = $nids[0];
473 }
474
475 // There are more than two candidates, so we need to show a left & right
476 // option for the user to vote on.
477 if (count($nids) >= 2) {
478
479 // Request the user's previous votes so we'll know what not to show
480 // him/her again. In Drupal 5, the Voting API doesn't provide a useful
481 // function for returning all of the votes of a particular user.
482 // Therefore, we need to go around the API and dig into the DB directly.
483 // This won't be necessary in Drupal 6 because the Drupal 6 version of
484 // the Voting API provides a much more general way of obtaining such
485 // data through the two functions votingapi_select_votes() and
486 // votingapi_select_results(). It appears as though the latter grabs
487 // data from the cache while the former does not. We can use one of
488 // these in the Drupal 6 version of Versus, and do away with the
489 // following query.
490 $result = db_query("
491 SELECT content_id AS loser, value AS winner FROM {votingapi_vote}
492 WHERE (content_type = 'node')
493 AND (value_type = 'option')
494 AND (tag = 'versus')
495 AND (uid = %d)
496 ", $user->uid);
497
498 // Marshal the data into an array.
499 $votes = array();
500 while ($db_object = db_fetch_object($result)) {
501 $votes[] = (object) array(
502 'loser' => $db_object->loser,
503 'winner' => $db_object->winner,
504 );
505 }
506
507 // Cycle through each pair of nodes.
508 foreach ($nids as $pos1 => $node1) {
509 foreach ($nids as $pos2 => $node2) {
510
511 // Don't compare nodes that have already been compared,
512 // or nodes that are of different types.
513 if (($pos2 <= $pos1) || ($node1->type != $node2->type)) {
514 continue;
515 }
516
517 // Create a pair with the first node as the loser, and the second
518 // as the winner.
519 $order1 = (object) array(
520 'loser' => $node1->nid,
521 'winner' => $node2->nid,
522 );
523
524 // Create a pair with the second node as the loser, and the first
525 // as the winner.
526 $order2 = (object) array(
527 'loser' => $node2->nid,
528 'winner' => $node1->nid,
529 );
530
531 // Check to see if either of them are in the list of previous votes
532 // for this user. If either of them are, we need to skip this pair
533 // and try to find another one.
534 if (in_array($order1, $votes) || in_array($order2, $votes)) {
535 continue;
536 }
537 else /* this pair hasn't been voted on yet */ {
538
539 // Assign the current pair to the left and right options,
540 // and then get off this roller coaster.
541 $left = $node1;
542 $right = $node2;
543 break;
544 }
545 }
546 }
547 }
548
549 // If the left and right options haven't been set, we can only assume
550 // that the user has voted on all possible pairs. Therefore, the user
551 // is done voting in this category.
552 if (!($left || $right)) {
553 $done = TRUE;
554 }
555
556 // Return a ballot based on what we've discovered above.
557 return versus_voting_ballot(count($nids), $done, $left, $right);
558 }
559
560 /****************************************************************************
561 ** THEME FUNCTIONS *********************************************************
562 ****************************************************************************/
563
564 /**
565 * Theme the general voting options.
566 *
567 * @param $instructions
568 * The instructions.
569 * @param $options
570 * A list of associate arrays containing the following elements:
571 * 'title' - the page title
572 * 'path' - the local Drupal path that the item links to
573 * 'description' - a description of the item
574 * @return
575 * The themed output as HTML.
576 */
577 function theme_versus_voting_options($instructions, $options) {
578
579 // Print the instructions.
580 $output = "<p>$instructions</p>";
581
582 // Present the options as a definition list.
583 $output .= "<dl>";
584 foreach ($options as $option) {
585 $output .= "<dt>" . l($option['title'], $option['path']) . "</dt>";
586 $output .= "<dd>" . $option['description'] . "</dd>";
587 }
588 $output .= "</dl>";
589
590 // Return the HTML.
591 return $output;
592 }
593
594 /**
595 * Theme a display of the competitions and their content types that
596 * can be voted on.
597 *
598 * @param $instructions
599 * The instructions.
600 * @param $competitions
601 * A list of associated arrays representing competitions and their
602 * content types. Each item contains the following elements:
603 * 'nid' - the node ID of the competition
604 * 'title' - the title of the competition
605 * 'types' - a list of content types accepted by the competition
606 * @return
607 * The themed output as HTML.
608 */
609 function theme_versus_voting_competitions($instructions, $competitions) {
610
611 // Set the voting path. Perhaps this should be an argument?
612 $path = "versus/vote";
613
614 // Print the instructions.
615 $output = "<p>$instructions</p>";
616
617 // Present the options as a definition list.
618 $output .= "<dl>";
619 foreach ($competitions as $competition) {
620
621 // For each competition, we need the ID, title and types it supports.
622 $nid = $competition['nid'];
623 $title = $competition['title'];
624 $types = $competition['types'];
625
626 // Display a link to each competition.
627 $output .= "<dt>" . l($title, "node/$nid") . "</dt>";
628
629 // Each definition is a list of available types.
630 $output .= "<dd><ul>";
631 foreach ($types as $type) {
632
633 // Display a link for each type so that it can be voted on.
634 $type_name = node_get_types('name', $type);
635 $output .= "<li>" . l($type_name, "$path/$type/$nid") . "</li>";
636 }
637 $output .= "</ul></dd>";
638 }
639 $output .= "</dl>";
640
641 // Return the HTML.
642 return $output;
643 }
644
645 /**
646 * Theme a general voting request.
647 *
648 * @param $types
649 * The content types that can be voted on.
650 * @return
651 * The themed output of the voting options.
652 */
653 function theme_versus_voting_types($types) {
654
655 // Get an overview of all content types that can be voted on.
656 foreach ($types as $type => $name) {
657
658 // Skip unset content types.
659 if ((!$type) || (!$name) || ($type == 1)) {
660 continue;
661 }
662
663 // Show a link for each thing that can be vored on.
664 $title = t('Vote for an existing @s.', array('@s' => $name));
665 $out = '<dt>'. l(
666 node_get_types('name', $name),
667 "versus/vote/". $type,
668 array('title' => $title)
669 ) .'</dt>';
670 $item[$type] = $out;
671 }
672
673 // Add a title & format it.
674 if (isset($item)) {
675 uksort($item, 'strnatcasecmp');
676 $output = t('Choose the type of content that you would like to vote on:') .
677 '<dl>'. implode('', $item) .'</dl>';
678 }
679 else {
680 $output = t('No content types available for voting.');
681 }
682
683 return $output;
684 }
685
686 /**
687 * Prepare the output for the voting ballot.
688 *
689 * @param $candidates
690 * The size of the candidate pool.
691 * @param $done
692 * TRUE if the user has finished voting, FALSE otherwise.
693 * @param $left
694 * The node representing the choice on the left.
695 * @param $right
696 * The node representing the choice on the right.
697 * @return
698 * The themed output of whatever's on the voting ballot.
699 */
700 function versus_voting_ballot($candidates, $done = FALSE,
701 $left = NULL, $right = NULL) {
702
703 // Check if there's nothing to vote on.
704 if (!$candidates) {
705 drupal_set_title(t('No voting for this content type'));
706 return t('There are no candidates of this type to vote on. Please select a different type of content for voting over at <a href="/versus/vote">the selection page</a>.');
707 }
708
709 // Check if we've only got one candidate. It, clearly, is the winner,
710 // so there's nothing to vote on. However, we should say what the winner
711 // is, and provide a link to it.
712 if ($candidates < 2) {
713 drupal_set_title(t('No voting for this content type'));
714 return t('There is only one candidate of this type available, so it wins by default. Take a look at it by clicking <a href="/node/@nid">here</a>.',
715 array('@nid' => $left->nid));
716 }
717
718 // Check if the user is done voting.
719 if ($done) {
720 drupal_set_title(t('Thanks for voting!'));
721 return t('You have already voting on all pairs of candidates. If you haven\'t voted for all types of content, please do so from the <a href="/versus/vote">selection page</a>.');
722 }
723
724 // Get all of the information for each voting option.
725 $left = node_load($left->nid);
726 $right = node_load($right->nid);
727
728 // Set the page title.
729 drupal_set_title(t('@left vs. @right', array(
730 '@left' => check_plain($left->title),
731 '@right' => check_plain($right->title),
732 )));
733
734 return theme('versus_voting_ballot', $left, $right);
735 }
736
737 /**
738 * Theme the voting ballot.
739 *
740 * @param $left
741 * The node representing the choice on the left.
742 * @param $right
743 * The node representing the choice on the right.
744 * @return
745 * The themed output of whatever's on the voting ballot.
746 */
747 function theme_versus_voting_ballot($left = NULL, $right = NULL) {
748
749 // Prepare the forms for each vote
750 $input_left = drupal_get_form('versus_voting_form',
751 $left->nid, $right->nid, $left->type);
752 $input_right = drupal_get_form('versus_voting_form',
753 $right->nid, $left->nid, $left->type);
754
755 // Show the teaser for each node side by side.
756 $output = '<table id="versus_box_choices" width="100%" border="0" cellspacing="0" cellpadding="0">';
757 $output .= ' <tr>';
758 $output .= ' <td>'. node_view($left, TRUE, FALSE, FALSE) .'</td>';
759 $output .= ' <td>'. node_view($right, TRUE, FALSE, FALSE) .'</td>';
760 $output .= ' </tr>';
761 $output .= ' <tr>';
762 $output .= ' <td>'. $input_left .'</td>';
763 $output .= ' <td>'. $input_right .'</td>';
764 $output .= ' </tr>';
765 $output .= '</table>';
766
767 // Return the ballot for display.
768 return $output;
769 }
770
771 /**
772 * Theme a voting button.
773 *
774 * @param $form
775 * The associated form.
776 * @return
777 * The themed button.
778 */
779 function theme_versus_vote_button($form) {
780 return '<input type="submit" class="form-submit" value="Vote" id="edit-vote-ref-1" name="op"/>';
781 }
782
783 /****************************************************************************
784 ** API FUNCTIONS ***********************************************************
785 ****************************************************************************/
786
787 /**
788 * Set the voting status.
789 *
790 * Other modules can use this function to enable or disable voting.
791 *
792 * @param $enabled
793 * TRUE to enable voting or FALSE to disable it.
794 */
795 function versus_set_voting_status($enabled) {
796 variable_set('versus_voting_enabled', $enabled);
797 }
798
799 /****************************************************************************
800 ** VIEWS FUNCTIONS *********************************************************
801 ****************************************************************************/
802
803 /**
804 * Implementation of hook_views_tables().
805 */
806 function versus_views_tables() {
807 $tables['versus'] = array(
808 'name' => 'versus',
809 'fields' => array(
810 'votes' => array(
811 'name' => t('Versus: votes'),
812 'help' => t('Number of Versus votes for the node.'),
813 'sortable' => TRUE,
814 'notafield' => TRUE,
815 'query_handler' => 'versus_query_handler_votes',
816 ),
817 ),
818 );
819 return $tables;
820 }
821
822 /**
823 * Views query handler to define the number of Versus votes.
824 */
825 function versus_query_handler_votes($field, $fieldinfo, &$query) {
826 $query->add_field('(SELECT COUNT(value) AS votes FROM votingapi_vote WHERE value = node.nid)', '', 'versus_votes');
827 }
828
829 /**
830 * Implementation of hook_views_default_views().
831 */
832 function versus_views_default_views() {
833
834 // Create an array to hold the defined views.
835 $views = array();
836
837 // Define an exported view.
838 $view = new stdClass();
839 $view->name = 'versus_standings';
840 $view->description = 'The Versus standings organized by content type (& competition if applicable)';
841 $view->access = array (
842 );
843 $view->view_args_php = '';
844 $view->page = TRUE;
845 $view->page_title = 'Standings by Content Type';
846 $view->page_header = '';
847 $view->page_header_format = '1';
848 $view->page_footer = '';
849 $view->page_footer_format = '1';
850 $view->page_empty = 'As yet, no votes have been cast for this content type.';
851 $view->page_empty_format = '1';
852 $view->page_type = 'table';
853 $view->url = 'versus/standings';
854 $view->use_pager = TRUE;
855 $view->nodes_per_page = '100';
856 $view->menu = TRUE;
857 $view->menu_title = 'View Standings';
858 $view->menu_tab = FALSE;
859 $view->menu_tab_weight = '0';
860 $view->menu_tab_default = FALSE;
861 $view->menu_tab_default_parent = NULL;
862 $view->menu_tab_default_parent_type = 'tab';
863 $view->menu_parent_tab_weight = '0';
864 $view->menu_parent_title = '';
865 $view->sort = array (
866 );
867 $view->argument = array (
868 array (
869 'type' => 'nodetype',
870 'argdefault' => '4',
871 'title' => '%1 Standings',
872 'options' => '',
873 'wildcard' => '',
874 'wildcard_substitution' => '',
875 ),
876 );
877 // This argument should only exist when the Competition module is enabled.
878 if (module_exists('competition')) {
879 $view->argument[] = array(
880 'type' => 'competition_id',
881 'argdefault' => '4',
882 'title' => '%1 Standings for %2',
883 'options' => '',
884 'wildcard' => '',
885 'wildcard_substitution' => '',
886 );
887 }
888 $view->field = array (
889 array (
890 'tablename' => 'node',
891 'field' => 'nid',
892 'label' => 'Node ID',
893 ),
894 array (
895 'tablename' => 'node',
896 'field' => 'title',
897 'label' => 'Name',
898 'handler' => 'views_handler_field_nodelink',
899 'options' => 'link',
900 ),
901 array (
902 'tablename' => 'users',
903 'field' => 'name',
904 'label' => 'Author',
905 ),
906 array (
907 'tablename' => 'versus',
908 'field' => 'votes',
909 'label' => 'Votes',
910 'sortable' => '1',
911 'defaultsort' => 'DESC',
912 ),
913 );
914 $view->filter = array (
915 array (
916 'tablename' => 'node',
917 'field' => 'status',
918 'operator' => '=',
919 'options' => '',
920 'value' => '1',
921 ),
922 );
923 $view->exposed_filter = array (
924 );
925 $view->requires = array(node, users, versus);
926 $views[$view->name] = $view;
927
928 // Return the defined views.
929 return $views;
930 }

  ViewVC Help
Powered by ViewVC 1.1.2