Skip to content
poll.module 17 KiB
Newer Older
Dries Buytaert's avatar
 
Dries Buytaert committed
/**
 * @file
 * Enables your site to capture votes on different topics in the form of multiple
 * choice questions.
 */

/**
 * Implementation of hook_help().
 */
function poll_help($section) {
Steven Wittens's avatar
Steven Wittens committed
  switch ($section) {
    case 'admin/help#poll':
      $output = '<p>'. t('The poll module can be used to create simple polls for site users.  A poll is a simple multiple choice questionnaire which displays the cumulative results of the answers to the poll.  Having polls on the site is a good way to get instant feedback from community members.') .'</p>';
      $output .= '<p>'. t('Users can create a poll. The title of the poll should be the question, then enter the answers and the "base" vote counts. You can also choose the time period over which the vote will run.The <a href="%poll">poll</a> item in the navigation menu will take you to a page where you can see all the current polls, vote on them (if you haven\'t already) and view the results.', array('%poll' => url('poll'))) .'</p>';
      $output .= t('<p>You can</p>
<ul>
<li>view the <a href="%poll">polls page</a>.</li>
<li><a href="%admin-node-configure-types-poll">administer &gt;&gt; settings &gt;&gt; content types &gt;&gt; configure poll</a>.</li>
', array('%poll' => url('poll'), '%admin-node-configure-types-poll' => url('admin/settings/content-types/poll')));
      $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="%poll">Poll page</a>.', array('%poll' => 'http://drupal.org/handbook/modules/poll/')) .'</p>';
Dries Buytaert's avatar
 
Dries Buytaert committed
    case 'admin/modules#description':
      return t("Allows your site to capture votes on different topics in the form of multiple choice questions.");
Steven Wittens's avatar
Steven Wittens committed
    case 'node/add#poll':
      return t("A poll is a multiple-choice question which visitors can vote on.");
function poll_access($op, $node) {
Steven Wittens's avatar
Steven Wittens committed
  if ($op == 'create') {
    return user_access('create polls');
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
/**
 * Implementation of hook_block().
 *
 * Generates a block containing the latest poll.
 */
Steven Wittens's avatar
Steven Wittens committed
function poll_block($op = 'list', $delta = 0) {
  if (user_access('access content')) {
    if ($op == 'list') {
      $blocks[0]['info'] = t('Most recent poll');
Dries Buytaert's avatar
 
Dries Buytaert committed
      return $blocks;
    }
      $sql = db_rewrite_sql("SELECT MAX(n.created) FROM {node} n INNER JOIN {poll} p ON p.nid = n.nid WHERE n.status = 1 AND p.active = 1 AND n.moderate = 0");
Dries Buytaert's avatar
 
Dries Buytaert committed
      $timestamp = db_result(db_query($sql));
Dries Buytaert's avatar
 
Dries Buytaert committed
      if ($timestamp) {
Steven Wittens's avatar
Steven Wittens committed
        $poll = node_load(array('type' => 'poll', 'created' => $timestamp, 'moderate' => 0, 'status' => 1));

Dries Buytaert's avatar
 
Dries Buytaert committed
        if ($poll->nid) {
          // poll_view() dumps the output into $poll->body.
Dries Buytaert's avatar
 
Dries Buytaert committed
        }
Dries Buytaert's avatar
 
Dries Buytaert committed
      }
Steven Wittens's avatar
Steven Wittens committed
      $block['subject'] = t('Poll');
      $block['content'] = $poll->body;
Dries Buytaert's avatar
 
Dries Buytaert committed
      return $block;
/**
 * Implementation of hook_cron().
 *
 * Closes polls that have exceeded their allowed runtime.
 */
function poll_cron() {
  $result = db_query('SELECT p.nid FROM {poll} p INNER JOIN {node} n ON p.nid = n.nid WHERE (n.created + p.runtime) < '. time() .' AND p.active = 1 AND p.runtime != 0');
Dries Buytaert's avatar
 
Dries Buytaert committed
  while ($poll = db_fetch_object($result)) {
    db_query("UPDATE {poll} SET active = 0 WHERE nid = %d", $poll->nid);
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
function poll_delete($node) {
  db_query("DELETE FROM {poll} WHERE nid = %d", $node->nid);
Dries Buytaert's avatar
 
Dries Buytaert committed
  db_query("DELETE FROM {poll_choices} WHERE nid = %d", $node->nid);
Dries Buytaert's avatar
Dries Buytaert committed
  db_query("DELETE FROM {poll_votes} WHERE nid = %d", $node->nid);
  // Renumber fields
  $node->choice = array_values($node->choice);
  $node->teaser = poll_teaser($node);
}
function poll_validate($node) {
  if (isset($node->title)) {
    // Check for at least two options and validate amount of votes:
Steven Wittens's avatar
Steven Wittens committed
    $realchoices = 0;
    // Renumber fields
    $node->choice = array_values($node->choice);
Steven Wittens's avatar
Steven Wittens committed
    foreach ($node->choice as $i => $choice) {
      if ($choice['chtext'] != '') {
        $realchoices++;
Steven Wittens's avatar
Steven Wittens committed
      if ($choice['chvotes'] < 0) {
Dries Buytaert's avatar
 
Dries Buytaert committed
        form_set_error("choice][$i][chvotes", t('Negative values are not allowed.'));
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
    if ($realchoices < 2) {
Dries Buytaert's avatar
 
Dries Buytaert committed
      form_set_error("choice][$realchoices][chtext", t('You must fill in at least two choices.'));
Dries Buytaert's avatar
 
Dries Buytaert committed
function poll_form(&$node) {
Steven Wittens's avatar
Steven Wittens committed
  $admin = user_access('administer nodes');
  $form['title'] = array('#type' => 'textfield', '#title' => t('Question'), '#required' => TRUE, '#default_value' => $node->title, '#weight' => -1);
  $form['choice']['choices'] = array('#type' => 'hidden', '#default_value' => max(2, count($node->choice) ? count($node->choice) : 5));
  $form['choice']['morechoices'] = array('#type' => 'checkbox', '#title' => t('Need more choices'), '#default_value' => 0, '#description' => t("If the amount of boxes above isn't enough, check this box and click the Preview button below to add some more."), '#weight' => 1);
  $form['choice'] = form_builder('poll_node_form', $form['choice']);
  if ($form['choice']['morechoices']['#value']) {
    $form['choice']['morechoices']['#value'] = 0;
    $form['choice']['choices']['#value'] *= 2;
  // if the value was changed in a previous iteration, retain it.
  $node->choices = $form['choice']['choices']['#value'];

Steven Wittens's avatar
Steven Wittens committed
  // Poll choices
  $form['choice'] += array('#type' => 'fieldset', '#title' => t('Choices'), '#prefix' => '<div class="poll-form">', '#suffix' => '</div>', '#tree' => TRUE);
  for ($a = 0; $a < $node->choices; $a++) {
    $form['choice'][$a]['chtext'] = array('#type' => 'textfield', '#title' => t('Choice %n', array('%n' => ($a + 1))), '#default_value' => $node->choice[$a]['chtext']);
    if ($admin) {
      $form['choice'][$a]['chvotes'] = array('#type' => 'textfield', '#title' => t('Votes for choice %n', array('%n' => ($a + 1))), '#default_value' => (int)$node->choice[$a]['chvotes'], '#size' => 5, '#maxlength' => 7);
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  // Poll attributes
  $_duration = array(0 => t('Unlimited')) + drupal_map_assoc(array(86400, 172800, 345600, 604800, 1209600, 2419200, 4838400, 9676800, 31536000), "format_interval");
Steven Wittens's avatar
Steven Wittens committed
  $_active = array(0 => t('Closed'), 1 => t('Active'));
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  if ($admin) {
    $form['settings'] = array('#type' => 'fieldset', '#title' => t('Settings'));
    $form['settings']['active'] = array('#type' => 'radios', '#title' => t('Poll status'), '#default_value' => isset($node->active) ? $node->active : 1, '#options' => $_active, '#description' => t('When a poll is closed, visitors can no longer vote for it.'));
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
  $form['settings']['runtime'] = array('#type' => 'select', '#title' => t('Poll duration'), '#default_value' => $node->runtime ? $node->runtime : 0, '#options' => $_duration, '#description' => t('After this period, the poll will be closed automatically.'));
Dries Buytaert's avatar
 
Dries Buytaert committed

function poll_insert($node) {
Steven Wittens's avatar
Steven Wittens committed
  if (!user_access('administer nodes')) {
    // Make sure all votes are 0 initially
Steven Wittens's avatar
Steven Wittens committed
    foreach ($node->choice as $i => $choice) {
      $node->choice[$i]['chvotes'] = 0;
    }
    $node->active = 1;
  }
  db_query("INSERT INTO {poll} (nid, runtime, active) VALUES (%d, %d, %d)", $node->nid, $node->runtime, $node->active);
Dries Buytaert's avatar
 
Dries Buytaert committed

Steven Wittens's avatar
Steven Wittens committed
  foreach ($node->choice as $choice) {
    if ($choice['chtext'] != '') {
      db_query("INSERT INTO {poll_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $choice['chtext'], $choice['chvotes'], $i++);
Dries Buytaert's avatar
 
Dries Buytaert committed
/**
 * Implementation of hook_menu().
 */
Dries Buytaert's avatar
 
Dries Buytaert committed
function poll_menu($may_cache) {
Dries Buytaert's avatar
 
Dries Buytaert committed
  $items = array();
Dries Buytaert's avatar
 
Dries Buytaert committed

  if ($may_cache) {
    $items[] = array('path' => 'node/add/poll', 'title' => t('poll'),
      'access' => user_access('create polls'));
    $items[] = array('path' => 'poll', 'title' => t('polls'),
      'callback' => 'poll_page',
      'access' => user_access('access content'),
      'type' => MENU_SUGGESTED_ITEM);

    $items[] = array('path' => 'poll/vote',
      'title' => t('vote'),
      'callback' => 'poll_vote',
      'access' => user_access('vote on polls'),
      'type' => MENU_CALLBACK);
  }
  else {
    if (arg(0) == 'node' && is_numeric(arg(1))) {
      $node = node_load(arg(1));
Dries Buytaert's avatar
 
Dries Buytaert committed

      if ($node->type == 'poll' && $node->allowvotes) {
        $items[] = array('path' => 'node/'. arg(1) .'/results',
          'title' => t('results'),
          'callback' => 'poll_results',
          'access' => user_access('access content'),
          'weight' => 3,
          'type' => MENU_LOCAL_TASK);
      }
Dries Buytaert's avatar
 
Dries Buytaert committed

Dries Buytaert's avatar
 
Dries Buytaert committed
  return $items;
}

function poll_load($node) {
  // Load the appropriate choices into the $node object
  $poll = db_fetch_object(db_query("SELECT runtime, active FROM {poll} WHERE nid = %d", $node->nid));
Dries Buytaert's avatar
 
Dries Buytaert committed

  $result = db_query("SELECT chtext, chvotes, chorder FROM {poll_choices} WHERE nid = %d ORDER BY chorder", $node->nid);
Steven Wittens's avatar
Steven Wittens committed
  while ($choice = db_fetch_array($result)) {
    $poll->choice[$choice['chorder']] = $choice;
Steven Wittens's avatar
Steven Wittens committed
  // Determine whether or not this user is allowed to vote
  $poll->allowvotes = FALSE;
  if (user_access('vote on polls') && $poll->active) {
    if ($user->uid && db_num_rows(db_query('SELECT uid FROM {poll_votes} WHERE nid = %d AND uid = %d', $node->nid, $user->uid)) == 0) {
      $poll->allowvotes = TRUE;
    }
    else if ($user->uid == 0 && db_num_rows(db_query("SELECT hostname FROM {poll_votes} WHERE nid = %d AND hostname = '%s'", $node->nid, $_SERVER['REMOTE_ADDR'])) == 0) {
      $poll->allowvotes = TRUE;
Dries Buytaert's avatar
 
Dries Buytaert committed

 * Implementation of hook_node_info().
  return array('poll' => array('name' => t("poll"), 'base' => 'poll'));
Steven Wittens's avatar
Steven Wittens committed
function poll_page() {
Steven Wittens's avatar
Steven Wittens committed
  // List all polls
  $sql = "SELECT n.nid, n.title, p.active, n.created, SUM(c.chvotes) AS votes FROM {node} n INNER JOIN {poll} p ON n.nid = p.nid INNER JOIN {poll_choices} c ON n.nid = c.nid WHERE n.status = 1 AND n.moderate = 0 GROUP BY n.nid, n.title, p.active, n.created ORDER BY n.created DESC";
Dries Buytaert's avatar
 
Dries Buytaert committed
  $result = pager_query($sql, 15);
Steven Wittens's avatar
Steven Wittens committed
  $output = '<ul>';
Steven Wittens's avatar
Steven Wittens committed
  while ($node = db_fetch_object($result)) {
Dries Buytaert's avatar
 
Dries Buytaert committed
    $output .= '<li>'. l($node->title, "node/$node->nid") .' - '. format_plural($node->votes, '1 vote', '%count votes') .' - '. ($node->active ? t('open') : t('closed')) .'</li>';
Steven Wittens's avatar
Steven Wittens committed
  }
Steven Wittens's avatar
Steven Wittens committed
  $output .= '</ul>';
  $output .= theme("pager", NULL, 15);
Dries Buytaert's avatar
 
Dries Buytaert committed
  return $output;
Steven Wittens's avatar
Steven Wittens committed
}

function poll_perm() {
Steven Wittens's avatar
Steven Wittens committed
  return array('create polls', 'vote on polls');
Dries Buytaert's avatar
 
Dries Buytaert committed

/**
 * Creates a simple teaser that lists all the choices.
 */
function poll_teaser($node) {
Dries Buytaert's avatar
Dries Buytaert committed
  if (is_array($node->choice)) {
Steven Wittens's avatar
Steven Wittens committed
    foreach ($node->choice as $k => $choice) {
      $teaser .= '* '. $choice['chtext'] .'\n';
Steven Wittens's avatar
Steven Wittens committed
/**
Steven Wittens's avatar
Steven Wittens committed
 */
Dries Buytaert's avatar
Dries Buytaert committed
function poll_view_voting(&$node, $teaser, $page, $block) {
  if ($_POST['op'] == t('Vote')) {
    poll_vote($node);
  }
Dries Buytaert's avatar
 
Dries Buytaert committed
  if ($node->choice) {
Steven Wittens's avatar
Steven Wittens committed
    $list = array();
    foreach ($node->choice as $i => $choice) {
      $list[$i] = check_plain($choice['chtext']);
    $form['choice'] = array('#type' => 'radios', '#title' => $block ? check_plain($node->title) : '', '#default_value' => -1, '#options' => $list);
Dries Buytaert's avatar
 
Dries Buytaert committed
  }
  $form['nid'] = array('#type' => 'hidden', '#value' => $node->nid);
  $form['vote'] = array('#type' => 'submit', '#value' => t('Vote'));
  $form['#action'] = url('node/'. $node->nid);
  return drupal_get_form('poll_view_voting', $form);
}
/**
 * Themes the voting form for a poll.
 */
function theme_poll_view_voting($form) {
  $output .= '<div class="poll">';
  $output .= '  <div class="vote-form">';
  $output .= '    <div class="choices">';
  $output .= form_render($form['choice']);
  $output .= '    </div>';
  $output .= form_render($form['nid']);
  $output .= form_render($form['vote']);
  $output .= '  </div>';
  $output .= form_render($form);
Steven Wittens's avatar
Steven Wittens committed
  $output .= '</div>';
  return $output;
}

/**
 * Generates a graphical representation of the results of a poll.
 */
Dries Buytaert's avatar
Dries Buytaert committed
function poll_view_results(&$node, $teaser, $page, $block) {
  // Count the votes and find the maximum
Steven Wittens's avatar
Steven Wittens committed
  foreach ($node->choice as $choice) {
    $total_votes += $choice['chvotes'];
    $max_votes = max($max_votes, $choice['chvotes']);
Steven Wittens's avatar
Steven Wittens committed
  foreach ($node->choice as $i => $choice) {
    if ($choice['chtext'] != '') {
      $poll_results .= theme('poll_bar', check_plain($choice['chtext']), round($choice['chvotes'] * 100 / max($total_votes, 1)), format_plural($choice['chvotes'], '1 vote', '%count votes'), $block);
Dries Buytaert's avatar
 
Dries Buytaert committed

  $output .= theme('poll_results', check_plain($node->title), $poll_results, $total_votes, $node->links, $block);

  return $output;
}

function theme_poll_results($title, $results, $votes, $links, $block) {
  if ($block) {
    $output .= '<div class="poll">';
    $output .= '<div class="title">'. $title .'</div>';
    $output .= $results;
    $output .= '<div class="total">'. t('Total votes: %votes', array('%votes' => $votes)) .'</div>';
    $output .= '</div>';
    $output .= '<div class="links">'. theme('links', $links) .'</div>';
  }
  else {
    $output .= '<div class="poll">';
    $output .= $results;
    $output .= '<div class="total">'. t('Total votes: %votes', array('%votes' => $votes)) .'</div>';
    $output .= '</div>';
  }

  return $output;
}

function theme_poll_bar($title, $percentage, $votes, $block) {
  if ($block) {
    $output  = '<div class="text">'. $title .'</div>';
    $output .= '<div class="bar"><div style="width: '. $percentage .'%;" class="foreground"></div></div>';
    $output .= '<div class="percent">'. $percentage .'%</div>';
  }
  else {
    $output  = '<div class="text">'. $title .'</div>';
    $output .= '<div class="bar"><div style="width: '. $percentage .'%;" class="foreground"></div></div>';
    $output .= '<div class="percent">'. $percentage .'% ('. $votes .')</div>';
  }

  return $output;
}

/**
 * Callback for the 'results' tab for polls you can vote on
 */
function poll_results() {
  if ($node = node_load(arg(1))) {
    drupal_set_title(check_plain($node->title));
Dries Buytaert's avatar
 
Dries Buytaert committed
    return node_show($node, 0);
  }
  else {
    drupal_not_found();
  }
}

/**
 * Callback for processing a vote
 */
function poll_vote(&$node) {
  if ($node = node_load($nid)) {
    $edit = $_POST['edit'];
    $choice = $edit['choice'];
    $vote = $_POST['vote'];
Steven Wittens's avatar
Steven Wittens committed

    if (isset($choice) && isset($node->choice[$choice])) {
      if ($node->allowvotes) {
        // Mark the user or host as having voted.
        if ($user->uid) {
          db_query('INSERT INTO {poll_votes} (nid, uid) VALUES (%d, %d)', $node->nid, $user->uid);
        }
        else {
          db_query("INSERT INTO {poll_votes} (nid, hostname) VALUES (%d, '%s')", $node->nid, $_SERVER['REMOTE_ADDR']);
        }

        // Add one to the votes.
Steven Wittens's avatar
Steven Wittens committed
        db_query("UPDATE {poll_choices} SET chvotes = chvotes + 1 WHERE nid = %d AND chorder = %d", $node->nid, $choice);
Steven Wittens's avatar
Steven Wittens committed
        $node->choice[$choice]['chvotes']++;
Dries Buytaert's avatar
 
Dries Buytaert committed
        drupal_set_message(t('Your vote was recorded.'));
Steven Wittens's avatar
Steven Wittens committed
      }
      else {
Dries Buytaert's avatar
 
Dries Buytaert committed
        drupal_set_message(t("You're not allowed to vote on this poll."), 'error');
Steven Wittens's avatar
Steven Wittens committed
      }
    }
    else {
Dries Buytaert's avatar
 
Dries Buytaert committed
      drupal_set_message(t("You didn't specify a valid poll choice."), 'error');
Steven Wittens's avatar
Steven Wittens committed
    }

    drupal_goto('node/'. $nid);
  }
  else {
    drupal_not_found();
/**
 * Implementation of hook_view().
 *
 * @param $block
 *   An extra parameter that adapts the hook to display a block-ready
 *   rendering of the poll.
 */
Dries Buytaert's avatar
 
Dries Buytaert committed
function poll_view(&$node, $teaser = FALSE, $page = FALSE, $block = FALSE) {
Dries Buytaert's avatar
 
Dries Buytaert committed
  global $user;
Dries Buytaert's avatar
 
Dries Buytaert committed
  $output = '';
Steven Wittens's avatar
Steven Wittens committed
  // Special display for side-block
  if ($block) {
Steven Wittens's avatar
Steven Wittens committed
    // No 'read more' link
    $node->body = $node->teaser = '';
Dries Buytaert's avatar
Dries Buytaert committed
    $links = module_invoke_all('link', 'node', $node, 1);
Steven Wittens's avatar
Steven Wittens committed
    $links[] = l(t('older polls'), 'poll', array('title' => t('View the list of polls on this site.')));
    if ($node->allowvotes && $block) {
      $links[] = l(t('results'), 'node/'. $node->nid .'/results', array('title' => t('View the current poll results.')));
    }
    $node->links = $links;
  }

  if ($node->allowvotes && ($block || arg(2) != 'results')) {
    $output .= poll_view_voting($node, $teaser, $page, $block);
  }
  else {
    $output .= poll_view_results($node, $teaser, $page, $block);
  }

  $node->body = $node->teaser = $output;
function poll_update($node) {
Steven Wittens's avatar
Steven Wittens committed
  db_query('UPDATE {poll} SET runtime = %d, active = %d WHERE nid = %d', $node->runtime, $node->active, $node->nid);
Steven Wittens's avatar
Steven Wittens committed
  db_query('DELETE FROM {poll_choices} WHERE nid = %d', $node->nid);
Dries Buytaert's avatar
Dries Buytaert committed
  db_query('DELETE FROM {poll_votes} WHERE nid = %d', $node->nid);
Steven Wittens's avatar
Steven Wittens committed
  foreach ($node->choice as $choice) {
    $chvotes = (int)$choice['chvotes'];
    $chtext = $choice['chtext'];
Steven Wittens's avatar
Steven Wittens committed
    if ($chtext != '') {
      db_query("INSERT INTO {poll_choices} (nid, chtext, chvotes, chorder) VALUES (%d, '%s', %d, %d)", $node->nid, $chtext, $chvotes, $i++);

/**
 * Implementation of hook_user().
 */
function poll_user($op, &$edit, &$user) {
  if ($op == 'delete') {
    db_query('UPDATE {poll_votes} SET uid = 0 WHERE uid = %d', $user->uid);
  }
}